Merge "AudioService: implement TV system volume" into lmp-dev
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c0ac023..fed68f9 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -46,8 +46,8 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-
 import android.util.SparseIntArray;
+
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
@@ -222,7 +222,11 @@
 
 public final class ActivityManagerService extends ActivityManagerNative
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
+
     private static final String USER_DATA_DIR = "/data/user/";
+    // File that stores last updated system version and called preboot receivers
+    static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat";
+
     static final String TAG = "ActivityManager";
     static final String TAG_MU = "ActivityManagerServiceMU";
     static final boolean DEBUG = false;
@@ -354,6 +358,8 @@
     static final int ALLOW_NON_FULL_IN_PROFILE = 1;
     static final int ALLOW_FULL_ONLY = 2;
 
+    static final int LAST_PREBOOT_DELIVERED_FILE_VERSION = 10000;
+
     /** All system services */
     SystemServiceManager mSystemServiceManager;
 
@@ -9947,12 +9953,10 @@
     private static File getCalledPreBootReceiversFile() {
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
-        File fname = new File(systemDir, "called_pre_boots.dat");
+        File fname = new File(systemDir, CALLED_PRE_BOOTS_FILENAME);
         return fname;
     }
 
-    static final int LAST_DONE_VERSION = 10000;
-
     private static ArrayList<ComponentName> readLastDonePreBootReceivers() {
         ArrayList<ComponentName> lastDoneReceivers = new ArrayList<ComponentName>();
         File file = getCalledPreBootReceiversFile();
@@ -9961,7 +9965,7 @@
             fis = new FileInputStream(file);
             DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 2048));
             int fvers = dis.readInt();
-            if (fvers == LAST_DONE_VERSION) {
+            if (fvers == LAST_PREBOOT_DELIVERED_FILE_VERSION) {
                 String vers = dis.readUTF();
                 String codename = dis.readUTF();
                 String build = dis.readUTF();
@@ -9990,16 +9994,15 @@
         }
         return lastDoneReceivers;
     }
-    
+
     private static void writeLastDonePreBootReceivers(ArrayList<ComponentName> list) {
         File file = getCalledPreBootReceiversFile();
         FileOutputStream fos = null;
         DataOutputStream dos = null;
         try {
-            Slog.i(TAG, "Writing new set of last done pre-boot receivers...");
             fos = new FileOutputStream(file);
             dos = new DataOutputStream(new BufferedOutputStream(fos, 2048));
-            dos.writeInt(LAST_DONE_VERSION);
+            dos.writeInt(LAST_PREBOOT_DELIVERED_FILE_VERSION);
             dos.writeUTF(android.os.Build.VERSION.RELEASE);
             dos.writeUTF(android.os.Build.VERSION.CODENAME);
             dos.writeUTF(android.os.Build.VERSION.INCREMENTAL);
@@ -10023,11 +10026,92 @@
             }
         }
     }
-    
+
+    private boolean deliverPreBootCompleted(final Runnable onFinishCallback,
+            ArrayList<ComponentName> doneReceivers, int userId) {
+        boolean waitingUpdate = false;
+        Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
+        List<ResolveInfo> ris = null;
+        try {
+            ris = AppGlobals.getPackageManager().queryIntentReceivers(
+                    intent, null, 0, userId);
+        } catch (RemoteException e) {
+        }
+        if (ris != null) {
+            for (int i=ris.size()-1; i>=0; i--) {
+                if ((ris.get(i).activityInfo.applicationInfo.flags
+                        &ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    ris.remove(i);
+                }
+            }
+            intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+
+            // For User 0, load the version number. When delivering to a new user, deliver
+            // to all receivers.
+            if (userId == UserHandle.USER_OWNER) {
+                ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
+                for (int i=0; i<ris.size(); i++) {
+                    ActivityInfo ai = ris.get(i).activityInfo;
+                    ComponentName comp = new ComponentName(ai.packageName, ai.name);
+                    if (lastDoneReceivers.contains(comp)) {
+                        // We already did the pre boot receiver for this app with the current
+                        // platform version, so don't do it again...
+                        ris.remove(i);
+                        i--;
+                        // ...however, do keep it as one that has been done, so we don't
+                        // forget about it when rewriting the file of last done receivers.
+                        doneReceivers.add(comp);
+                    }
+                }
+            }
+
+            // If primary user, send broadcast to all available users, else just to userId
+            final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked()
+                    : new int[] { userId };
+            for (int i = 0; i < ris.size(); i++) {
+                ActivityInfo ai = ris.get(i).activityInfo;
+                ComponentName comp = new ComponentName(ai.packageName, ai.name);
+                doneReceivers.add(comp);
+                intent.setComponent(comp);
+                for (int j=0; j<users.length; j++) {
+                    IIntentReceiver finisher = null;
+                    // On last receiver and user, set up a completion callback
+                    if (i == ris.size() - 1 && j == users.length - 1 && onFinishCallback != null) {
+                        finisher = new IIntentReceiver.Stub() {
+                            public void performReceive(Intent intent, int resultCode,
+                                    String data, Bundle extras, boolean ordered,
+                                    boolean sticky, int sendingUser) {
+                                // The raw IIntentReceiver interface is called
+                                // with the AM lock held, so redispatch to
+                                // execute our code without the lock.
+                                mHandler.post(onFinishCallback);
+                            }
+                        };
+                    }
+                    Slog.i(TAG, "Sending system update to " + intent.getComponent()
+                            + " for user " + users[j]);
+                    broadcastIntentLocked(null, null, intent, null, finisher,
+                            0, null, null, null, AppOpsManager.OP_NONE,
+                            true, false, MY_PID, Process.SYSTEM_UID,
+                            users[j]);
+                    if (finisher != null) {
+                        waitingUpdate = true;
+                    }
+                }
+            }
+        }
+
+        return waitingUpdate;
+    }
+
     public void systemReady(final Runnable goingCallback) {
         synchronized(this) {
             if (mSystemReady) {
-                if (goingCallback != null) goingCallback.run();
+                // If we're done calling all the receivers, run the next "boot phase" passed in
+                // by the SystemServer
+                if (goingCallback != null) {
+                    goingCallback.run();
+                }
                 return;
             }
 
@@ -10048,82 +10132,20 @@
                 if (mWaitingUpdate) {
                     return;
                 }
-                Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
-                List<ResolveInfo> ris = null;
-                try {
-                    ris = AppGlobals.getPackageManager().queryIntentReceivers(
-                            intent, null, 0, 0);
-                } catch (RemoteException e) {
-                }
-                if (ris != null) {
-                    for (int i=ris.size()-1; i>=0; i--) {
-                        if ((ris.get(i).activityInfo.applicationInfo.flags
-                                &ApplicationInfo.FLAG_SYSTEM) == 0) {
-                            ris.remove(i);
+                final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
+                mWaitingUpdate = deliverPreBootCompleted(new Runnable() {
+                    public void run() {
+                        synchronized (ActivityManagerService.this) {
+                            mDidUpdate = true;
                         }
+                        writeLastDonePreBootReceivers(doneReceivers);
+                        showBootMessage(mContext.getText(
+                                R.string.android_upgrading_complete),
+                                false);
+                        systemReady(goingCallback);
                     }
-                    intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+                }, doneReceivers, UserHandle.USER_OWNER);
 
-                    ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
-
-                    final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
-                    for (int i=0; i<ris.size(); i++) {
-                        ActivityInfo ai = ris.get(i).activityInfo;
-                        ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                        if (lastDoneReceivers.contains(comp)) {
-                            // We already did the pre boot receiver for this app with the current
-                            // platform version, so don't do it again...
-                            ris.remove(i);
-                            i--;
-                            // ...however, do keep it as one that has been done, so we don't
-                            // forget about it when rewriting the file of last done receivers.
-                            doneReceivers.add(comp);
-                        }
-                    }
-
-                    final int[] users = getUsersLocked();
-                    for (int i=0; i<ris.size(); i++) {
-                        ActivityInfo ai = ris.get(i).activityInfo;
-                        ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                        doneReceivers.add(comp);
-                        intent.setComponent(comp);
-                        for (int j=0; j<users.length; j++) {
-                            IIntentReceiver finisher = null;
-                            if (i == ris.size()-1 && j == users.length-1) {
-                                finisher = new IIntentReceiver.Stub() {
-                                    public void performReceive(Intent intent, int resultCode,
-                                            String data, Bundle extras, boolean ordered,
-                                            boolean sticky, int sendingUser) {
-                                        // The raw IIntentReceiver interface is called
-                                        // with the AM lock held, so redispatch to
-                                        // execute our code without the lock.
-                                        mHandler.post(new Runnable() {
-                                            public void run() {
-                                                synchronized (ActivityManagerService.this) {
-                                                    mDidUpdate = true;
-                                                }
-                                                writeLastDonePreBootReceivers(doneReceivers);
-                                                showBootMessage(mContext.getText(
-                                                        R.string.android_upgrading_complete),
-                                                        false);
-                                                systemReady(goingCallback);
-                                            }
-                                        });
-                                    }
-                                };
-                            }
-                            Slog.i(TAG, "Sending system update to " + intent.getComponent()
-                                    + " for user " + users[j]);
-                            broadcastIntentLocked(null, null, intent, null, finisher,
-                                    0, null, null, null, AppOpsManager.OP_NONE,
-                                    true, false, MY_PID, Process.SYSTEM_UID,
-                                    users[j]);
-                            if (finisher != null) {
-                                mWaitingUpdate = true;
-                            }
-                        }
-                    }
-                }
                 if (mWaitingUpdate) {
                     return;
                 }
@@ -17156,6 +17178,7 @@
                 }
 
                 if (needStart) {
+                    // Send USER_STARTED broadcast
                     Intent intent = new Intent(Intent.ACTION_USER_STARTED);
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                             | Intent.FLAG_RECEIVER_FOREGROUND);
@@ -17167,6 +17190,11 @@
 
                 if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
                     if (userId != UserHandle.USER_OWNER) {
+                        // Send PRE_BOOT_COMPLETED broadcasts for this new user
+                        final ArrayList<ComponentName> doneReceivers
+                                = new ArrayList<ComponentName>();
+                        deliverPreBootCompleted(null, doneReceivers, userId);
+
                         Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
                         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                         broadcastIntentLocked(null, null, intent, null,
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
index 397ef13..051ed0e 100644
--- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
@@ -34,8 +34,10 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * This test is intended to measure the amount of memory applications use when
@@ -57,11 +59,12 @@
 
     private static final String TAG = "MemoryUsageInstrumentation";
     private static final String KEY_APPS = "apps";
-
+    private static final String KEY_PROCS = "persistent";
+    private static final String LAUNCHER_KEY = "launcher";
     private Map<String, Intent> mNameToIntent;
     private Map<String, String> mNameToProcess;
     private Map<String, String> mNameToResultKey;
-
+    private Set<String> mPersistentProcesses;
     private IActivityManager mAm;
 
     public void testMemory() {
@@ -75,35 +78,61 @@
 
         Bundle results = new Bundle();
         for (String app : mNameToResultKey.keySet()) {
-            String processName;
-            try {
-                processName = startApp(app);
-                measureMemory(app, processName, results);
-                closeApp();
-            } catch (NameNotFoundException e) {
-                Log.i(TAG, "Application " + app + " not found");
+            if (!mPersistentProcesses.contains(app)) {
+                String processName;
+                try {
+                    processName = startApp(app);
+                    measureMemory(app, processName, results);
+                    closeApp();
+                } catch (NameNotFoundException e) {
+                    Log.i(TAG, "Application " + app + " not found");
+                }
+            } else {
+                measureMemory(app, app, results);
             }
-
         }
         instrumentation.sendStatus(0, results);
     }
 
-    private void parseArgs(Bundle args) {
-        mNameToResultKey = new HashMap<String, String>();
-        String appList = args.getString(KEY_APPS);
+    private String getLauncherPackageName() {
+      Intent intent = new Intent(Intent.ACTION_MAIN);
+      intent.addCategory(Intent.CATEGORY_HOME);
+      ResolveInfo resolveInfo = getInstrumentation().getContext().
+          getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+      return resolveInfo.activityInfo.packageName;
+    }
 
-        if (appList == null)
-            return;
-
-        String appNames[] = appList.split("\\|");
-        for (String pair : appNames) {
+    private Map<String, String> parseListToMap(String list) {
+        Map<String, String> map = new HashMap<String, String>();
+        String names[] = list.split("\\|");
+        for (String pair : names) {
             String[] parts = pair.split("\\^");
             if (parts.length != 2) {
                 Log.e(TAG, "The apps key is incorectly formatted");
                 fail();
             }
+            map.put(parts[0], parts[1]);
+        }
+        return map;
+    }
 
-            mNameToResultKey.put(parts[0], parts[1]);
+    private void parseArgs(Bundle args) {
+        mNameToResultKey = new HashMap<String, String>();
+        mPersistentProcesses = new HashSet<String>();
+        String appList = args.getString(KEY_APPS);
+        String procList = args.getString(KEY_PROCS);
+        String mLauncherPackageName = getLauncherPackageName();
+        mPersistentProcesses.add(mLauncherPackageName);
+        mNameToResultKey.put(mLauncherPackageName, LAUNCHER_KEY);
+        if (appList == null && procList == null)
+            return;
+        if (appList != null) {
+            mNameToResultKey.putAll(parseListToMap(appList));
+        }
+        if (procList != null) {
+            Map<String, String> procMap = parseListToMap(procList);
+            mPersistentProcesses.addAll(procMap.keySet());
+            mNameToResultKey.putAll(procMap);
         }
     }