summaryrefslogtreecommitdiff
path: root/core/java/android/app/ActivityManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/app/ActivityManager.java')
-rw-r--r--core/java/android/app/ActivityManager.java400
1 files changed, 348 insertions, 52 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a25e311f882a..bb04063905d5 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -16,10 +16,13 @@
package android.app;
-import android.R;
+import android.os.BatteryStats;
+import android.os.IBinder;
import com.android.internal.app.IUsageStats;
+import com.android.internal.app.ProcessStats;
import com.android.internal.os.PkgUsageStats;
-import com.android.internal.util.MemInfoReader;
+import com.android.internal.os.TransferPipe;
+import com.android.internal.util.FastPrintWriter;
import android.content.ComponentName;
import android.content.Context;
@@ -31,10 +34,7 @@ import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerGlobal;
-import android.os.Binder;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -49,8 +49,10 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
-import android.view.Display;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -66,6 +68,14 @@ public class ActivityManager {
private final Handler mHandler;
/**
+ * <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code
+ * &lt;meta-data>}</a> name for a 'home' Activity that declares a package that is to be
+ * uninstalled in lieu of the declaring one. The package named here must be
+ * signed with the same certificate as the one declaring the {@code &lt;meta-data>}.
+ */
+ public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
+
+ /**
* Result for IActivityManager.startActivity: an error where the
* start had to be canceled.
* @hide
@@ -222,6 +232,56 @@ public class ActivityManager {
/** @hide User operation call: given user id is the current user, can't be stopped. */
public static final int USER_OP_IS_CURRENT = -2;
+ /** @hide Process is a persistent system process. */
+ public static final int PROCESS_STATE_PERSISTENT = 0;
+
+ /** @hide Process is a persistent system process and is doing UI. */
+ public static final int PROCESS_STATE_PERSISTENT_UI = 1;
+
+ /** @hide Process is hosting the current top activities. Note that this covers
+ * all activities that are visible to the user. */
+ public static final int PROCESS_STATE_TOP = 2;
+
+ /** @hide Process is important to the user, and something they are aware of. */
+ public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 3;
+
+ /** @hide Process is important to the user, but not something they are aware of. */
+ public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 4;
+
+ /** @hide Process is in the background running a backup/restore operation. */
+ public static final int PROCESS_STATE_BACKUP = 5;
+
+ /** @hide Process is in the background, but it can't restore its state so we want
+ * to try to avoid killing it. */
+ public static final int PROCESS_STATE_HEAVY_WEIGHT = 6;
+
+ /** @hide Process is in the background running a service. Unlike oom_adj, this level
+ * is used for both the normal running in background state and the executing
+ * operations state. */
+ public static final int PROCESS_STATE_SERVICE = 7;
+
+ /** @hide Process is in the background running a receiver. Note that from the
+ * perspective of oom_adj receivers run at a higher foreground level, but for our
+ * prioritization here that is not necessary and putting them below services means
+ * many fewer changes in some process states as they receive broadcasts. */
+ public static final int PROCESS_STATE_RECEIVER = 8;
+
+ /** @hide Process is in the background but hosts the home activity. */
+ public static final int PROCESS_STATE_HOME = 9;
+
+ /** @hide Process is in the background but hosts the last shown activity. */
+ public static final int PROCESS_STATE_LAST_ACTIVITY = 10;
+
+ /** @hide Process is being cached for later use and contains activities. */
+ public static final int PROCESS_STATE_CACHED_ACTIVITY = 11;
+
+ /** @hide Process is being cached for later use and is a client of another cached
+ * process that contains activities. */
+ public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 12;
+
+ /** @hide Process is being cached for later use and is empty. */
+ public static final int PROCESS_STATE_CACHED_EMPTY = 13;
+
/*package*/ ActivityManager(Context context, Handler handler) {
mContext = context;
mHandler = handler;
@@ -370,53 +430,34 @@ public class ActivityManager {
// Really brain dead right now -- just take this from the configured
// vm heap size, and assume it is in megabytes and thus ends with "m".
String vmHeapSize = SystemProperties.get("dalvik.vm.heapsize", "16m");
- return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length() - 1));
+ return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
}
/**
- * Used by persistent processes to determine if they are running on a
- * higher-end device so should be okay using hardware drawing acceleration
- * (which tends to consume a lot more RAM).
- * @hide
+ * Returns true if this is a low-RAM device. Exactly whether a device is low-RAM
+ * is ultimately up to the device configuration, but currently it generally means
+ * something in the class of a 512MB device with about a 800x480 or less screen.
+ * This is mostly intended to be used by apps to determine whether they should turn
+ * off certain features that require more RAM.
*/
- static public boolean isHighEndGfx() {
- MemInfoReader reader = new MemInfoReader();
- reader.readMemInfo();
- if (reader.getTotalSize() >= (512*1024*1024)) {
- // If the device has at least 512MB RAM available to the kernel,
- // we can afford the overhead of graphics acceleration.
- return true;
- }
-
- Display display = DisplayManagerGlobal.getInstance().getRealDisplay(
- Display.DEFAULT_DISPLAY);
- Point p = new Point();
- display.getRealSize(p);
- int pixels = p.x * p.y;
- if (pixels >= (1024*600)) {
- // If this is a sufficiently large screen, then there are enough
- // pixels on it that we'd really like to use hw drawing.
- return true;
- }
- return false;
+ public boolean isLowRamDevice() {
+ return isLowRamDeviceStatic();
+ }
+
+ /** @hide */
+ public static boolean isLowRamDeviceStatic() {
+ return "true".equals(SystemProperties.get("ro.config.low_ram", "false"));
}
/**
- * Use to decide whether the running device can be considered a "large
- * RAM" device. Exactly what memory limit large RAM is will vary, but
- * it essentially means there is plenty of RAM to have lots of background
- * processes running under decent loads.
+ * Used by persistent processes to determine if they are running on a
+ * higher-end device so should be okay using hardware drawing acceleration
+ * (which tends to consume a lot more RAM).
* @hide
*/
- static public boolean isLargeRAM() {
- MemInfoReader reader = new MemInfoReader();
- reader.readMemInfo();
- if (reader.getTotalSize() >= (640*1024*1024)) {
- // Currently 640MB RAM available to the kernel is the point at
- // which we have plenty of RAM to spare.
- return true;
- }
- return false;
+ static public boolean isHighEndGfx() {
+ return !isLowRamDeviceStatic() &&
+ !Resources.getSystem().getBoolean(com.android.internal.R.bool.config_avoidGfxAccel);
}
/**
@@ -454,14 +495,22 @@ public class ActivityManager {
* Description of the task's last state.
*/
public CharSequence description;
-
+
+ /**
+ * The id of the ActivityStack this Task was on most recently.
+ * @hide
+ */
+ public int stackId;
+
public RecentTaskInfo() {
}
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeInt(persistentId);
@@ -474,6 +523,7 @@ public class ActivityManager {
ComponentName.writeToParcel(origActivity, dest);
TextUtils.writeToParcel(description, dest,
Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ dest.writeInt(stackId);
}
public void readFromParcel(Parcel source) {
@@ -486,8 +536,9 @@ public class ActivityManager {
}
origActivity = ComponentName.readFromParcel(source);
description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+ stackId = source.readInt();
}
-
+
public static final Creator<RecentTaskInfo> CREATOR
= new Creator<RecentTaskInfo>() {
public RecentTaskInfo createFromParcel(Parcel source) {
@@ -629,6 +680,12 @@ public class ActivityManager {
*/
public int numRunning;
+ /**
+ * Last time task was run. For sorting.
+ * @hide
+ */
+ public long lastActiveTime;
+
public RunningTaskInfo() {
}
@@ -1230,7 +1287,169 @@ public class ActivityManager {
} catch (RemoteException e) {
}
}
-
+
+ /**
+ * Information you can retrieve about the WindowManager StackBox hierarchy.
+ * @hide
+ */
+ public static class StackBoxInfo implements Parcelable {
+ public int stackBoxId;
+ public float weight;
+ public boolean vertical;
+ public Rect bounds;
+ public StackBoxInfo[] children;
+ public int stackId;
+ public StackInfo stack;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(stackBoxId);
+ dest.writeFloat(weight);
+ dest.writeInt(vertical ? 1 : 0);
+ bounds.writeToParcel(dest, flags);
+ dest.writeInt(stackId);
+ if (children != null) {
+ children[0].writeToParcel(dest, flags);
+ children[1].writeToParcel(dest, flags);
+ } else {
+ stack.writeToParcel(dest, flags);
+ }
+ }
+
+ public void readFromParcel(Parcel source) {
+ stackBoxId = source.readInt();
+ weight = source.readFloat();
+ vertical = source.readInt() == 1;
+ bounds = Rect.CREATOR.createFromParcel(source);
+ stackId = source.readInt();
+ if (stackId == -1) {
+ children = new StackBoxInfo[2];
+ children[0] = StackBoxInfo.CREATOR.createFromParcel(source);
+ children[1] = StackBoxInfo.CREATOR.createFromParcel(source);
+ } else {
+ stack = StackInfo.CREATOR.createFromParcel(source);
+ }
+ }
+
+ public static final Creator<StackBoxInfo> CREATOR =
+ new Creator<ActivityManager.StackBoxInfo>() {
+
+ @Override
+ public StackBoxInfo createFromParcel(Parcel source) {
+ return new StackBoxInfo(source);
+ }
+
+ @Override
+ public StackBoxInfo[] newArray(int size) {
+ return new StackBoxInfo[size];
+ }
+ };
+
+ public StackBoxInfo() {
+ }
+
+ public StackBoxInfo(Parcel source) {
+ readFromParcel(source);
+ }
+
+ public String toString(String prefix) {
+ StringBuilder sb = new StringBuilder(256);
+ sb.append(prefix); sb.append("Box id=" + stackBoxId); sb.append(" weight=" + weight);
+ sb.append(" vertical=" + vertical); sb.append(" bounds=" + bounds.toShortString());
+ sb.append("\n");
+ if (children != null) {
+ sb.append(prefix); sb.append("First child=\n");
+ sb.append(children[0].toString(prefix + " "));
+ sb.append(prefix); sb.append("Second child=\n");
+ sb.append(children[1].toString(prefix + " "));
+ } else {
+ sb.append(prefix); sb.append("Stack=\n");
+ sb.append(stack.toString(prefix + " "));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return toString("");
+ }
+ }
+
+ /**
+ * Information you can retrieve about an ActivityStack in the system.
+ * @hide
+ */
+ public static class StackInfo implements Parcelable {
+ public int stackId;
+ public Rect bounds;
+ public int[] taskIds;
+ public String[] taskNames;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(stackId);
+ dest.writeInt(bounds.left);
+ dest.writeInt(bounds.top);
+ dest.writeInt(bounds.right);
+ dest.writeInt(bounds.bottom);
+ dest.writeIntArray(taskIds);
+ dest.writeStringArray(taskNames);
+ }
+
+ public void readFromParcel(Parcel source) {
+ stackId = source.readInt();
+ bounds = new Rect(
+ source.readInt(), source.readInt(), source.readInt(), source.readInt());
+ taskIds = source.createIntArray();
+ taskNames = source.createStringArray();
+ }
+
+ public static final Creator<StackInfo> CREATOR = new Creator<StackInfo>() {
+ @Override
+ public StackInfo createFromParcel(Parcel source) {
+ return new StackInfo(source);
+ }
+ @Override
+ public StackInfo[] newArray(int size) {
+ return new StackInfo[size];
+ }
+ };
+
+ public StackInfo() {
+ }
+
+ private StackInfo(Parcel source) {
+ readFromParcel(source);
+ }
+
+ public String toString(String prefix) {
+ StringBuilder sb = new StringBuilder(256);
+ sb.append(prefix); sb.append("Stack id="); sb.append(stackId);
+ sb.append(" bounds="); sb.append(bounds.toShortString()); sb.append("\n");
+ prefix = prefix + " ";
+ for (int i = 0; i < taskIds.length; ++i) {
+ sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]);
+ sb.append(": "); sb.append(taskNames[i]); sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return toString("");
+ }
+ }
+
/**
* @hide
*/
@@ -1242,7 +1461,21 @@ public class ActivityManager {
return false;
}
}
-
+
+ /**
+ * Permits an application to erase its own data from disk. This is equivalent to
+ * the user choosing to clear the app's data from within the device settings UI. It
+ * erases all dynamic data associated with the app -- its private data and data in its
+ * private area on external storage -- but does not remove the installed application
+ * itself, nor any OBB files.
+ *
+ * @return {@code true} if the application successfully requested that the application's
+ * data be erased; {@code false} otherwise.
+ */
+ public boolean clearApplicationUserData() {
+ return clearApplicationUserData(mContext.getPackageName(), null);
+ }
+
/**
* Information you can retrieve about any processes that are in an error condition.
*/
@@ -1304,10 +1537,12 @@ public class ActivityManager {
public ProcessErrorStateInfo() {
}
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(condition);
dest.writeString(processName);
@@ -1318,7 +1553,7 @@ public class ActivityManager {
dest.writeString(longMsg);
dest.writeString(stackTrace);
}
-
+
public void readFromParcel(Parcel source) {
condition = source.readInt();
processName = source.readString();
@@ -1538,7 +1773,7 @@ public class ActivityManager {
public ComponentName importanceReasonComponent;
/**
- * When {@link importanceReasonPid} is non-0, this is the importance
+ * When {@link #importanceReasonPid} is non-0, this is the importance
* of the other pid. @hide
*/
public int importanceReasonImportance;
@@ -1888,7 +2123,12 @@ public class ActivityManager {
}
// If the target is not exported, then nobody else can get to it.
if (!exported) {
- Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid);
+ /*
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
+ here);
+ */
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
@@ -2010,4 +2250,60 @@ public class ActivityManager {
return false;
}
}
+
+ /**
+ * Perform a system dump of various state associated with the given application
+ * package name. This call blocks while the dump is being performed, so should
+ * not be done on a UI thread. The data will be written to the given file
+ * descriptor as text. An application must hold the
+ * {@link android.Manifest.permission#DUMP} permission to make this call.
+ * @param fd The file descriptor that the dump should be written to. The file
+ * descriptor is <em>not</em> closed by this function; the caller continues to
+ * own it.
+ * @param packageName The name of the package that is to be dumped.
+ */
+ public void dumpPackageState(FileDescriptor fd, String packageName) {
+ dumpPackageStateStatic(fd, packageName);
+ }
+
+ /**
+ * @hide
+ */
+ public static void dumpPackageStateStatic(FileDescriptor fd, String packageName) {
+ FileOutputStream fout = new FileOutputStream(fd);
+ PrintWriter pw = new FastPrintWriter(fout);
+ dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { "package", packageName });
+ pw.println();
+ dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { packageName });
+ pw.println();
+ dumpService(pw, fd, "usagestats", new String[] { "--packages", packageName });
+ pw.println();
+ dumpService(pw, fd, "package", new String[] { packageName });
+ pw.println();
+ dumpService(pw, fd, BatteryStats.SERVICE_NAME, new String[] { packageName });
+ pw.flush();
+ }
+
+ private static void dumpService(PrintWriter pw, FileDescriptor fd, String name, String[] args) {
+ pw.print("DUMP OF SERVICE "); pw.print(name); pw.println(":");
+ IBinder service = ServiceManager.checkService(name);
+ if (service == null) {
+ pw.println(" (Service not found)");
+ return;
+ }
+ TransferPipe tp = null;
+ try {
+ pw.flush();
+ tp = new TransferPipe();
+ tp.setBufferPrefix(" ");
+ service.dump(tp.getWriteFd().getFileDescriptor(), args);
+ tp.go(fd);
+ } catch (Throwable e) {
+ if (tp != null) {
+ tp.kill();
+ }
+ pw.println("Failure dumping service:");
+ e.printStackTrace(pw);
+ }
+ }
}