Merge "Prevent authenticators from using Settings to  launch arbitrary activities." into klp-dev
diff --git a/Android.mk b/Android.mk
index 13b717a..49dc6af 100644
--- a/Android.mk
+++ b/Android.mk
@@ -433,6 +433,7 @@
 
 non_base_dirs := \
 	../../external/apache-http/src/org/apache/http \
+	../opt/telephony/src/java/android/provider \
 	../opt/telephony/src/java/android/telephony \
 	../opt/telephony/src/java/android/telephony/gsm \
 	../opt/net/voip/src/java/android/net/rtp \
diff --git a/api/current.txt b/api/current.txt
index 37881e6..f4f3602 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21727,6 +21727,277 @@
     method public static void update(android.content.ContentProviderClient, android.net.Uri, byte[]) throws android.os.RemoteException;
   }
 
+  public final class Telephony {
+  }
+
+  public static abstract interface Telephony.BaseMmsColumns implements android.provider.BaseColumns {
+    field public static final java.lang.String CONTENT_CLASS = "ct_cls";
+    field public static final java.lang.String CONTENT_LOCATION = "ct_l";
+    field public static final java.lang.String CONTENT_TYPE = "ct_t";
+    field public static final java.lang.String DATE = "date";
+    field public static final java.lang.String DATE_SENT = "date_sent";
+    field public static final java.lang.String DELIVERY_REPORT = "d_rpt";
+    field public static final java.lang.String DELIVERY_TIME = "d_tm";
+    field public static final java.lang.String EXPIRY = "exp";
+    field public static final java.lang.String LOCKED = "locked";
+    field public static final java.lang.String MESSAGE_BOX = "msg_box";
+    field public static final int MESSAGE_BOX_ALL = 0; // 0x0
+    field public static final int MESSAGE_BOX_DRAFTS = 3; // 0x3
+    field public static final int MESSAGE_BOX_INBOX = 1; // 0x1
+    field public static final int MESSAGE_BOX_OUTBOX = 4; // 0x4
+    field public static final int MESSAGE_BOX_SENT = 2; // 0x2
+    field public static final java.lang.String MESSAGE_CLASS = "m_cls";
+    field public static final java.lang.String MESSAGE_ID = "m_id";
+    field public static final java.lang.String MESSAGE_SIZE = "m_size";
+    field public static final java.lang.String MESSAGE_TYPE = "m_type";
+    field public static final java.lang.String MMS_VERSION = "v";
+    field public static final java.lang.String PRIORITY = "pri";
+    field public static final java.lang.String READ = "read";
+    field public static final java.lang.String READ_REPORT = "rr";
+    field public static final java.lang.String READ_STATUS = "read_status";
+    field public static final java.lang.String REPORT_ALLOWED = "rpt_a";
+    field public static final java.lang.String RESPONSE_STATUS = "resp_st";
+    field public static final java.lang.String RESPONSE_TEXT = "resp_txt";
+    field public static final java.lang.String RETRIEVE_STATUS = "retr_st";
+    field public static final java.lang.String RETRIEVE_TEXT = "retr_txt";
+    field public static final java.lang.String RETRIEVE_TEXT_CHARSET = "retr_txt_cs";
+    field public static final java.lang.String SEEN = "seen";
+    field public static final java.lang.String STATUS = "st";
+    field public static final java.lang.String SUBJECT = "sub";
+    field public static final java.lang.String SUBJECT_CHARSET = "sub_cs";
+    field public static final java.lang.String TEXT_ONLY = "text_only";
+    field public static final java.lang.String THREAD_ID = "thread_id";
+    field public static final java.lang.String TRANSACTION_ID = "tr_id";
+  }
+
+  public static abstract interface Telephony.CanonicalAddressesColumns implements android.provider.BaseColumns {
+    field public static final java.lang.String ADDRESS = "address";
+  }
+
+  public static final class Telephony.Carriers implements android.provider.BaseColumns {
+    field public static final java.lang.String APN = "apn";
+    field public static final java.lang.String AUTH_TYPE = "authtype";
+    field public static final java.lang.String BEARER = "bearer";
+    field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String CURRENT = "current";
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "name ASC";
+    field public static final java.lang.String MCC = "mcc";
+    field public static final java.lang.String MMSC = "mmsc";
+    field public static final java.lang.String MMSPORT = "mmsport";
+    field public static final java.lang.String MMSPROXY = "mmsproxy";
+    field public static final java.lang.String MNC = "mnc";
+    field public static final java.lang.String MVNO_MATCH_DATA = "mvno_match_data";
+    field public static final java.lang.String MVNO_TYPE = "mvno_type";
+    field public static final java.lang.String NAME = "name";
+    field public static final java.lang.String NUMERIC = "numeric";
+    field public static final java.lang.String PASSWORD = "password";
+    field public static final java.lang.String PORT = "port";
+    field public static final java.lang.String PROTOCOL = "protocol";
+    field public static final java.lang.String PROXY = "proxy";
+    field public static final java.lang.String ROAMING_PROTOCOL = "roaming_protocol";
+    field public static final java.lang.String SERVER = "server";
+    field public static final java.lang.String TYPE = "type";
+    field public static final java.lang.String USER = "user";
+  }
+
+  public static final class Telephony.Mms implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final android.net.Uri REPORT_REQUEST_URI;
+    field public static final android.net.Uri REPORT_STATUS_URI;
+  }
+
+  public static final class Telephony.Mms.Addr implements android.provider.BaseColumns {
+    field public static final java.lang.String ADDRESS = "address";
+    field public static final java.lang.String CHARSET = "charset";
+    field public static final java.lang.String CONTACT_ID = "contact_id";
+    field public static final java.lang.String MSG_ID = "msg_id";
+    field public static final java.lang.String TYPE = "type";
+  }
+
+  public static final class Telephony.Mms.Draft implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Mms.Inbox implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Mms.Intents {
+    field public static final java.lang.String CONTENT_CHANGED_ACTION = "android.intent.action.CONTENT_CHANGED";
+    field public static final java.lang.String DELETED_CONTENTS = "deleted_contents";
+  }
+
+  public static final class Telephony.Mms.Outbox implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Mms.Part implements android.provider.BaseColumns {
+    field public static final java.lang.String CHARSET = "chset";
+    field public static final java.lang.String CONTENT_DISPOSITION = "cd";
+    field public static final java.lang.String CONTENT_ID = "cid";
+    field public static final java.lang.String CONTENT_LOCATION = "cl";
+    field public static final java.lang.String CONTENT_TYPE = "ct";
+    field public static final java.lang.String CT_START = "ctt_s";
+    field public static final java.lang.String CT_TYPE = "ctt_t";
+    field public static final java.lang.String FILENAME = "fn";
+    field public static final java.lang.String MSG_ID = "mid";
+    field public static final java.lang.String NAME = "name";
+    field public static final java.lang.String SEQ = "seq";
+    field public static final java.lang.String TEXT = "text";
+    field public static final java.lang.String _DATA = "_data";
+  }
+
+  public static final class Telephony.Mms.Rate {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String SENT_TIME = "sent_time";
+  }
+
+  public static final class Telephony.Mms.Sent implements android.provider.Telephony.BaseMmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.MmsSms implements android.provider.BaseColumns {
+    field public static final android.net.Uri CONTENT_CONVERSATIONS_URI;
+    field public static final android.net.Uri CONTENT_DRAFT_URI;
+    field public static final android.net.Uri CONTENT_FILTER_BYPHONE_URI;
+    field public static final android.net.Uri CONTENT_LOCKED_URI;
+    field public static final android.net.Uri CONTENT_UNDELIVERED_URI;
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final int ERR_TYPE_GENERIC = 1; // 0x1
+    field public static final int ERR_TYPE_GENERIC_PERMANENT = 10; // 0xa
+    field public static final int ERR_TYPE_MMS_PROTO_PERMANENT = 12; // 0xc
+    field public static final int ERR_TYPE_MMS_PROTO_TRANSIENT = 3; // 0x3
+    field public static final int ERR_TYPE_SMS_PROTO_PERMANENT = 11; // 0xb
+    field public static final int ERR_TYPE_SMS_PROTO_TRANSIENT = 2; // 0x2
+    field public static final int ERR_TYPE_TRANSPORT_FAILURE = 4; // 0x4
+    field public static final int MMS_PROTO = 1; // 0x1
+    field public static final int NO_ERROR = 0; // 0x0
+    field public static final android.net.Uri SEARCH_URI;
+    field public static final int SMS_PROTO = 0; // 0x0
+    field public static final java.lang.String TYPE_DISCRIMINATOR_COLUMN = "transport_type";
+  }
+
+  public static final class Telephony.MmsSms.PendingMessages implements android.provider.BaseColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DUE_TIME = "due_time";
+    field public static final java.lang.String ERROR_CODE = "err_code";
+    field public static final java.lang.String ERROR_TYPE = "err_type";
+    field public static final java.lang.String LAST_TRY = "last_try";
+    field public static final java.lang.String MSG_ID = "msg_id";
+    field public static final java.lang.String MSG_TYPE = "msg_type";
+    field public static final java.lang.String PROTO_TYPE = "proto_type";
+    field public static final java.lang.String RETRY_INDEX = "retry_index";
+  }
+
+  public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    method public static java.lang.String getDefaultSmsPackage(android.content.Context);
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Sms.Conversations implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final java.lang.String MESSAGE_COUNT = "msg_count";
+    field public static final java.lang.String SNIPPET = "snippet";
+  }
+
+  public static final class Telephony.Sms.Draft implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Sms.Inbox implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Sms.Intents {
+    method public static android.telephony.SmsMessage[] getMessagesFromIntent(android.content.Intent);
+    field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.provider.Telephony.ACTION_CHANGE_DEFAULT";
+    field public static final java.lang.String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
+    field public static final java.lang.String EXTRA_PACKAGE_NAME = "package";
+    field public static final int RESULT_SMS_DUPLICATED = 5; // 0x5
+    field public static final int RESULT_SMS_GENERIC_ERROR = 2; // 0x2
+    field public static final int RESULT_SMS_HANDLED = 1; // 0x1
+    field public static final int RESULT_SMS_OUT_OF_MEMORY = 3; // 0x3
+    field public static final int RESULT_SMS_UNSUPPORTED = 4; // 0x4
+    field public static final java.lang.String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL";
+    field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
+    field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
+    field public static final java.lang.String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
+    field public static final java.lang.String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
+    field public static final java.lang.String SMS_REJECTED_ACTION = "android.provider.Telephony.SMS_REJECTED";
+    field public static final java.lang.String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION = "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
+    field public static final java.lang.String WAP_PUSH_DELIVER_ACTION = "android.provider.Telephony.WAP_PUSH_DELIVER";
+    field public static final java.lang.String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
+  }
+
+  public static final class Telephony.Sms.Outbox implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static final class Telephony.Sms.Sent implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+  }
+
+  public static abstract interface Telephony.TextBasedSmsColumns {
+    field public static final java.lang.String ADDRESS = "address";
+    field public static final java.lang.String BODY = "body";
+    field public static final java.lang.String DATE = "date";
+    field public static final java.lang.String DATE_SENT = "date_sent";
+    field public static final java.lang.String ERROR_CODE = "error_code";
+    field public static final java.lang.String LOCKED = "locked";
+    field public static final int MESSAGE_TYPE_ALL = 0; // 0x0
+    field public static final int MESSAGE_TYPE_DRAFT = 3; // 0x3
+    field public static final int MESSAGE_TYPE_FAILED = 5; // 0x5
+    field public static final int MESSAGE_TYPE_INBOX = 1; // 0x1
+    field public static final int MESSAGE_TYPE_OUTBOX = 4; // 0x4
+    field public static final int MESSAGE_TYPE_QUEUED = 6; // 0x6
+    field public static final int MESSAGE_TYPE_SENT = 2; // 0x2
+    field public static final java.lang.String PERSON = "person";
+    field public static final java.lang.String PROTOCOL = "protocol";
+    field public static final java.lang.String READ = "read";
+    field public static final java.lang.String REPLY_PATH_PRESENT = "reply_path_present";
+    field public static final java.lang.String SEEN = "seen";
+    field public static final java.lang.String SERVICE_CENTER = "service_center";
+    field public static final java.lang.String STATUS = "status";
+    field public static final int STATUS_COMPLETE = 0; // 0x0
+    field public static final int STATUS_FAILED = 64; // 0x40
+    field public static final int STATUS_NONE = -1; // 0xffffffff
+    field public static final int STATUS_PENDING = 32; // 0x20
+    field public static final java.lang.String SUBJECT = "subject";
+    field public static final java.lang.String THREAD_ID = "thread_id";
+    field public static final java.lang.String TYPE = "type";
+  }
+
+  public static final class Telephony.Threads implements android.provider.Telephony.ThreadsColumns {
+    field public static final int BROADCAST_THREAD = 1; // 0x1
+    field public static final int COMMON_THREAD = 0; // 0x0
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final android.net.Uri OBSOLETE_THREADS_URI;
+  }
+
+  public static abstract interface Telephony.ThreadsColumns implements android.provider.BaseColumns {
+    field public static final java.lang.String DATE = "date";
+    field public static final java.lang.String ERROR = "error";
+    field public static final java.lang.String HAS_ATTACHMENT = "has_attachment";
+    field public static final java.lang.String MESSAGE_COUNT = "message_count";
+    field public static final java.lang.String READ = "read";
+    field public static final java.lang.String RECIPIENT_IDS = "recipient_ids";
+    field public static final java.lang.String SNIPPET = "snippet";
+    field public static final java.lang.String SNIPPET_CHARSET = "snippet_cs";
+    field public static final java.lang.String TYPE = "type";
+  }
+
   public class UserDictionary {
     ctor public UserDictionary();
     field public static final java.lang.String AUTHORITY = "user_dictionary";
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index 6432a37..d32b71b 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -28,6 +28,7 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.List;
 
 /**
@@ -40,8 +41,8 @@
     private static final int MSG_PRINTERS_ADDED = 1;
     private static final int MSG_PRINTERS_REMOVED = 2;
 
-    private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
-            new ArrayMap<PrinterId, PrinterInfo>();
+    private final LinkedHashMap<PrinterId, PrinterInfo> mPrinters =
+            new LinkedHashMap<PrinterId, PrinterInfo>();
 
     private final IPrintManager mPrintManager;
 
@@ -218,9 +219,7 @@
         }
 
         // Update printers we already have.
-        final int oldPrinterCount = mPrinters.size();
-        for (int i = 0; i < oldPrinterCount; i++) {
-            PrinterId oldPrinterId = mPrinters.keyAt(i);
+        for (PrinterId oldPrinterId : mPrinters.keySet()) {
             PrinterInfo updatedPrinter = addedPrintersMap.remove(oldPrinterId);
             if (updatedPrinter != null) {
                 mPrinters.put(oldPrinterId, updatedPrinter);
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index a281f7c..a95bac8 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -47,6 +47,10 @@
 
     public static final String SERVICE_NAME = "procstats";
 
+    // How often the service commits its data, giving the minimum batching
+    // that is done.
+    public static long COMMIT_PERIOD = 3*60*60*1000;  // Commit current stats every 3 hours
+
     public static final int STATE_NOTHING = -1;
     public static final int STATE_PERSISTENT = 0;
     public static final int STATE_TOP = 1;
@@ -1015,7 +1019,7 @@
                 pkgMap.removeAt(ip);
             }
         }
-        mStartTime = SystemClock.uptimeMillis();
+        mStartTime = now;
         if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
     }
 
@@ -1449,7 +1453,7 @@
                     mReadError = "bad uid: " + uid;
                     return;
                 }
-                PackageState pkgState = new PackageState(uid);
+                PackageState pkgState = new PackageState(pkgName, uid);
                 mPackages.put(pkgName, uid, pkgState);
                 int NPROCS = in.readInt();
                 if (NPROCS < 0) {
@@ -1620,7 +1624,7 @@
         if (as != null) {
             return as;
         }
-        as = new PackageState(uid);
+        as = new PackageState(packageName, uid);
         mPackages.put(packageName, uid, as);
         return as;
     }
@@ -1646,11 +1650,22 @@
                 // but it was created for a different package than the caller.
                 // We need to convert it to a multi-package process.
                 commonProc.mMultiPackage = true;
-                // The original package it was created for now needs to point
-                // to its own copy.
+                // To do this, we need to make two new process states, one a copy
+                // of the current state for the process under the original package
+                // name, and the second a free new process state for it as the
+                // new package name.
                 long now = SystemClock.uptimeMillis();
-                pkgState.mProcesses.put(commonProc.mName, commonProc.clone(
-                        commonProc.mPackage, now));
+                // First let's make a copy of the current process state and put
+                // that under the now unique state for its original package name.
+                final PackageState commonPkgState = getPackageStateLocked(commonProc.mPackage, uid);
+                if (commonPkgState != null) {
+                    commonPkgState.mProcesses.put(commonProc.mName, commonProc.clone(
+                            commonProc.mPackage, now));
+                } else {
+                    Slog.w(TAG, "Cloning proc state: no package state " + commonProc.mPackage
+                            + "/" + uid + " for proc " + commonProc.mName);
+                }
+                // And now make a fresh new process state for the new package name.
                 ps = new ProcessState(commonProc, packageName, uid, processName, now);
             }
         } else {
@@ -1677,6 +1692,32 @@
         return ss;
     }
 
+    private void dumpProcessInternalLocked(PrintWriter pw, String prefix, ProcessState proc,
+            boolean dumpAll) {
+        if (dumpAll) {
+            pw.print(prefix); pw.print("myID=");
+                    pw.print(Integer.toHexString(System.identityHashCode(proc)));
+                    pw.print(" mCommonProcess=");
+                    pw.print(Integer.toHexString(System.identityHashCode(proc.mCommonProcess)));
+                    pw.print(" mPackage="); pw.println(proc.mPackage);
+            if (proc.mMultiPackage) {
+                pw.print(prefix); pw.print("mMultiPackage="); pw.println(proc.mMultiPackage);
+            }
+            if (proc != proc.mCommonProcess) {
+                pw.print(prefix); pw.print("Common Proc: "); pw.print(proc.mCommonProcess.mName);
+                        pw.print("/"); pw.print(proc.mCommonProcess.mUid);
+                        pw.print(" pkg="); pw.println(proc.mCommonProcess.mPackage);
+            }
+        }
+        pw.print(prefix); pw.print("mActive="); pw.println(proc.mActive);
+        if (proc.mDead) {
+            pw.print(prefix); pw.print("mDead="); pw.println(proc.mDead);
+        }
+        pw.print(prefix); pw.print("mNumActiveServices="); pw.print(proc.mNumActiveServices);
+                pw.print(" mNumStartedServices=");
+                pw.println(proc.mNumStartedServices);
+    }
+
     public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
             boolean dumpAll) {
         long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
@@ -1715,10 +1756,7 @@
                                 ALL_PROC_STATES, now);
                         dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
                                 ALL_PROC_STATES);
-                        pw.print("        mActive="); pw.println(proc.mActive);
-                        pw.print("        mNumActiveServices="); pw.print(proc.mNumActiveServices);
-                                pw.print(" mNumStartedServices=");
-                                pw.println(proc.mNumStartedServices);
+                        dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
                     }
                 } else {
                     ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
@@ -1737,6 +1775,7 @@
                     pw.print(pkgState.mServices.keyAt(isvc));
                     pw.println(":");
                     ServiceState svc = pkgState.mServices.valueAt(isvc);
+                    pw.print("        Process: "); pw.println(svc.mProcessName);
                     dumpServiceStats(pw, "        ", "          ", "    ", "Running", svc,
                             svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
                             svc.mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
@@ -1759,16 +1798,19 @@
         if (reqPackage == null) {
             ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
             printedHeader = false;
+            int numShownProcs = 0, numTotalProcs = 0;
             for (int ip=0; ip<procMap.size(); ip++) {
                 String procName = procMap.keyAt(ip);
                 SparseArray<ProcessState> uids = procMap.valueAt(ip);
                 for (int iu=0; iu<uids.size(); iu++) {
                     int uid = uids.keyAt(iu);
+                    numTotalProcs++;
                     ProcessState proc = uids.valueAt(iu);
                     if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
                             && proc.mPssTableSize == 0) {
                         continue;
                     }
+                    numShownProcs++;
                     if (!printedHeader) {
                         pw.println();
                         pw.println("Per-Process Stats:");
@@ -1783,13 +1825,15 @@
                     dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
                             ALL_PROC_STATES);
                     if (dumpAll) {
-                        pw.print("        mActive="); pw.println(proc.mActive);
-                        pw.print("        mNumActiveServices="); pw.print(proc.mNumActiveServices);
-                                pw.print(" mNumStartedServices=");
-                                pw.println(proc.mNumStartedServices);
+                        dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
                     }
                 }
             }
+            if (dumpAll) {
+                pw.println();
+                pw.print("  Total procs: "); pw.print(numShownProcs);
+                        pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+            }
 
             pw.println();
             if (dumpSummary) {
@@ -1876,7 +1920,7 @@
         long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
                 mStartTime, now);
         dumpFilteredSummaryLocked(pw, null, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                NON_CACHED_PROC_STATES, now, totalTime, reqPackage);
+                ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage);
         pw.println();
         dumpTotalsLocked(pw, now);
     }
@@ -1916,22 +1960,22 @@
     }
 
     void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
-            int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime,
-            String reqPackage) {
+            int[] screenStates, int[] memStates, int[] procStates,
+            int[] sortProcStates, long now, long totalTime, String reqPackage) {
         ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
-                procStates, now, reqPackage);
+                procStates, sortProcStates, now, reqPackage);
         if (procs.size() > 0) {
             if (header != null) {
                 pw.println();
                 pw.println(header);
             }
-            dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates, procStates,
-                    now, totalTime);
+            dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates,
+                    sortProcStates, now, totalTime);
         }
     }
 
     public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
-            int[] procStates, long now, String reqPackage) {
+            int[] procStates, int sortProcStates[], long now, String reqPackage) {
         ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
         ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
         for (int ip=0; ip<pkgMap.size(); ip++) {
@@ -1953,6 +1997,9 @@
             if (computeProcessTimeLocked(proc, screenStates, memStates,
                     procStates, now) > 0) {
                 outProcs.add(proc);
+                if (procStates != sortProcStates) {
+                    computeProcessTimeLocked(proc, screenStates, memStates, sortProcStates, now);
+                }
             }
         }
         Collections.sort(outProcs, new Comparator<ProcessState>() {
@@ -2134,15 +2181,97 @@
         pw.println();
     }
 
-    public static final class ProcessState {
+    public static class DurationsTable {
         public final ProcessStats mStats;
+        public final String mName;
+        public int[] mDurationsTable;
+        public int mDurationsTableSize;
+
+        public DurationsTable(ProcessStats stats, String name) {
+            mStats = stats;
+            mName = name;
+        }
+
+        void copyDurationsTo(DurationsTable other) {
+            if (mDurationsTable != null) {
+                mStats.mAddLongTable = new int[mDurationsTable.length];
+                mStats.mAddLongTableSize = 0;
+                for (int i=0; i<mDurationsTableSize; i++) {
+                    int origEnt = mDurationsTable[i];
+                    int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+                    int newOff = mStats.addLongData(i, type, 1);
+                    mStats.mAddLongTable[i] = newOff | type;
+                    mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0));
+                }
+                other.mDurationsTable = mStats.mAddLongTable;
+                other.mDurationsTableSize = mStats.mAddLongTableSize;
+            } else {
+                other.mDurationsTable = null;
+                other.mDurationsTableSize = 0;
+            }
+        }
+
+        void addDurations(DurationsTable other) {
+            for (int i=0; i<other.mDurationsTableSize; i++) {
+                int ent = other.mDurationsTable[i];
+                int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+                if (DEBUG) Slog.d(TAG, "Adding state " + state + " duration "
+                        + other.mStats.getLong(ent, 0));
+                addDuration(state, other.mStats.getLong(ent, 0));
+            }
+        }
+
+        void resetDurationsSafely() {
+            mDurationsTable = null;
+            mDurationsTableSize = 0;
+        }
+
+        void writeDurationsToParcel(Parcel out) {
+            out.writeInt(mDurationsTableSize);
+            for (int i=0; i<mDurationsTableSize; i++) {
+                if (DEBUG) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
+                        + printLongOffset(mDurationsTable[i]));
+                out.writeInt(mDurationsTable[i]);
+            }
+        }
+
+        boolean readDurationsFromParcel(Parcel in) {
+            mDurationsTable = mStats.readTableFromParcel(in, mName, "durations");
+            if (mDurationsTable == BAD_TABLE) {
+                return false;
+            }
+            mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
+            return true;
+        }
+
+        void addDuration(int state, long dur) {
+            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
+            int off;
+            if (idx >= 0) {
+                off = mDurationsTable[idx];
+            } else {
+                mStats.mAddLongTable = mDurationsTable;
+                mStats.mAddLongTableSize = mDurationsTableSize;
+                off = mStats.addLongData(~idx, state, 1);
+                mDurationsTable = mStats.mAddLongTable;
+                mDurationsTableSize = mStats.mAddLongTableSize;
+            }
+            long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+            if (DEBUG) Slog.d(TAG, "Duration of " + mName + " state " + state + " inc by " + dur
+                    + " from " + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK]);
+            longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
+        }
+
+        long getDuration(int state, long now) {
+            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
+            return idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
+        }
+    }
+
+    public static final class ProcessState extends DurationsTable {
         public final ProcessState mCommonProcess;
         public final String mPackage;
         public final int mUid;
-        public final String mName;
-
-        int[] mDurationsTable;
-        int mDurationsTableSize;
 
         //final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT];
         int mCurState = STATE_NOTHING;
@@ -2175,11 +2304,10 @@
          * a single package running in a process.  The initial state is not running.
          */
         public ProcessState(ProcessStats processStats, String pkg, int uid, String name) {
-            mStats = processStats;
+            super(processStats, name);
             mCommonProcess = this;
             mPackage = pkg;
             mUid = uid;
-            mName = name;
         }
 
         /**
@@ -2189,30 +2317,17 @@
          */
         public ProcessState(ProcessState commonProcess, String pkg, int uid, String name,
                 long now) {
-            mStats = commonProcess.mStats;
+            super(commonProcess.mStats, name);
             mCommonProcess = commonProcess;
             mPackage = pkg;
             mUid = uid;
-            mName = name;
             mCurState = commonProcess.mCurState;
             mStartTime = now;
         }
 
         ProcessState clone(String pkg, long now) {
             ProcessState pnew = new ProcessState(this, pkg, mUid, mName, now);
-            if (mDurationsTable != null) {
-                mStats.mAddLongTable = new int[mDurationsTable.length];
-                mStats.mAddLongTableSize = 0;
-                for (int i=0; i<mDurationsTableSize; i++) {
-                    int origEnt = mDurationsTable[i];
-                    int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                    int newOff = mStats.addLongData(i, type, 1);
-                    mStats.mAddLongTable[i] = newOff | type;
-                    mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0));
-                }
-                pnew.mDurationsTable = mStats.mAddLongTable;
-                pnew.mDurationsTableSize = mStats.mAddLongTableSize;
-            }
+            copyDurationsTo(pnew);
             if (mPssTable != null) {
                 mStats.mAddLongTable = new int[mPssTable.length];
                 mStats.mAddLongTableSize = 0;
@@ -2240,13 +2355,7 @@
         }
 
         void add(ProcessState other) {
-            for (int i=0; i<other.mDurationsTableSize; i++) {
-                int ent = other.mDurationsTable[i];
-                int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                if (DEBUG) Slog.d(TAG, "Adding state " + state + " duration "
-                        + other.mStats.getLong(ent, 0));
-                addDuration(state, other.mStats.getLong(ent, 0));
-            }
+            addDurations(other);
             for (int i=0; i<other.mPssTableSize; i++) {
                 int ent = other.mPssTable[i];
                 int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
@@ -2267,8 +2376,7 @@
         }
 
         void resetSafely(long now) {
-            mDurationsTable = null;
-            mDurationsTableSize = 0;
+            resetDurationsSafely();
             mStartTime = now;
             mLastPssState = STATE_NOTHING;
             mLastPssTime = 0;
@@ -2294,12 +2402,7 @@
 
         void writeToParcel(Parcel out, long now) {
             out.writeInt(mMultiPackage ? 1 : 0);
-            out.writeInt(mDurationsTableSize);
-            for (int i=0; i<mDurationsTableSize; i++) {
-                if (DEBUG) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
-                        + printLongOffset(mDurationsTable[i]));
-                out.writeInt(mDurationsTable[i]);
-            }
+            writeDurationsToParcel(out);
             out.writeInt(mPssTableSize);
             for (int i=0; i<mPssTableSize; i++) {
                 if (DEBUG) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": "
@@ -2322,11 +2425,9 @@
                 mMultiPackage = multiPackage;
             }
             if (DEBUG) Slog.d(TAG, "Reading durations table...");
-            mDurationsTable = mStats.readTableFromParcel(in, mName, "durations");
-            if (mDurationsTable == BAD_TABLE) {
+            if (!readDurationsFromParcel(in)) {
                 return false;
             }
-            mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
             if (DEBUG) Slog.d(TAG, "Reading pss table...");
             mPssTable = mStats.readTableFromParcel(in, mName, "pss");
             if (mPssTable == BAD_TABLE) {
@@ -2411,24 +2512,6 @@
             mStartTime = now;
         }
 
-        void addDuration(int state, long dur) {
-            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
-            int off;
-            if (idx >= 0) {
-                off = mDurationsTable[idx];
-            } else {
-                mStats.mAddLongTable = mDurationsTable;
-                mStats.mAddLongTableSize = mDurationsTableSize;
-                off = mStats.addLongData(~idx, state, 1);
-                mDurationsTable = mStats.mAddLongTable;
-                mDurationsTableSize = mStats.mAddLongTableSize;
-            }
-            long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-            if (DEBUG) Slog.d(TAG, "Duration of " + mName + " state " + state + " inc by " + dur
-                    + " from " + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK]);
-            longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
-        }
-
         void incActiveServices() {
             if (mCommonProcess != this) {
                 mCommonProcess.incActiveServices();
@@ -2470,7 +2553,8 @@
             }
         }
 
-        public void addPss(long pss, long uss, boolean always) {
+        public void addPss(long pss, long uss, boolean always,
+                ArrayMap<String, ProcessState> pkgList) {
             ensureNotDead();
             if (!always) {
                 if (mLastPssState == mCurState && SystemClock.uptimeMillis()
@@ -2481,7 +2565,20 @@
             mLastPssState = mCurState;
             mLastPssTime = SystemClock.uptimeMillis();
             if (mCurState != STATE_NOTHING) {
-                addPss(mCurState, 1, pss, pss, pss, uss, uss, uss);
+                // First update the common process.
+                mCommonProcess.addPss(mCurState, 1, pss, pss, pss, uss, uss, uss);
+
+                // If the common process is not multi-package, there is nothing else to do.
+                if (!mCommonProcess.mMultiPackage) {
+                    return;
+                }
+
+                if (pkgList != null) {
+                    for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                        pullFixedProc(pkgList, ip).addPss(mCurState, 1,
+                                pss, pss, pss, uss, uss, uss);
+                    }
+                }
             }
         }
 
@@ -2632,8 +2729,7 @@
         }
 
         long getDuration(int state, long now) {
-            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
-            long time = idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
+            long time = super.getDuration(state, now);
             if (mCurState == state) {
                 time += now - mStartTime;
             }
@@ -2676,10 +2772,8 @@
         }
     }
 
-    public static final class ServiceState {
-        final ProcessStats mStats;
+    public static final class ServiceState extends DurationsTable {
         public final String mPackage;
-        public final String mName;
         public final String mProcessName;
         ProcessState mProc;
 
@@ -2691,9 +2785,6 @@
         public static final int SERVICE_EXEC = 3;
         static final int SERVICE_COUNT = 4;
 
-        int[] mDurationsTable;
-        int mDurationsTableSize;
-
         int mRunCount;
         public int mRunState = STATE_NOTHING;
         long mRunStartTime;
@@ -2712,9 +2803,8 @@
 
         public ServiceState(ProcessStats processStats, String pkg, String name,
                 String processName, ProcessState proc) {
-            mStats = processStats;
+            super(processStats, name);
             mPackage = pkg;
-            mName = name;
             mProcessName = processName;
             mProc = proc;
         }
@@ -2743,11 +2833,7 @@
         }
 
         void add(ServiceState other) {
-            for (int i=0; i<other.mDurationsTableSize; i++) {
-                int ent = other.mDurationsTable[i];
-                int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
-                addStateTime(state, other.mStats.getLong(ent, 0));
-            }
+            addDurations(other);
             mRunCount += other.mRunCount;
             mStartedCount += other.mStartedCount;
             mBoundCount += other.mBoundCount;
@@ -2755,22 +2841,16 @@
         }
 
         void resetSafely(long now) {
-            mDurationsTable = null;
-            mDurationsTableSize = 0;
+            resetDurationsSafely();
             mRunCount = mRunState != STATE_NOTHING ? 1 : 0;
             mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
             mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
             mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
-            mStartedStartTime = mBoundStartTime = mExecStartTime = now;
+            mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now;
         }
 
         void writeToParcel(Parcel out, long now) {
-            out.writeInt(mDurationsTableSize);
-            for (int i=0; i<mDurationsTableSize; i++) {
-                if (DEBUG) Slog.i(TAG, "Writing service in " + mPackage + " dur #" + i + ": "
-                        + printLongOffset(mDurationsTable[i]));
-                out.writeInt(mDurationsTable[i]);
-            }
+            writeDurationsToParcel(out);
             out.writeInt(mRunCount);
             out.writeInt(mStartedCount);
             out.writeInt(mBoundCount);
@@ -2778,12 +2858,9 @@
         }
 
         boolean readFromParcel(Parcel in) {
-            if (DEBUG) Slog.d(TAG, "Reading durations table...");
-            mDurationsTable = mStats.readTableFromParcel(in, mPackage, "service");
-            if (mDurationsTable == BAD_TABLE) {
+            if (!readDurationsFromParcel(in)) {
                 return false;
             }
-            mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
             mRunCount = in.readInt();
             mStartedCount = in.readInt();
             mBoundCount = in.readInt();
@@ -2791,40 +2868,22 @@
             return true;
         }
 
-        void addStateTime(int state, long time) {
-            if (time > 0) {
-                int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
-                int off;
-                if (idx >= 0) {
-                    off = mDurationsTable[idx];
-                } else {
-                    mStats.mAddLongTable = mDurationsTable;
-                    mStats.mAddLongTableSize = mDurationsTableSize;
-                    off = mStats.addLongData(~idx, state, 1);
-                    mDurationsTable = mStats.mAddLongTable;
-                    mDurationsTableSize = mStats.mAddLongTableSize;
-                }
-                long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
-                longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += time;
-            }
-        }
-
         void commitStateTime(long now) {
             if (mRunState != STATE_NOTHING) {
-                addStateTime(SERVICE_RUN + (mRunState*SERVICE_COUNT), now - mRunStartTime);
+                addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), now - mRunStartTime);
                 mRunStartTime = now;
             }
             if (mStartedState != STATE_NOTHING) {
-                addStateTime(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+                addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
                         now - mStartedStartTime);
                 mStartedStartTime = now;
             }
             if (mBoundState != STATE_NOTHING) {
-                addStateTime(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), now - mBoundStartTime);
+                addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), now - mBoundStartTime);
                 mBoundStartTime = now;
             }
             if (mExecState != STATE_NOTHING) {
-                addStateTime(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
+                addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
                 mExecStartTime = now;
             }
         }
@@ -2834,7 +2893,7 @@
                     || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
             if (mRunState != state) {
                 if (mRunState != STATE_NOTHING) {
-                    addStateTime(SERVICE_RUN + (mRunState*SERVICE_COUNT),
+                    addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
                             now - mRunStartTime);
                 } else if (state != STATE_NOTHING) {
                     mRunCount++;
@@ -2852,7 +2911,7 @@
             final int state = started ? memFactor : STATE_NOTHING;
             if (mStartedState != state) {
                 if (mStartedState != STATE_NOTHING) {
-                    addStateTime(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+                    addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
                             now - mStartedStartTime);
                 } else if (started) {
                     mStartedCount++;
@@ -2878,7 +2937,7 @@
             final int state = bound ? memFactor : STATE_NOTHING;
             if (mBoundState != state) {
                 if (mBoundState != STATE_NOTHING) {
-                    addStateTime(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
+                    addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
                             now - mBoundStartTime);
                 } else if (bound) {
                     mBoundCount++;
@@ -2896,7 +2955,7 @@
             final int state = executing ? memFactor : STATE_NOTHING;
             if (mExecState != state) {
                 if (mExecState != STATE_NOTHING) {
-                    addStateTime(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
+                    addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
                 } else if (executing) {
                     mExecCount++;
                 }
@@ -2909,8 +2968,7 @@
         private long getDuration(int opType, int curState, long startTime, int memFactor,
                 long now) {
             int state = opType + (memFactor*SERVICE_COUNT);
-            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
-            long time = idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
+            long time = getDuration(state, now);
             if (curState == memFactor) {
                 time += now - startTime;
             }
@@ -2923,10 +2981,12 @@
                 = new ArrayMap<String, ProcessState>();
         public final ArrayMap<String, ServiceState> mServices
                 = new ArrayMap<String, ServiceState>();
-        final int mUid;
+        public final String mPackageName;
+        public final int mUid;
 
-        public PackageState(int uid) {
+        public PackageState(String packageName, int uid) {
             mUid = uid;
+            mPackageName = packageName;
         }
     }
 
@@ -2951,6 +3011,9 @@
         }
 
         void print(PrintWriter pw, long overallTime, boolean full) {
+            if (totalTime > overallTime) {
+                pw.print("*");
+            }
             printPercent(pw, (double) totalTime / (double) overallTime);
             if (numPss > 0) {
                 pw.print(" (");
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 15792e8..62f057f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -156,31 +156,32 @@
  * Uses libmemtrack to retrieve graphics memory that the process is using.
  * Any graphics memory reported in /proc/pid/smaps is not included here.
  */
-static int read_memtrack_memory(struct memtrack_proc* p, int pid, struct graphics_memory_pss* graphics_mem)
+static int read_memtrack_memory(struct memtrack_proc* p, int pid,
+        struct graphics_memory_pss* graphics_mem)
 {
     int err = memtrack_proc_get(p, pid);
     if (err != 0) {
-        ALOGE("failed to get memory consumption info: %d", err);
+        ALOGW("failed to get memory consumption info: %d", err);
         return err;
     }
 
     ssize_t pss = memtrack_proc_graphics_pss(p);
     if (pss < 0) {
-        ALOGE("failed to get graphics pss: %d", pss);
+        ALOGW("failed to get graphics pss: %d", pss);
         return pss;
     }
     graphics_mem->graphics = pss / 1024;
 
     pss = memtrack_proc_gl_pss(p);
     if (pss < 0) {
-        ALOGE("failed to get gl pss: %d", pss);
+        ALOGW("failed to get gl pss: %d", pss);
         return pss;
     }
     graphics_mem->gl = pss / 1024;
 
     pss = memtrack_proc_other_pss(p);
     if (pss < 0) {
-        ALOGE("failed to get other pss: %d", pss);
+        ALOGW("failed to get other pss: %d", pss);
         return pss;
     }
     graphics_mem->other = pss / 1024;
@@ -199,7 +200,7 @@
 
     struct memtrack_proc* p = memtrack_proc_new();
     if (p == NULL) {
-        ALOGE("failed to create memtrack_proc");
+        ALOGW("failed to create memtrack_proc");
         return -1;
     }
 
@@ -418,8 +419,6 @@
         stats[HEAP_GL].privateDirty = graphics_mem.gl;
         stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
         stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
-    } else {
-        ALOGE("Failed to read gpu memory");
     }
 
     for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
@@ -623,7 +622,7 @@
         close(fd);
         if (len > 0) {
             buffer[len] = 0;
-            mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer);
+            mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer)/1024;
         }
     }
 
@@ -633,7 +632,7 @@
     }
     jlong* outArray = env->GetLongArrayElements(out, 0);
     if (outArray != NULL) {
-        for (int i=0; i<maxNum && tags[i]; i++) {
+        for (int i=0; i<maxNum; i++) {
             outArray[i] = mem[i];
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 49777d4..932fe20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -123,7 +123,7 @@
 
     protected int mCurrentUserId = 0;
 
-    protected int mLayoutDirection;
+    protected int mLayoutDirection = -1; // invalid
     private Locale mLocale;
     protected boolean mUseHeadsUp = false;
 
@@ -299,8 +299,6 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
-
-        mLocale = mContext.getResources().getConfiguration().locale;
     }
 
     public void userSwitched(int newUserId) {
@@ -320,11 +318,17 @@
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
-        final Locale newLocale = mContext.getResources().getConfiguration().locale;
-        if (! newLocale.equals(mLocale)) {
-            mLocale = newLocale;
-            mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
-            refreshLayout(mLayoutDirection);
+        final Locale locale = mContext.getResources().getConfiguration().locale;
+        final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
+        if (! locale.equals(mLocale) || ld != mLayoutDirection) {
+            if (DEBUG) {
+                Log.v(TAG, String.format(
+                        "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
+                        locale, ld));
+            }
+            mLocale = locale;
+            mLayoutDirection = ld;
+            refreshLayout(ld);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
index ecf7b35..16fe1aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar;
 
+import android.content.res.Configuration;
 import android.provider.Settings;
 import android.util.Log;
 
@@ -70,6 +71,13 @@
     }
 
     @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        if (mStatusBar != null) {
+            mStatusBar.onConfigurationChanged(newConfig);
+        }
+    }
+
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mStatusBar != null) {
             mStatusBar.dump(fd, pw, args);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index fbc94b1..c47d0eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -38,6 +38,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Canvas;
@@ -633,7 +634,6 @@
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(Intent.ACTION_SCREEN_ON);
@@ -2433,17 +2433,6 @@
                 notifyNavigationBarScreenOn(false);
                 notifyHeadsUpScreenOn(false);
             }
-            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                if (DEBUG) {
-                    Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
-                }
-                mDisplay.getSize(mCurrentDisplaySize);
-
-                updateResources();
-                repositionNavigationBar();
-                updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-                updateShowSearchHoldoff();
-            }
             else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                 mScreenOn = true;
                 // work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018)
@@ -2466,6 +2455,22 @@
         }
     };
 
+    // SystemUIService notifies SystemBars of configuration changes, which then calls down here
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig); // calls refreshLayout
+
+        if (DEBUG) {
+            Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
+        }
+        mDisplay.getSize(mCurrentDisplaySize);
+
+        updateResources();
+        repositionNavigationBar();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        updateShowSearchHoldoff();
+    }
+
     @Override
     public void userSwitched(int newUserId) {
         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a14d729..ddb6d1a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1689,7 +1689,7 @@
                                     && proc.pid == pid) {
                                 num++;
                                 proc.lastPssTime = SystemClock.uptimeMillis();
-                                proc.baseProcessTracker.addPss(pss, tmp[0], true);
+                                proc.baseProcessTracker.addPss(pss, tmp[0], true, proc.pkgList);
                                 if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
                                         + ": " + pss + " lastPss=" + proc.lastPss
                                         + " state=" + ProcessList.makeProcStateString(procState));
@@ -2705,18 +2705,6 @@
         return intent;
     }
 
-    String getHomePackageName() {
-        Intent intent = getHomeIntent();
-        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, mCurrentUserId);
-        if (aInfo != null) {
-            final String homePackageName = aInfo.applicationInfo.packageName;
-            if (!ResolverActivity.class.getName().equals(homePackageName)) {
-                return homePackageName;
-            }
-        }
-        return null;
-    }
-
     boolean startHomeActivityLocked(int userId) {
         if (mHeadless) {
             // Added because none of the other calls to ensureBootCompleted seem to fire
@@ -4278,7 +4266,7 @@
                     if (proc.thread != null && proc.setAdj == oomAdj) {
                         // Record this for posterity if the process has been stable.
                         proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
-                                infos[i].getTotalUss(), false);
+                                infos[i].getTotalUss(), false, proc.pkgList);
                     }
                 }
             }
@@ -4305,7 +4293,7 @@
                 synchronized (this) {
                     if (proc.thread != null && proc.setAdj == oomAdj) {
                         // Record this for posterity if the process has been stable.
-                        proc.baseProcessTracker.addPss(pss[i], tmpUss[0], false);
+                        proc.baseProcessTracker.addPss(pss[i], tmpUss[0], false, proc.pkgList);
                     }
                 }
             }
@@ -6786,6 +6774,10 @@
             // Kill the running processes.
             for (int i=0; i<procs.size(); i++) {
                 ProcessRecord pr = procs.get(i);
+                if (pr == mHomeProcess) {
+                    // Don't kill the home process along with tasks from the same package.
+                    continue;
+                }
                 if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
                     killUnneededProcessLocked(pr, "remove task");
                 } else {
@@ -11748,7 +11740,7 @@
                 synchronized (this) {
                     if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
                         // Record this for posterity if the process has been stable.
-                        r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true);
+                        r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true, r.pkgList);
                     }
                 }
 
@@ -11909,7 +11901,7 @@
                 if (memInfo.getZramTotalSizeKb() != 0) {
                     if (!isCompact) {
                         pw.print("     ZRAM: "); pw.print(memInfo.getZramTotalSizeKb());
-                                pw.print(" kB used for ");
+                                pw.print(" kB physical used for ");
                                 pw.print(memInfo.getSwapTotalSizeKb()
                                         - memInfo.getSwapFreeSizeKb());
                                 pw.print(" kB in swap (");
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 4359895..2c0b83b 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -58,6 +58,7 @@
 final class ActivityRecord {
     static final String TAG = ActivityManagerService.TAG;
     static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
+    final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent";
 
     final ActivityManagerService service; // owner
     final IApplicationToken.Stub appToken; // window manager token
@@ -443,25 +444,18 @@
             noDisplay = ent != null && ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowNoDisplay, false);
 
-            // If we know the system has determined the component, then
-            // we can consider this to be a home activity...
-            String homePackageName = supervisor.getHomePackageName();
-            if (homePackageName != null && homePackageName.equals(packageName)) {
-                mActivityType = HOME_ACTIVITY_TYPE;
-            } else if ((!_componentSpecified || _launchedFromUid == Process.myUid()
+            if ((!_componentSpecified || _launchedFromUid == Process.myUid()
                     || _launchedFromUid == 0) &&
                     Intent.ACTION_MAIN.equals(_intent.getAction()) &&
                     _intent.hasCategory(Intent.CATEGORY_HOME) &&
                     _intent.getCategories().size() == 1 &&
                     _intent.getData() == null &&
                     _intent.getType() == null &&
-                    (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+                    (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
+                    isNotResolverActivity()) {
                 // This sure looks like a home activity!
                 mActivityType = HOME_ACTIVITY_TYPE;
-                if (isNotResolverActivity()) {
-                    supervisor.setHomePackageName(userId, packageName);
-                }
-            } else if (realActivity.getClassName().contains("com.android.systemui.recent")) {
+            } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
                 mActivityType = RECENTS_ACTIVITY_TYPE;
             } else {
                 mActivityType = APPLICATION_ACTIVITY_TYPE;
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index bf91904..f718706 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -203,12 +203,6 @@
      */
     final PowerManager.WakeLock mGoingToSleep;
 
-    /**
-     * The name of the current home activity for each user.
-     * TODO: Remove entries when user is deleted.
-     */
-    final SparseArray<String> mHomePackageNames = new SparseArray<String>();
-
     public ActivityStackSupervisor(ActivityManagerService service, Context context,
             Looper looper) {
         mService = service;
@@ -2285,11 +2279,6 @@
     boolean switchUserLocked(int userId, UserStartedState uss) {
         mCurrentUser = userId;
 
-        final String homePackageName = mService.getHomePackageName();
-        if (homePackageName != null) {
-            setHomePackageName(mCurrentUser, homePackageName);
-        }
-
         mStartingUsers.add(uss);
         boolean haveActivities = false;
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -2391,12 +2380,6 @@
         pw.print(prefix); pw.print("mStackState="); pw.println(stackStateToString(mStackState));
         pw.print(prefix); pw.println("mSleepTimeout: " + mSleepTimeout);
         pw.print(prefix); pw.println("mCurTaskId: " + mCurTaskId);
-        pw.print(prefix); pw.print("mHomePackageNames:");
-                for (int i = 0; i < mHomePackageNames.size(); ++i) {
-                    pw.print(" ("); pw.print(mHomePackageNames.keyAt(i)); pw.print(",");
-                    pw.print(mHomePackageNames.valueAt(i)); pw.print(")");
-                }
-                pw.println();
     }
 
     ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
@@ -2653,14 +2636,4 @@
             }
         }
     }
-
-    String getHomePackageName() {
-        return mHomePackageNames.get(mCurrentUser);
-    }
-
-    void setHomePackageName(int userId, String homePackageName) {
-        if (DEBUG_SWITCH) Slog.d(TAG, "setHomePackageName: user=" + userId + " package="
-                + homePackageName);
-        mHomePackageNames.put(userId, homePackageName);
-    }
 }
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index be08973..2c49bb9 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -61,7 +61,6 @@
     static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames.
     static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in.
     static long WRITE_PERIOD = 30*60*1000;      // Write file every 30 minutes or so.
-    static long COMMIT_PERIOD = 3*60*60*1000;  // Commit current stats every 3 hours.
 
     final ActivityManagerService mAm;
     final File mBaseDir;
@@ -160,7 +159,7 @@
     public boolean shouldWriteNowLocked(long now) {
         if (now > (mLastWriteTime+WRITE_PERIOD)) {
             if (SystemClock.elapsedRealtime()
-                    > (mProcessStats.mTimePeriodStartRealtime+COMMIT_PERIOD)) {
+                    > (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD)) {
                 mCommitPending = true;
             }
             return true;
@@ -358,7 +357,7 @@
             boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
             boolean sepProcStates, int[] procStates, long now, String reqPackage) {
         ArrayList<ProcessStats.ProcessState> procs = mProcessStats.collectProcessesLocked(
-                screenStates, memStates, procStates, now, reqPackage);
+                screenStates, memStates, procStates, procStates, now, reqPackage);
         if (procs.size() > 0) {
             if (header != null) {
                 pw.println(header);
@@ -457,7 +456,7 @@
             if (curTime < minTime) {
                 // Need to add in older stats to reach desired time.
                 ArrayList<String> files = getCommittedFiles(0, false, true);
-                if (files.size() > 0) {
+                if (files != null && files.size() > 0) {
                     current.setDataPosition(0);
                     ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
                     current.recycle();
@@ -520,7 +519,7 @@
     static private void dumpHelp(PrintWriter pw) {
         pw.println("Process stats (procstats) dump options:");
         pw.println("    [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
-        pw.println("    [--details] [--full-details] [--current] [--one-day]");
+        pw.println("    [--details] [--full-details] [--current] [--hours]");
         pw.println("    [--commit] [--reset] [--clear] [--write] [-h] [<package.name>]");
         pw.println("  --checkin: perform a checkin: print and delete old committed states.");
         pw.println("  --c: print only state in checkin format.");
@@ -532,7 +531,7 @@
         pw.println("  --details: dump all execution details, not just summary.");
         pw.println("  --full-details: dump only detail information, for all saved state.");
         pw.println("  --current: only dump current state.");
-        pw.println("  --one-day: dump stats aggregated across about one day.");
+        pw.println("  --hours: aggregate over about N last hours.");
         pw.println("  --commit: commit current stats to disk and reset to start new stats.");
         pw.println("  --reset: reset current stats, without committing.");
         pw.println("  --clear: clear all stats; does both --reset and deletes old stats.");
@@ -562,7 +561,7 @@
         boolean dumpDetails = false;
         boolean dumpFullDetails = false;
         boolean dumpAll = false;
-        boolean oneDay = false;
+        int aggregateHours = 0;
         String reqPackage = null;
         boolean csvSepScreenStats = false;
         int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON};
@@ -632,8 +631,20 @@
                     dumpDetails = true;
                 } else if ("--full-details".equals(arg)) {
                     dumpFullDetails = true;
-                } else if ("--one-day".equals(arg)) {
-                    oneDay = true;
+                } else if ("--hours".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("Error: argument required for --hours");
+                        dumpHelp(pw);
+                        return;
+                    }
+                    try {
+                        aggregateHours = Integer.parseInt(args[i]);
+                    } catch (NumberFormatException e) {
+                        pw.println("Error: --hours argument not an int -- " + args[i]);
+                        dumpHelp(pw);
+                        return;
+                    }
                 } else if ("--current".equals(arg)) {
                     currentOnly = true;
                 } else if ("--commit".equals(arg)) {
@@ -750,8 +761,9 @@
                 */
             }
             return;
-        } else if (oneDay) {
-            ParcelFileDescriptor pfd = getStatsOverTime(24*60*60*1000);
+        } else if (aggregateHours != 0) {
+            ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
+                    - (ProcessStats.COMMIT_PERIOD/2));
             if (pfd == null) {
                 pw.println("Unable to build stats!");
                 return;
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 8a9324c..385253e 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -428,6 +428,7 @@
             pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
                     pw.print(" rootWasReset="); pw.print(rootWasReset);
                     pw.print(" userId="); pw.print(userId);
+                    pw.print(" mTaskType="); pw.print(mTaskType);
                     pw.print(" numFullscreen="); pw.print(numFullscreen);
                     pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
         }
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index beeb899..2798104 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -162,6 +162,7 @@
     void moveStack(TaskStack stack, boolean toTop) {
         mStackHistory.remove(stack);
         mStackHistory.add(toTop ? mStackHistory.size() : 0, stack);
+        mService.moveStackWindowsLocked(stack);
     }
 
     public boolean isPrivate() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 680b44e..80c50cc 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4715,7 +4715,7 @@
         }
     }
 
-    private void moveStackWindowsLocked(TaskStack stack) {
+    void moveStackWindowsLocked(TaskStack stack) {
         DisplayContent displayContent = stack.getDisplayContent();
 
         // First remove all of the windows from the list.
@@ -4782,7 +4782,6 @@
                 }
                 stack.moveTaskToTop(task);
                 displayContent.moveStack(stack, true);
-                moveStackWindowsLocked(stack);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);