summaryrefslogtreecommitdiff
path: root/services/java/com/android/server/am/ActivityManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/am/ActivityManagerService.java')
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java267
1 files changed, 233 insertions, 34 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 361c7f7b02d3..f5efe4b591fe 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -48,6 +48,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
@@ -96,6 +97,7 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
+import java.lang.IllegalStateException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
@@ -631,6 +633,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* any user id that can impact battery performance.
*/
final BatteryStatsService mBatteryStatsService;
+
+ /**
+ * information about component usage
+ */
+ final UsageStatsService mUsageStatsService;
/**
* Current configuration information. HistoryRecord objects are given
@@ -1053,6 +1060,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
m.mLaunchingActivity.setReferenceCounted(false);
m.mBatteryStatsService.publish(context);
+ m.mUsageStatsService.publish(context);
synchronized (thr) {
thr.mReady = true;
@@ -1186,8 +1194,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
procs = service.mLRUProcesses;
}
}
- pw.println("Applications Memory Usage (kB):");
- dumpApplicationMemoryUsage(fd, pw, procs, " ");
+ dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
}
}
@@ -1224,6 +1231,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
systemDir, "batterystats.bin").toString());
mBatteryStatsService.getActiveStatistics().readLocked();
mBatteryStatsService.getActiveStatistics().writeLocked();
+
+ mUsageStatsService = new UsageStatsService( new File(
+ systemDir, "usagestats.bin").toString());
mConfiguration.makeDefault();
mProcessStats.init();
@@ -1522,6 +1532,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
r.info, r.icicle, results, newIntents, !andResume,
isNextTransitionForward());
+ // Update usage stats for launched activity
+ updateUsageStats(r, true);
} catch (RemoteException e) {
if (r.launchFailed) {
// This is the second time we failed -- finish activity
@@ -1804,6 +1816,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
prev.shortComponentName);
prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
prev.configChangeFlags);
+ updateUsageStats(prev, false);
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Log.w(TAG, "Exception thrown during pause", e);
@@ -1848,6 +1861,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final void completePauseLocked() {
HistoryRecord prev = mPausingActivity;
if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
+
if (prev != null) {
if (prev.finishing) {
if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
@@ -2085,6 +2099,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ensureActivitiesVisibleLocked(r, starting, null, configChanges);
}
}
+
+ private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
+ if (resumed) {
+ mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
+ } else {
+ mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
+ }
+ }
/**
* Ensure that the top activity in the stack is resumed.
@@ -2290,6 +2312,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
System.identityHashCode(next),
next.task.taskId, next.shortComponentName);
+ updateUsageStats(next, true);
next.app.thread.scheduleResumeActivity(next,
isNextTransitionForward());
@@ -2453,9 +2476,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
if (prev.task != r.task) prev = null;
- // (2) The current activity is not the first in the task.
- else if (!prev.frontOfTask) prev = null;
- // (3) The current activity is already displayed.
+ // (2) The current activity is already displayed.
else if (prev.nowVisible) prev = null;
}
mWindowManager.setAppStartingWindow(
@@ -2537,6 +2558,40 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
/**
+ * Find the activity in the history stack within the given task. Returns
+ * the index within the history at which it's found, or < 0 if not found.
+ */
+ private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
+ int i = mHistory.size();
+ while (i > 0) {
+ i--;
+ HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
+ if (candidate.task.taskId != task) {
+ break;
+ }
+ if (candidate.realActivity.equals(r.realActivity)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Reorder the history stack so that the activity at the given index is
+ * brought to the front.
+ */
+ private final HistoryRecord moveActivityToFrontLocked(int where) {
+ HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
+ int top = mHistory.size();
+ HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
+ mHistory.add(top, newTop);
+ oldTop.frontOfTask = false;
+ newTop.frontOfTask = true;
+ return newTop;
+ }
+
+ /**
* Deliver a new Intent to an existing activity, so that its onNewIntent()
* method will be called at the proper time.
*/
@@ -2969,6 +3024,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
resumeTopActivityLocked(null);
return START_DELIVERED_TO_TOP;
}
+ } else if (!addingToTask &&
+ (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
+ // In this case, we are launching an activity in our own task
+ // that may already be running somewhere in the history, and
+ // we want to shuffle it to the front of the stack if so.
+ int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
+ if (where >= 0) {
+ HistoryRecord top = moveActivityToFrontLocked(where);
+ logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
+ deliverNewIntentLocked(top, r.intent);
+ resumeTopActivityLocked(null);
+ return START_DELIVERED_TO_TOP;
+ }
}
// An existing activity is starting this new activity, so we want
// to keep the new one in the same task as the one that is starting
@@ -4142,8 +4210,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = ActivityThread.getPackageManager();
+ int pkgUid = -1;
synchronized(this) {
- int pkgUid = -1;
try {
pkgUid = pm.getPackageUid(packageName);
} catch (RemoteException e) {
@@ -4156,7 +4224,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
android.Manifest.permission.CLEAR_APP_USER_DATA,
pid, uid, -1)
== PackageManager.PERMISSION_GRANTED) {
- uninstallPackageLocked(packageName, pkgUid, false);
+ restartPackageLocked(packageName, pkgUid);
} else {
throw new SecurityException(pid+" does not have permission:"+
android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
@@ -4167,6 +4235,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
//clear application user data
pm.clearApplicationUserData(packageName, observer);
+ Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
+ Uri.fromParts("package", packageName, null));
+ intent.putExtra(Intent.EXTRA_UID, pkgUid);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID);
} catch (RemoteException e) {
}
} finally {
@@ -4188,25 +4262,48 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
long callingId = Binder.clearCallingIdentity();
try {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ int pkgUid = -1;
synchronized(this) {
- uninstallPackageLocked(packageName, -1, false);
- broadcastIntentLocked(null, null,
- new Intent(Intent.ACTION_PACKAGE_RESTARTED,
- Uri.fromParts("package", packageName, null)),
- null, null, 0, null, null, null,
- false, false, MY_PID, Process.SYSTEM_UID);
+ try {
+ pkgUid = pm.getPackageUid(packageName);
+ } catch (RemoteException e) {
+ }
+ if (pkgUid == -1) {
+ Log.w(TAG, "Invalid packageName:"+packageName);
+ return;
+ }
+ restartPackageLocked(packageName, pkgUid);
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
+ private void restartPackageLocked(final String packageName, int uid) {
+ uninstallPackageLocked(packageName, uid, false);
+ Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
+ Uri.fromParts("package", packageName, null));
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID);
+ }
+
private final void uninstallPackageLocked(String name, int uid,
boolean callerWillRestart) {
if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
int i, N;
+ final String procNamePrefix = name + ":";
+ if (uid < 0) {
+ try {
+ uid = ActivityThread.getPackageManager().getPackageUid(name);
+ } catch (RemoteException e) {
+ }
+ }
+
Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
while (badApps.hasNext()) {
SparseArray<Long> ba = badApps.next();
@@ -4217,14 +4314,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
- final String procNamePrefix = name + ":";
- if (uid < 0) {
- try {
- uid = ActivityThread.getPackageManager().getPackageUid(name);
- } catch (RemoteException e) {
- }
- }
-
// Remove all processes this package may have touched: all with the
// same UID (except for the system or root user), and all whose name
// matches the package name.
@@ -7226,6 +7315,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ public boolean testIsSystemReady() {
+ // no need to synchronize(this) just to read & return the value
+ return mSystemReady;
+ }
+
public void systemReady() {
// In the simulator, startRunning will never have been called, which
// normally sets a few crucial variables. Do it here instead.
@@ -7628,6 +7722,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ActivityManager.RunningAppProcessInfo currApp =
new ActivityManager.RunningAppProcessInfo(app.processName,
app.pid, app.getPackageList());
+ int adj = app.curAdj;
+ if (adj >= CONTENT_PROVIDER_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
+ } else if (adj >= HIDDEN_APP_MIN_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
+ currApp.lru = adj - HIDDEN_APP_MIN_ADJ;
+ } else if (adj >= SECONDARY_SERVER_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
+ } else if (adj >= VISIBLE_APP_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+ } else {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+ }
+ //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
+ // + " lru=" + currApp.lru);
if (runList == null) {
runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
}
@@ -8176,28 +8285,53 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
- PrintWriter pw, List list, String prefix) {
+ PrintWriter pw, List list, String prefix, String[] args) {
+ final boolean isCheckinRequest = scanArgs(args, "-c");
+ long uptime = SystemClock.uptimeMillis();
+ long realtime = SystemClock.elapsedRealtime();
+
+ if (isCheckinRequest) {
+ // short checkin version
+ pw.println(uptime + "," + realtime);
+ pw.flush();
+ } else {
+ pw.println("Applications Memory Usage (kB):");
+ pw.println("Uptime: " + uptime + " Realtime: " + realtime);
+ }
for (int i = list.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = (ProcessRecord)list.get(i);
if (r.thread != null) {
- pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
- pw.flush();
-
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
+ if (!isCheckinRequest) {
+ pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
+ pw.flush();
+ }
try {
- data.writeFileDescriptor(fd);
- r.thread.asBinder().transact(IBinder.DUMP_TRANSACTION, data, reply, 0);
-
+ r.thread.asBinder().dump(fd, args);
} catch (RemoteException e) {
- pw.println("Got RemoteException!");
- pw.flush();
+ if (!isCheckinRequest) {
+ pw.println("Got RemoteException!");
+ pw.flush();
+ }
}
+ }
+ }
+ }
- data.recycle();
- reply.recycle();
+ /**
+ * Searches array of arguments for the specified string
+ * @param args array of argument strings
+ * @param value value to search for
+ * @return true if the value is contained in the array
+ */
+ private static boolean scanArgs(String[] args, String value) {
+ if (args != null) {
+ for (String arg : args) {
+ if (value.equals(arg)) {
+ return true;
+ }
}
}
+ return false;
}
private final int indexOfTokenLocked(IBinder token, boolean required) {
@@ -9120,6 +9254,36 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return 0;
}
+ public IBinder peekService(Intent service, String resolvedType) {
+ // Refuse possible leaked file descriptors
+ if (service != null && service.hasFileDescriptors() == true) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+
+ IBinder ret = null;
+
+ synchronized(this) {
+ ServiceLookupResult r = findServiceLocked(service, resolvedType);
+
+ if (r != null) {
+ // r.record is null if findServiceLocked() failed the caller permission check
+ if (r.record == null) {
+ throw new SecurityException(
+ "Permission Denial: Accessing service " + r.record.name
+ + " from pid=" + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + r.permission);
+ }
+ IntentBindRecord ib = r.record.bindings.get(r.record.intent);
+ if (ib != null) {
+ ret = ib.binder;
+ }
+ }
+ }
+
+ return ret;
+ }
+
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) {
synchronized(this) {
@@ -9928,6 +10092,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized(this) {
+ if (!mSystemReady) {
+ // if the caller really truly claims to know what they're doing, go
+ // ahead and allow the broadcast without launching any receivers
+ int flags = intent.getFlags();
+ if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
+ intent = new Intent(intent);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
+ Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
+ + " before boot completion");
+ throw new IllegalStateException("Cannot broadcast before boot completed");
+ }
+ }
+
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
@@ -10639,6 +10817,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// =========================================================
// CONFIGURATION
// =========================================================
+
+ public ConfigurationInfo getDeviceConfigurationInfo() {
+ ConfigurationInfo config = new ConfigurationInfo();
+ synchronized (this) {
+ config.reqTouchScreen = mConfiguration.touchscreen;
+ config.reqKeyboardType = mConfiguration.keyboard;
+ config.reqNavigation = mConfiguration.navigation;
+ if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
+ config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
+ }
+ if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
+ config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
+ }
+ }
+ return config;
+ }
public Configuration getConfiguration() {
Configuration ci;
@@ -10653,6 +10847,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
"updateConfiguration()");
synchronized(this) {
+ if (values == null && mWindowManager != null) {
+ // sentinel: fetch the current configuration from the window manager
+ values = mWindowManager.computeNewConfiguration();
+ }
+
final long origId = Binder.clearCallingIdentity();
updateConfigurationLocked(values, null);
Binder.restoreCallingIdentity(origId);