Operating System Support for Inter-Application Monitoring in Android

Similar documents
Android For Java Developers. Marko Gargenta Marakana

Android Fundamentals 1

Android Security Lab WS 2014/15 Lab 1: Android Application Programming

Hacking your Droid ADITYA GUPTA

Android Basics. Xin Yang

Hello World! Some code

App Development for Smart Devices. Lec #4: Services and Broadcast Receivers Try It Out

TUTORIALS AND QUIZ ANDROID APPLICATION SANDEEP REDDY PAKKER. B. Tech in Aurora's Engineering College, 2013 A REPORT

Mobile Security - Tutorial 1. Beginning Advanced Android Development Brian Ricks Fall 2014

Mobile App Sensor Documentation (English Version)

ECWM511 MOBILE APPLICATION DEVELOPMENT Lecture 1: Introduction to Android

Mobile Application Development 2014

AndroLIFT: A Tool for Android Application Life Cycles

SDK Quick Start Guide

Android Application Development

Android Development. Marc Mc Loughlin

Mono for Android Activity Lifecycle Activity Lifecycle Concepts and Overview

Frameworks & Android. Programmeertechnieken, Tim Cocx

Android Services. Services

Life Cycle Implementation of an Android Application for Self-Communication with Increasing Efficiency, Storage Space and High Performance

INTRODUCTION TO ANDROID CSCI 4448/5448: OBJECT-ORIENTED ANALYSIS & DESIGN LECTURE 11 02/15/2011

Graduate presentation for CSCI By Janakiram Vantipalli ( Janakiram.vantipalli@colorado.edu )

How to develop your own app

Android app development course

Android Application Development - Exam Sample

An Introduction to Android Application Development. Serdar Akın, Haluk Tüfekçi

Specialized Android APP Development Program with Java (SAADPJ) Duration 2 months

Q1. What method you should override to use Android menu system?

TomTom PRO 82xx PRO.connect developer guide

Les Broadcast Receivers...

CSE476 Mobile Application Development. Yard. Doç. Dr. Tacha Serif Department of Computer Engineering Yeditepe University

How To Develop Smart Android Notifications using Google Cloud Messaging Service

Android Application Model

Basics of Android Development 1

Google s Android: An Overview

Android for Java Developers OSCON Marko Gargenta Marakana

Android Developer Fundamental 1

How To Develop Android On Your Computer Or Tablet Or Phone

Introduction to Android. CSG250 Wireless Networks Fall, 2008

App Development for Smart Devices. Lec #2: Android Tools, Building Applications, and Activities

Tutorial #1. Android Application Development Advanced Hello World App

Using Extensions or Cordova Plugins in your RhoMobile Application Darryn

ANDROID BASED MOBILE APPLICATION DEVELOPMENT and its SECURITY

Android Application Repackaging

4. The Android System

06 Team Project: Android Development Crash Course; Project Introduction

Introduction to NaviGenie SDK Client API for Android

Building an Android client. Rohit Nayak Talentica Software

APPFORUM2014. Helping the developer community build next-generation, multi-platform apps. SCHAUMBURG, ILLINOIS SEPTEMBER 8-10

Software Environments of Smartphone Applications

directory to "d:\myproject\android". Hereafter, I shall denote the android installed directory as

Lecture 17: Mobile Computing Platforms: Android. Mythili Vutukuru CS 653 Spring 2014 March 24, Monday

Android 多 核 心 嵌 入 式 多 媒 體 系 統 設 計 與 實 作

ANDROID APPS DEVELOPMENT FOR MOBILE AND TABLET DEVICE (LEVEL I)

Introduction (Apps and the Android platform)

Login with Amazon Getting Started Guide for Android. Version 2.0

Mobile Application Development

Creating and Using Databases for Android Applications

ANDROID PROGRAMMING - INTRODUCTION. Roberto Beraldi

Programming with Android: System Architecture. Dipartimento di Scienze dell Informazione Università di Bologna

Developing NFC Applications on the Android Platform. The Definitive Resource

Android Java Live and In Action

Deep Inside Android. OpenExpo Zurich September 25 th, Gilles Printemps - Senior Architect. Copyright 2007 Esmertec AG.

Copyright 2014 Jaspersoft Corporation. All rights reserved. Printed in the U.S.A. Jaspersoft, the Jaspersoft

Università Degli Studi di Parma. Distributed Systems Group. Android Development. Lecture 2 Android Platform. Marco Picone

BlackBerry Enterprise Service 10. Secure Work Space for ios and Android Version: Security Note

Administrator's Guide

Mobile applications security Android OS (case study) Maciej Olewiński. Cryptographic Seminar r.

Tutorial: Android Object API Application Development. SAP Mobile Platform 2.3

Mocean Android SDK Developer Guide

How to Prepare for the Upgrade to Microsoft Dynamics CRM 2013 (On-premises)

Android Security. Giovanni Russello

Introduction to Android Development. Daniel Rodrigues, Buuna 2014

SavvyDox Publishing Augmenting SharePoint and Office 365 Document Content Management Systems

Android Services. Android. Victor Matos

Introduction to Android Programming (CS5248 Fall 2015)

Tutorial: Android Object API Application Development. Sybase Unwired Platform 2.2 SP02

WebView addjavascriptinterface Remote Code Execution 23/09/2013

PubMatic Android SDK. Developer Guide. For Android SDK Version 4.3.5

GETTING STARTED WITH ANDROID DEVELOPMENT FOR EMBEDDED SYSTEMS

Developing Android Apps: Part 1

ECWM511 MOBILE APPLICATION DEVELOPMENT Lecture 1: Introduction to Android

Developing for MSI Android Devices

Patterns of Information Management

Arduino & Android. A How to on interfacing these two devices. Bryant Tram

ANDROID APPS DEVELOPMENT FOR MOBILE GAME

Detecting privacy leaks in Android Apps

Lecture 1 Introduction to Android

Building Your First App

Beginner s Android Development Tutorial!

AdFalcon Android SDK Developer's Guide. AdFalcon Mobile Ad Network Product of Noqoush Mobile Media Group

Creating and Managing Shared Folders

Measuring The End-to-End Value Of Your App. Neil Rhodes: Tech Lead, Mobile Analytics Nick Mihailovski: Developer Programs Engineer

Android Development Exercises Version Hands On Exercises for. Android Development. v

APPLICATION VIRTUALIZATION TECHNOLOGIES WHITEPAPER

SAMPLE CHAPTER. Unlocking. Frank Ableson Charlie Collins Robi Sen FOREWORD BY DICK WALL MANNING

zen Platform technical white paper

How To Build A Connector On A Website (For A Nonprogrammer)

A model driven approach for Android applications development

White Paper. Anywhere, Any Device File Access with IT in Control. Enterprise File Serving 2.0

Transcription:

Operating System Support for Inter-Application Monitoring in Android Daniel M. Jackowitz Spring 2013 Submitted in partial fulfillment of the requirements of the Master of Science in Software Engineering

Abstract In the stock Android mobile operating system there exists no mechanism by which an application is able to observe state changes within other applications. While for most typical applications this functionality is not necessary, there are particular instances in which it proves incredibly useful. One such scenario presented in this paper is an app to monitor the behavioral patterns of users through their device interactions. The addition of this feature also opens up many new possibilities for more adaptive applications that respond to how the device is being used. This thesis presents a mechanism by which apps can register to be notified of lifecycle transitions within other applications, extends the Android Open Source Project to include this mechanism, and ensures that the security of the device is not compromised and that performance is impacted as little as possible. i

Table of Contents Abstract. i 1 Introduction 1 1.1 Motivation. 1 1.2 System Goals 1 1.3 Extending the Potential Uses.. 2 1.4 Related Work.. 3 2 Android Application Structure.. 3 3 What to Intercept 6 4 The Communication Protocol 7 4.1 General Mechanism. 7 4.2 Broadcast Actions. 8 4.3 Intent Extras. 9 5 Permissions.. 10 6 Fragments. 11 7 Implementation. 15 8 Using the System: Developer Samples 21 9 Limitations. 25 9.1 Falsified Broadcasts 25 9.2 Android Support Library.. 25 10 Conclusion 27 Appendix A: Building Android from Source 28 Glossary. 30 References.. 31 ii

1 Introduction 1.1 Motivation The original idea for this project was born out of a very specialized goal to be able to record data about application usage on smart devices and send that data to a remote server where a pattern analysis could be performed and abnormalities in user behavior detected. The intent was to implement this mechanism in the form of an ios application and distribute it for the Apple family of mobile devices. It quickly became apparent, however, that this monitoring of other applications would not be possible under the strict ios security model. As a result, Google s Android mobile operating system emerged as the new target platform. Like ios, however, Android provides a security model to protect users from malicious applications intruding on other apps. This protection therefore also eliminates the possibility of a simple monitoring app on the Android platform as well. Fortunately, the open nature of the Android operating system lends itself to an alternative approach. Whereas much of the internals of ios are proprietary to Apple and hidden from developers, the entirety 1 of the Android OS has been open-sourced in the form of the Android Open Source Project (AOSP) [1]. All code in the AOSP repository, which completely encompasses core Android functionality, is freely accessible and modifiable by anyone who is interested. Therefore, the goal of the project migrated away from creating a monitoring app running on a mobile operating system to instead creating a custom, monitoring-enabled version of the Android OS itself. 1.2 System Goals With the need for modification to the operating system itself identified, a high-level list of the necessary features of the system was outlined. These initial requirements involved augmenting the Android operating system to: Intercept application events 1 With the exception of some low-level hardware drivers for specific devices. 1

Log each event to a repository on the device Periodically upload the contents of the repository to a web service and then reset the repository on success While this solution will work to accomplish the task at hand, it is a suboptimal design. The major issue is that some of the responsibilities being moved into the operating system would be more appropriately handled by an application. Android provides apps with easy ways to both write to local storage [2] and make HTTP requests [3], so these existing solutions should be leveraged whenever possible. The only feature of the system truly beyond the capabilities of a standard app is the actual interception of events. Therefore, the requirements are revised to include: An operating system modification to intercept application events An application to log, process and upload the events A communication protocol between the operating system and the application This updated solution is much more elegant as it maintains a clear separation between the tasks of the operating system and the tasks of the application. 1.3 Extending the Potential Uses With the processing logic moved out of the operating system and communication being performed over a defined protocol, it becomes possible to extend the system to cover a much larger set of potential uses. In order to accomplish the original goal of behavioral monitoring through device interaction, the monitoring application is particularly interested in other applications launch and close events. The app must also receive timing data regarding both when and for how long the application was used. Any additional details, such as what URL is opened by the browser app, should also be made available to the monitor if possible. Considering this core set of data, the What?, When? and How? of user interaction, it is not difficult to imagine other scenarios beyond behavioral monitoring where it may also prove useful. One 2

simple such case would be providing the ability to define macros of applications. For example, a mobile device user notices that he or she consistently checks for new e-mail immediately upon waking in the morning. Utilizing the proposed system, it would be possible for a software developer to create an application that allows a user to define a macro describing the relationships between the executions of other applications in this example, the e-mail app immediately following the alarm clock app. This macro app then listens for the alarm clock application close event and reacts by automatically launching the e-mail app. The next logical extension of this idea takes the automation even further based on patterns in past events, the app learns what the proper macros should be. 1.4 Related Work LogCat is the Android logging system mechanism for collecting and viewing system debug output [4]. It is most often used as a debugging tool during application development but frequently logging statements are left in deployed applications either by accident or for the purpose of error reporting. In addition to providing command line tools, LogCat can also be executed from within an Android application allowing for programmatic parsing of the logs. Although Android 4.1 added the restriction that applications are now able to read only the log entries which they themselves have written, in prior versions of the operating system it is possible for developers to glean some information about other applications by analyzing the LogCat logs. Parsing the logs relies heavily on heuristics and guesswork, however, as not all applications log the same information or even any information at all. As a result, monitoring applications developed in this fashion typically behave quite inconsistently. 3

2 Android Application Structure In order to determine how to best capture Android application events, the structure of the applications must first be understood. The major component of an Android app is the activity. An activity is a single, focused thing that the user can do and, typically, corresponds to a single screen in the user interface [4]. Only a single activity can be active at any given time and there is always an active activity when the device is in use. This activity is defined as being in the running or foreground state. Activities communicate with each other via intents. An intent is an abstract description of an operation to be performed as well as a container for data related to that operation [5]. An intent falls into one of two categories explicit or implicit. An explicit intent specifies the exact target of the intent by means of its class and package names. Explicit intents are typically used to transition between activities within a single application. An implicit intent does not specify a target, but rather provides a set of criteria, in the form of actions and categories, used by the system to find an appropriate target. Implicit intents are often used to start an activity which is part of a separate application. For example, when the user clicks on a phone number within the Browser app, it will launch an implicit intent requesting the system to start an activity which has registered itself as being capable of handling a phone number. In this case, the action will be android.intent.action.call and the phone number will be passed as a key-value pair in an intent extra. There are many other nuances related to the use of intents, but the above can be considered as the representative cases. At any point in time, an Android activity is in one of four states. As mentioned earlier, the current activity the user is interacting with is in the running state. An activity becomes paused when it has lost focus, but is still visible. The standard example of a paused activity is one with a dialog box partially covering it. A stopped activity is completely obscured by another activity. When an activity issues an intent to start another activity, it becomes briefly paused, and then stopped, after the newly started activity enters the running state. In both the paused and stopped states the activity is kept in 4

memory unless the space is truly needed elsewhere. If the memory used by an activity must be reclaimed, the activity will then enter the destroyed state. An activity can also request for itself to be destroyed when it is no longer needed. Although the states of activities are managed by the operating system, activities are informed of transitions through a series of lifecycle callbacks. There are 6 main lifecycle callbacks, each representing a transition between a pair of the above states as described in Figure 1. Figure 1: The activity lifecycle callbacks. All Android activities must extend the Activity class, which provides the basic implementations necessary for interacting with the Android framework classes. Developers then add functionality to their activities by overriding Activity methods to include additional implementations. It is very important to note that for many of the activity methods, and particularly for all of the lifecycle callbacks, it is required that all overriding implementations first call through to the superclass implementation to ensure that all framework interaction is handled properly. This requirement is essential to the system as it provides a well-defined set of guaranteed checkpoints at which activities can be examined. Since all activity implementations must call through to the superclass, by altering the callback methods in the Activity class itself it becomes possible to intercept the callbacks for the activities of all applications without requiring any cooperation, or even awareness, on the part of the developers of said applications. 5

3 What to Intercept After identifying where this interception of activity transitions should occur, the focus is shifted to defining exactly what data should be extracted from the activities. The goal throughout this process is to provide enough data to completely represent the most basic components of the state of the activity at the time of the callback. Firstly, the set of interest for lifecycle callbacks is identified as the six callbacks in Figure 1 - oncreate(), onstart(), onresume(), onpause(), onstop() and ondestroy(). Next, extracting appropriate data fields begins with the obvious the method of identifying the activity itself. In Android, activities are identified by a component name. Encapsulated in a ComponentName object, it is the combination of the package name of the application and the fully qualified name of the Java class of the activity [6]. Android guarantees that application package names are unique and Java guarantees that class names are unique within a package, so the component name serves this purpose perfectly. The component name of an activity is returned by getcomponentname(). The system must also provide a means of identifying which of the lifecycle callbacks was invoked, and when. How the former will be conveyed depends largely on the communication protocol chosen, while the latter is accomplished with a simple timestamp via getsystemtimemillis(). The final field is the current intent for the activity. More specifically, this is the result of calling getintent() on the activity at the time the callback is invoked. When an activity is started, this field is initialized to the intent used to start it, but it can be altered by the activity during its lifetime by calling setintent(). In general, this intent will contain any extra information passed to the activity for processing. For example, an intent used to start a browser activity may contain the URL of a page to load. 6

4 The Communication Protocol 4.1 General Mechanism Next, a communication protocol is defined to marshal the intercepted activity data back to the monitor applications. The initial approach designated a particular file within the application space as a repository. The interception component would then write to this file and the applications would read from it. The approach has some serious drawbacks, however, as it requires guarding against two processes accessing, and potentially modifying, the file concurrently. It is also overly restrictive in the fact that the path of the file is statically restricted to within a single application s space. Supporting multiple monitor apps would then require either writing to multiple files or, despite security recommendations, making the repository file accessible to all apps. Additionally, the responsibility of managing these files is not clearly defined. This can result in either excessive accumulation or premature deletion of the event data. A much better technique makes use of a broadcast-receive protocol, where an app can register itself as desiring to be notified when a lifecycle callback occurs. Then, when an event is intercepted, instead of writing to a file or some other repository the system sends a broadcast containing the data it has gathered to each of the registered receivers. The important advantage here is that each of the receivers can process this data independently and in whatever way it deems appropriate. In the example applications described earlier the behavioral monitor can log all events while the macro app will only listen for particular events and then respond to them immediately. Fortunately, the Android framework provides such a broadcast mechanism in the form of the BroadcastReceiver [7]. When a broadcast receiver is registered, either statically within an application manifest or dynamically by a running application, it is associated with one or more actions, encapsulated in an implicit intent as described earlier. When an activity (or other component) wants to send a broadcast, it creates an intent with the desired action and then calls 7

sendbroadcast(intent intent) with that intent as the argument. The operating system then handles delivering the intent to all broadcast receivers registered for that particular action. 4.2 Broadcast Actions When defining the protocol, the categorization of actions is an important consideration. At one extreme is a single action for all lifecycle callback broadcasts, providing an all-or-nothing approach. The simplicity of this design in both implementation and use is balanced by the inability of apps to register for only a subset of lifecycle callback broadcasts. This can potentially waste resources both in sending excessive broadcasts and in performing filtering in the receiving app. The other extreme assigns each lifecycle callback a unique action, allowing apps to be very selective about what broadcasts they want to receive at the expense of some complexity in development. After some analysis, a compromise between the above approaches was achieved by identifying a subset of the lifecycle callbacks as foreground lifecycle callbacks. The callbacks in this group are those which are invoked when the activity transitions either into or out of the running state specifically, onresume() and onpause(). As it is anticipated that members of this set will be the only callbacks many applications using the system are interested in, it is reasonable to separate them logically. This distinction of foreground callbacks allows for partitioning of the lifecycle callbacks into two classes. Each class is then assigned its own broadcast action, shown in Table 1. Note that the sets of lifecycle callbacks in the two classes are mutually exclusive. One important consequence of this arrangement is that in order to receive the complete set of lifecycle callbacks an application must register to receive broadcasts for both actions. Lifecycle Callback oncreate() onstart() onstop() ondestroy() Broadcast Action (Activity Class Constant) android.activity.action.lifecycle_callback (ACTION_LIFECYCLE_CALLBACK) 8

onresume() onpause() android.activity.action.foreground_lifecycle_callback (ACTION_FOREGROUND_LIFECYCLE_CALLBACK) Table 1: The activity lifecycle callbacks and their corresponding broadcast actions. 4.3 Intent Extras In the Android broadcast-receive mechanism, data payload is passed from broadcaster to receiver by means of intent extras attached to the broadcast intent. As described earlier, an intent extra is a key-value pair where the key is a Java String and the value is a Java object that must be either Parcelable or Serializable. With the payload data already identified, the task here becomes mapping the data to appropriate keys. This mapping is shown in Table 2. Value Activity Name Timestamp Callback Current Intent Key (Activity Class Constant) android.activity.extra.component_name (EXTRA_COMPONENT_NAME) android.activity.extra.timestamp (EXTRA_TIMESTAMP) android.activity.extra.callback (EXTRA_CALLBACK) android.activity.extra.intent (EXTRA_INTENT) Type Parcelable (ComponentName) long int Parcelable (Intent) Table 2: Intent extras for the ACTION_LIFECYCLE_CALLBACK and ACTION_FOREGROUND_LIFECYCLE_CALLBACK activity lifecycle callback broadcast actions. Of particular interest is the data type of the Callback value. For consistency and ease of use, integer constants were defined within the Activity class to correspond to each of the lifecycle callbacks. These values are shown in Table 3. Developers are recommended to always use the constant rather than the Constant Value ON_CREATE 0 ON_START 1 ON_RESUME 2 ON_PAUSE 3 ON_STOP 4 ON_DESTROY 5 Table 3: Activity lifecycle callback constants. integer value itself. 9

5 Permissions The Android security model is a complex structure stretching across all layers of the system. For the purposes of this project, however, it is sufficient to consider enforcement only at the permission level. Permissions in Android are a way to ensure that protected features of the device are not accessed without the user s consent [8]. Examples of protected features include both hardware components, such as turning on the Bluetooth radio, and software components, such as reading the user s list of contacts. Most simply, a protected feature is any feature that can be easily exploited in a malicious way. From this definition, it is clear that intercepting events from another application qualifies as a protected feature and therefore must be accessible only with permission. The remaining question is the appropriate coarseness of the access control. With broadcasts being sent for two separate actions, the options regarding permissions are effectively narrowed down to either a separate permission for each action, or a single permission encompassing both actions. Considering the fact that the permission model is intended largely as a benefit to the end user, a distinct permission for each broadcast action is chosen in order to make it more explicit to the user to what extent the requesting app is able to monitor other applications. The two permissions, along with the broadcast actions they protect, are shown in Table 4. Permission Broadcast Action android.permission.monitor_lifecycle LIFECYCLE_CALLBACK android.permission.monitor_foreground_lifecycle FOREGROUND_LIFECYCLE_CALLBACK Table 4: Permissions and the activity lifecycle callback broadcast actions they protect. 10

6 Fragments Until now, all design considerations have been working under the simplifying assumption that all foreground components with which users interact are activities. In early versions of Android this assumption held true but with Android 3.0 came the concept of fragments. In the context of this project it is easiest to think of a fragment as a sub-activity. Like an activity, each fragment represents something that the user can do. A fragment also has its own lifecycle events. The key difference is that a fragment is a lightweight component - it must always be embedded within an activity [9]. Fragments can be combined in ways that allow for complex multi-pane layouts across devices of vastly different screen dimensions and can be reused across activities. Consider the typical use of fragments illustrated in Figure 2. Figure 2: Fragments displayed serially on a phone and side-by-side on a tablet. Fragments are also dynamic. They can be added to and removed from an activity while the activity is running. For this reason, in order to get a true picture of the state of the application the system must monitor not only activity lifecycle callbacks but also fragment lifecycle callbacks. From the perspective of developers, implementing a fragment very closely parallels implementing an activity. All fragment implementations extend the Fragment class. Functionality is added by overriding methods of this class, including the lifecycle callbacks. As with activities, when overriding these methods 11

fragments must call through to the superclass implementations to ensure proper interaction with the framework. Although fragments have some additional lifecycle callbacks not present for activities, these callbacks either overlap with those of the parent activity, such as onactivitycreated(), or are directly related to another fragment callback, such as onattach() immediately preceding oncreate(). Therefore the domain is restricted to only those callbacks present for both activity and fragment components. Following the model used for activities, broadcast actions are assigned to the fragment lifecycle callbacks as shown in Table 5. Lifecycle Callback oncreate() onstart() onstop() ondestroy() onresume() onpause() Broadcast Action (Fragment Class Constant) android.fragment.action.lifecycle_callback (ACTION_LIFECYCLE_CALLBACK) android.fragment.action.foreground_lifecycle_callback (ACTION_FOREGROUND_LIFECYCLE_CALLBACK) Table 5: The fragment lifecycle callbacks and their corresponding broadcast actions. Overall, the intent extras containing the data payload for fragments are also very similar to those used for the activity lifecycle callback broadcast actions, with two key differences. Since fragments can be reused across activities, the intent includes an additional field to identify the current parent activity of the fragment at the time of the callback. It is also possible to remove the extra relating to the current intent as this is a concept specific to activities. The intent extras for the fragment lifecycle callback actions are outlined in Table 6. Value Fragment Name Parent Activity Name Key (Fragment Class Constant) android.fragment.extra.component_name (EXTRA_COMPONENT_NAME) android.fragment.extra.parent_component_name (EXTRA_PARENT_COMPONENT_NAME) Type Parcelable (ComponentName) Parcelable (ComponentName) 12

Timestamp Callback android.fragment.extra.timestamp (EXTRA_TIMESTAMP) android.fragment.extra.callback (EXTRA_CALLBACK) long int Table 6: Intent extras for the ACTION_LIFECYCLE_CALLBACK and ACTION_LIFECYCLE_CALLBACK fragment lifecycle callback broadcast actions. As was the case with for the activity broadcast actions, the possible values for the Callback intent extra were enumerated in the form of integer constants in the Fragment class. These constants are listed in Table 7. Rather than defining a new set of permissions, the Constant Value ON_CREATE 0 ON_START 1 ON_RESUME 2 ON_PAUSE 3 ON_STOP 4 ON_DESTROY 5 Table 7: Fragment lifecycle callback constants. permissions defined earlier to protect the activity broadcasts are reused for protecting the fragment lifecycle callback broadcasts. This is possible because to the end user there is no practical difference between activities and fragments. In fact, introducing a separate set of permissions would likely cause additional confusion for a user. For this reason, the wording shown to the end user regarding permissions sacrifices accuracy for understandability by describing everything in terms of applications rather than activities or fragments. Although it would have been possible to group the fragment lifecycle callback broadcasts with those of activity, this was not done for two reasons. Firstly, using distinct broadcast actions for activities and fragments allows applications to selectively register to receive only activity callbacks, only fragment callbacks, or both. This proves quite valuable in reducing the number of unnecessary broadcasts sent as well as the amount of filtering that must be done on the receiving end if the application is only interested in a subset of these events. Secondly, by keeping the two separate the system is more easily adaptable to future changes. Consider the case where a new, interesting lifecycle callback is added to activities but not to fragments. With this implementation it is simple to make the necessary changes to one component without 13

impacting the other. Combined, the above advantages were determined to be worth the trade-off of a small amount of code duplication. 14

7 Implementation With the design outlined clearly above, the implementation is fairly straightforward. First, the framework manifest file is edited to include the definition of the new permissions. frameworks/base/core/res/androidmanifest.xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" coreapp="true" android:shareduserid="android.uid.system" android:shareduserlabel="@string/android_system_label"> <permission android:name="android.permission.monitor_foreground_lifecycle" android:permissiongroup="android.permission-group.system_tools" android:protectionlevel="dangerous" android:label="@string/permlab_monitorforegroundlifecycle" android:description="@string/permdesc_monitorforegroundlifecycle" /> <permission android:name="android.permission.monitor_lifecycle" android:permissiongroup="android.permission-group.system_tools" android:protectionlevel="dangerous" android:label="@string/permlab_monitorlifecycle" android:description="@string/permdesc_monitorlifecycle" /> </manifest> Here two new permissions are added to the SYSTEM_TOOLS permission group. Although an additional permission group could have been defined specifically for this purpose, a review of the existing members of SYSTEM_TOOLS revealed it to be an appropriate category for the monitoring permissions. For example, SYSTEM_TOOLS also contains the GET_TASKS permission, which allows an app to retrieve the list of currently running applications. The protection level for both new permissions is declared as dangerous, which means that the user will always be asked to explicitly consent whenever an app requesting the permission is installed. The label and description attributes define exactly what will be displayed to the user at this time and are encapsulated in string resources. Adding these resources is the next step. frameworks/base/core/res/res/strings.xml <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="permlab_monitorforegroundlifecycle">monitor foreground applications</string> <string name="permdesc_monitorforegroundlifecycle">allows the app to receive broadcasts when Activities in other applications enter or leave the foreground.</string> <string name="permlab_monitorlifecycle">monitor application lifecycle events</string> 15

<string name="permdesc_monitorlifecycle">allows the app to receive broadcasts when Activities in other applications make Activity lifecycle transitions.</string> </resources> The remaining modifications are made within the Activity and Fragment Java classes. These additions can be divided into two categories constant definitions and broadcasts. Constant definitions occur at the beginning of the class definition and encompass the broadcast actions and intent extras described by the design. The broadcast components are a little more complex. Within each relevant lifecycle callback method code is added to create an intent with the proper broadcast action, collect the necessary data from the activity and package it within the intent extras, and request that the system send a broadcast with the intent using the appropriate permission. frameworks/base/core/java/android/app/activity.java public class Activity { private static final String MONITOR_FOREGROUND_LIFECYCLE_PERM = android.manifest.permission.monitor_foreground_lifecycle; private static final String MONITOR_LIFECYCLE_PERM = android.manifest.permission.monitor_lifecycle; public static final String ACTION_FOREGROUND_LIFECYCLE_CALLBACK = "android.activity.action.foreground_lifecycle_callback"; public static final String ACTION_LIFECYCLE_CALLBACK = "android.activity.action.lifecycle_callback"; public static final String EXTRA_COMPONENT_NAME = "android.activity.extra.component_name"; public static final String EXTRA_TIMESTAMP = "android.activity.extra.timestamp"; public static final String EXTRA_CALLBACK = "android.activity.extra.callback"; public static final int ON_CREATE = 0; public static final int ON_START = 1; public static final int ON_RESUME = 2; public static final int ON_PAUSE = 3; public static final int ON_STOP = 4; public static final int ON_DESTROY = 5; public static final String EXTRA_INTENT = "android.activity.extra.intent"; protected void oncreate(bundle savedinstancestate) { if (DEBUG_LIFECYCLE) Slog.v(TAG, "oncreate " + this + ": " + savedinstancestate); if (mlastnonconfigurationinstances!= null) { mallloadermanagers = mlastnonconfigurationinstances.loaders; if (mactivityinfo.parentactivityname!= null) { if (mactionbar == null) { 16

menabledefaultactionbarup = true; else { mactionbar.setdefaultdisplayhomeasupenabled(true); if (savedinstancestate!= null) { Parcelable p = savedinstancestate.getparcelable(fragments_tag); mfragments.restoreallstate(p, mlastnonconfigurationinstances!= null? mlastnonconfigurationinstances.fragments : null); Intent broadcast = new Intent(ACTION_LIFECYCLE_CALLBACK); broadcast.putextra(extra_component_name, getcomponentname()); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_CREATE); broadcast.putextra(extra_intent, getintent()); sendbroadcast(broadcast, MONITOR_LIFECYCLE_PERM); mfragments.dispatchcreate(); getapplication().dispatchactivitycreated(this, savedinstancestate); mcalled = true; protected void onstart() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onstart " + this); mcalled = true; if (!mloadersstarted) { mloadersstarted = true; if (mloadermanager!= null) { mloadermanager.dostart(); else if (!mcheckedforloadermanager) { mloadermanager = getloadermanager(-1, mloadersstarted, false); mcheckedforloadermanager = true; Intent broadcast = new Intent(ACTION_LIFECYCLE_CALLBACK); broadcast.putextra(extra_component_name, getcomponentname()); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_START); broadcast.putextra(extra_intent, getintent()); sendbroadcast(broadcast, MONITOR_LIFECYCLE_PERM); getapplication().dispatchactivitystarted(this); protected void onresume() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onresume " + this); Intent broadcast = new Intent(ACTION_FOREGROUND_LIFECYCLE_CALLBACK); broadcast.putextra(extra_component_name, getcomponentname()); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_RESUME); broadcast.putextra(extra_intent, getintent()); sendbroadcast(broadcast, MONITOR_FOREGROUND_LIFECYCLE_PERM); getapplication().dispatchactivityresumed(this); mcalled = true; protected void onpause() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onpause " + this); Intent broadcast = new Intent(ACTION_FOREGROUND_LIFECYCLE_CALLBACK); broadcast.putextra(extra_component_name, getcomponentname()); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_PAUSE); broadcast.putextra(extra_intent, getintent()); sendbroadcast(broadcast, MONITOR_FOREGROUND_LIFECYCLE_PERM); getapplication().dispatchactivitypaused(this); 17

mcalled = true; protected void onstop() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onstop " + this); if (mactionbar!= null) mactionbar.setshowhideanimationenabled(false); Intent broadcast = new Intent(ACTION_LIFECYCLE_CALLBACK); broadcast.putextra(extra_component_name, getcomponentname()); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_STOP); broadcast.putextra(extra_intent, getintent()); sendbroadcast(broadcast, MONITOR_LIFECYCLE_PERM); getapplication().dispatchactivitystopped(this); mcalled = true; protected void ondestroy() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "ondestroy " + this); mcalled = true; // dismiss any dialogs we are managing. if (mmanageddialogs!= null) { final int numdialogs = mmanageddialogs.size(); for (int i = 0; i < numdialogs; i++) { final ManagedDialog md = mmanageddialogs.valueat(i); if (md.mdialog.isshowing()) { md.mdialog.dismiss(); mmanageddialogs = null; // close any cursors we are managing. synchronized (mmanagedcursors) { int numcursors = mmanagedcursors.size(); for (int i = 0; i < numcursors; i++) { ManagedCursor c = mmanagedcursors.get(i); if (c!= null) { c.mcursor.close(); mmanagedcursors.clear(); // Close any open search dialog if (msearchmanager!= null) { msearchmanager.stopsearch(); Intent broadcast = new Intent(ACTION_LIFECYCLE_CALLBACK); broadcast.putextra(extra_component_name, getcomponentname()); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_DESTROY); broadcast.putextra(extra_intent, getintent()); sendbroadcast(broadcast, MONITOR_LIFECYCLE_PERM); getapplication().dispatchactivitydestroyed(this); frameworks/base/core/java/android/app/fragment.java public class Fragment { private static final String MONITOR_FOREGROUND_LIFECYCLE_PERM = android.manifest.permission.monitor_foreground_lifecycle; 18

private static final String MONITOR_LIFECYCLE_PERM = android.manifest.permission.monitor_lifecycle; public static final String ACTION_FOREGROUND_LIFECYCLE_CALLBACK = "android.fragment.action.foreground_lifecycle_callback"; public static final String ACTION_LIFECYCLE_CALLBACK = "android.fragment.action.lifecycle_callback"; public static final String EXTRA_COMPONENT_NAME = "android.fragment.extra.component_name"; public static final String EXTRA_PARENT_COMPONENT_NAME = "android.fragment.extra.parent_component_name"; public static final String EXTRA_TIMESTAMP = "android.fragment.extra.timestamp"; public static final String EXTRA_CALLBACK = "android.fragment.extra.callback"; public static final int ON_CREATE = 0; public static final int ON_START = 1; public static final int ON_RESUME = 2; public static final int ON_PAUSE = 3; public static final int ON_STOP = 4; public static final int ON_DESTROY = 5; public void oncreate(bundle savedinstancestate) { Intent broadcast = new Intent(ACTION_LIFECYCLE_CALLBACK); ComponentName parentcomponentname = getactivity().getcomponentname(); ComponentName componentname = new ComponentName( parentcomponentname.getpackagename(), getclass().getname()); broadcast.putextra(extra_component_name, componentname); broadcast.putextra(extra_parent_component_name, parentcomponentname); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_CREATE); getactivity().sendbroadcast(broadcast, MONITOR_LIFECYCLE_PERM); mcalled = true; public void onstart() { mcalled = true; if (!mloadersstarted) { mloadersstarted = true; if (!mcheckedforloadermanager) { mcheckedforloadermanager = true; mloadermanager = mactivity.getloadermanager(mindex, mloadersstarted, false); if (mloadermanager!= null) { mloadermanager.dostart(); Intent broadcast = new Intent(ACTION_LIFECYCLE_CALLBACK); ComponentName parentcomponentname = getactivity().getcomponentname(); ComponentName componentname = new ComponentName( parentcomponentname.getpackagename(), getclass().getname()); broadcast.putextra(extra_component_name, componentname); broadcast.putextra(extra_parent_component_name, parentcomponentname); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_START); getactivity().sendbroadcast(broadcast, MONITOR_LIFECYCLE_PERM); public void onresume() { 19

Intent broadcast = new Intent(ACTION_FOREGROUND_LIFECYCLE_CALLBACK); ComponentName parentcomponentname = getactivity().getcomponentname(); ComponentName componentname = new ComponentName( parentcomponentname.getpackagename(), getclass().getname()); broadcast.putextra(extra_component_name, componentname); broadcast.putextra(extra_parent_component_name, parentcomponentname); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_RESUME); getactivity().sendbroadcast(broadcast, MONITOR_FOREGROUND_LIFECYCLE_PERM); mcalled = true; public void onpause() { Intent broadcast = new Intent(ACTION_FOREGROUND_LIFECYCLE_CALLBACK); ComponentName parentcomponentname = getactivity().getcomponentname(); ComponentName componentname = new ComponentName( parentcomponentname.getpackagename(), getclass().getname()); broadcast.putextra(extra_component_name, componentname); broadcast.putextra(extra_parent_component_name, parentcomponentname); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_PAUSE); getactivity().sendbroadcast(broadcast, MONITOR_FOREGROUND_LIFECYCLE_PERM); mcalled = true; public void onstop() { Intent broadcast = new Intent(ACTION_LIFECYCLE_CALLBACK); ComponentName parentcomponentname = getactivity().getcomponentname(); ComponentName componentname = new ComponentName( parentcomponentname.getpackagename(), getclass().getname()); broadcast.putextra(extra_component_name, componentname); broadcast.putextra(extra_parent_component_name, parentcomponentname); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_STOP); getactivity().sendbroadcast(broadcast, MONITOR_LIFECYCLE_PERM); mcalled = true; public void ondestroy() { mcalled = true; //Log.v("foo", "ondestroy: mcheckedforloadermanager=" + mcheckedforloadermanager // + " mloadermanager=" + mloadermanager); if (!mcheckedforloadermanager) { mcheckedforloadermanager = true; mloadermanager = mactivity.getloadermanager(mindex, mloadersstarted, false); if (mloadermanager!= null) { mloadermanager.dodestroy(); Intent broadcast = new Intent(ACTION_LIFECYCLE_CALLBACK); ComponentName parentcomponentname = getactivity().getcomponentname(); ComponentName componentname = new ComponentName( parentcomponentname.getpackagename(), getclass().getname()); broadcast.putextra(extra_component_name, componentname); broadcast.putextra(extra_parent_component_name, parentcomponentname); broadcast.putextra(extra_timestamp, System.currentTimeMillis()); broadcast.putextra(extra_callback, ON_DESTROY); getactivity().sendbroadcast(broadcast, MONITOR_LIFECYCLE_PERM); 20

8 Using the System: Developer Samples The following examples provide annotated sample code for interacting with the monitoring system. The first example shows how to simply log all activity foreground transition events to a file. After installing the custom platform version of the Android SDK 2, create a new project and choose the AOSP build as the minimum SDK version. Open AndroidManifest.xml and ensure that the android:minsdkversion attribute is set to AOSP. Next declare the application as using the android.permission.monitor_foreground_lifecycle permission. Finally, add a receiver for the android.activity.action.forground_lifecycle_callback action. AndroidManifest.xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jackowitzd2.monitor.usagelogger" android:versioncode="1" android:versionname="1.0" > <uses-sdk android:minsdkversion="aosp" android:targetsdkversion="15" /> <uses-permission android:name="android.permission.monitor_foreground_lifecycle" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/apptheme" > <activity android:name=".mainactivity" android:label="@string/main_activity_title" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <receiver android:name=".lifecyclereceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name="android.activity.action.foreground_lifecycle_callback" /> </intent-filter> </receiver> </application> </manifest> Next the implementation of the broadcast receiver defined in AndroidManifest.xml is filled in. This is accomplished by overriding the onreceive() method to handle the intent broadcast 2 Simply copy the platform/android-x.x.x directory to android-sdk/platforms in the SDK installation. 21

by the system. For this example onreceive() simply extracts the intent extras for the timestamp, the component name, and the callback type and formats them in a comma-delimited string. It then appends this string to a file in the application space. LifecycleReceiver.java import java.io.ioexception; import java.io.outputstreamwriter; import android.app.activity; import android.content.broadcastreceiver; import android.content.componentname; import android.content.context; import android.content.intent; public class LifecycleReceiver extends BroadcastReceiver { private static final String TAG = "LifecycleReceiver"; private static final String UNKNOWN = "Unknown"; private static final String OPENED = "Opened"; private static final String CLOSED = "Closed"; @Override public void onreceive(context context, Intent intent) { long timestamp = intent.getlongextra(activity.extra_timestamp, -1); String classname = ((ComponentName) intent.getparcelableextra(activity.extra_component_name)).getclassname(); int callback = intent.getintextra(activity.extra_callback, -1); String state = UNKNOWN; switch (callback) { case Activity.ON_PAUSE: state = CLOSED; break; case Activity.ON_RESUME: state = OPENED; break; String csv = timestamp + "," + classname + "," + state + "\n"; OutputStreamWriter out = null; try { out = new OutputStreamWriter(context.openFileOutput( "lifecycle.log", Context.MODE_APPEND)); out.write(csv); out.flush(); catch (Exception e) { e.printstacktrace(); finally { try { out.close(); catch (IOException e) { e.printstacktrace(); Running the above application on a device for a short period of time will produce a log file similar to the following: 22

1363879283106,com.android.launcher2.Launcher,Opened 1363879295661,com.android.launcher2.Launcher,Closed 1363879295672,com.android.email.activity.EmailActivity,Opened 1363879305036,com.android.email.activity.EmailActivity,Closed 1363879305055,com.android.launcher2.Launcher,Opened 1363879305062,com.android.launcher2.Launcher,Closed 1363879305189,com.android.browser.BrowserActivity,Opened 1363879319226,com.android.browser.BrowserActivity,Closed 1363879319256,com.android.launcher2.Launcher,Opened 1363879320468,com.android.launcher2.Launcher,Closed 1363879353116,com.android.launcher2.Launcher,Opened 1363879366429,com.android.launcher2.Launcher,Closed 1363879366889,com.android.contacts.activities.PeopleActivity,Opened 1363879369170,com.android.contacts.activities.PeopleActivity,Closed 1363879369180,com.android.launcher2.Launcher,Opened 1363879371055,com.android.launcher2.Launcher,Closed 1363879371128,com.android.deskclock.DeskClock,Opened 1363879372918,com.android.deskclock.DeskClock,Closed 1363879372934,com.android.launcher2.Launcher,Opened 1363879374060,com.android.launcher2.Launcher,Closed 1363879374266,com.android.calendar.AllInOneActivity,Opened 1363879376829,com.android.calendar.AllInOneActivity,Closed 1363879376845,com.android.launcher2.Launcher,Opened 1363879386740,com.android.launcher2.Launcher,Closed While much more sophisticated parsing and pattern analysis can be easily performed on data in this, or similar, formats, for the purposes of this example it is sufficient to note the obvious. The log begins with the launcher, or the user s home screen. After that, many of the apps should be fairly recognizable from the activity names. This record shows the e-mail, browser, contacts, clock and calendar apps being used, in that order. The presence of the launcher activity between each app is expected, as the user returns there when exiting an application. The launcher, or any other app for that matter, being opened twice in a row is also not uncommon and indicates that the device screen has been turned off and then back on, temporarily pausing the foreground activity. The second developer sample takes a more active approach to using the system. It is the simplest version of the macro app described earlier in the document. This example requires no changes to the AndroidManifest.xml used in the first example. All modifications are made in the LifecycleReceiver.java file, as shown below. LifecycleReceiver.java 23

import android.app.activity; import android.content.broadcastreceiver; import android.content.componentname; import android.content.context; import android.content.intent; import android.net.uri; import android.util.log; public class LifecycleReceiver extends BroadcastReceiver { private static final String TAG = "LifecycleReceiver"; private static final String TARGET_CLASS_NAME = "com.android.deskclock.alarmalert"; @Override public void onreceive(context context, Intent intent) { String classname = ((ComponentName) intent.getparcelableextra(activity.extra_component_name)).getclassname(); int callback = intent.getintextra(activity.extra_callback, -1); if (classname.equals(target_class_name) && callback == Activity.ON_PAUSE) { Intent emailintent = context.getpackagemanager().getlaunchintentforpackage( com.android.email ); emailintent.addflags(intent.flag_activity_new_task); context.startactivity(emailintent); There are two main responsibilities of this broadcast receiver. The first is to recognize the user dismissing the alarm alert. This is done by retrieving the component name and lifecycle callback extras from the broadcast and comparing them with the name of the alarm alert activity in the desk clock application and the ON_PAUSE event, respectively. In the case where both items match, the second responsibility of launching the e-mail client application is executed 3. The end result is that every time the user dismisses an alarm, the e-mail client is automatically opened. 3 From an application design perspective, using an explicit intent to launch the e-mail app is not best practice. It is used in this example for the sake of simplicity. 24

9 Limitations While the system very well suits the purpose for which it was developed, there do exist limitations which may hinder its general applicability to other problems. These limitations are described in the following sections. 9.1 Falsified Broadcasts Because the lifecycle callback broadcasts are sent (unwittingly) by the activities and fragments that are being monitored, it is currently not possible to prevent an application from spamming broadcasts and bombarding receivers with false data. The impact of this limitation is that a malicious application can effectively corrupt the lifecycle callback data and potentially break the functionality of any application which relies on it. Possible solutions to this problem all rely on completely revamping the design to move the interception out of the Activity and Fragment classes and into a lower-level framework, or possibly even kernel, component. If the changes introduced by this system were to be merged back into the Android Open Source Project for use on a much larger scale this redesign would likely require further consideration. 9.2 Android Support Library Although fragments were introduced in Android 3.0, they have been back-ported to Android 1.6 through the Android Support Library [10]. Developers using fragments in applications targeting lower API levels can do so by packaging this library, which includes its own implementations of Fragment and other related classes, with their application. In cases where the support library is present, the implementations from the library will always be used rather than those from the operating system and, since these implementations are entirely distinct from those which this project has modified, the interception code for fragment lifecycle callbacks will not be available. 25

At first this may seem like a problem, but the percentage of applications which actually fall into this category is very small and only going to decrease as the older operating system versions become obsolete. Additionally, only the fragment callbacks are missed all activity callbacks are still intercepted properly. For these reasons, there is no need to address this limitation any further than simply documenting it. 26