am 11d1caed: am e3ddd117: am 3cc05c9d: Merge "BatteryStats: Fix coalescing of shared app GIDs and system UIDs" into mnc-dev

* commit '11d1caede255fe9643692974031fb93448adbd97':
  BatteryStats: Fix coalescing of shared app GIDs and system UIDs
diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java
index edab729..fbde228 100644
--- a/src/com/android/settings/fuelgauge/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/BatteryEntry.java
@@ -24,7 +24,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.graphics.drawable.Drawable;
-import android.os.BatteryStats;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -191,7 +190,7 @@
             icon = context.getDrawable(iconId);
         }
         if ((name == null || iconId == 0) && this.sipper.uidObj != null) {
-            getQuickNameIconForUid(this.sipper.uidObj);
+            getQuickNameIconForUid(this.sipper.uidObj.getUid());
         }
     }
 
@@ -206,8 +205,7 @@
         return name;
     }
 
-    void getQuickNameIconForUid(BatteryStats.Uid uidObj) {
-        final int uid = uidObj.getUid();
+    void getQuickNameIconForUid(final int uid) {
         final String uidString = Integer.toString(uid);
         if (sUidCache.containsKey(uidString)) {
             UidToDetail utd = sUidCache.get(uidString);
@@ -217,10 +215,8 @@
             return;
         }
         PackageManager pm = context.getPackageManager();
-        String[] packages = pm.getPackagesForUid(uid);
         icon = pm.getDefaultActivityIcon();
-        if (packages == null) {
-            //name = Integer.toString(uid);
+        if (pm.getPackagesForUid(uid) == null) {
             if (uid == 0) {
                 name = context.getResources().getString(R.string.process_kernel_label);
             } else if ("mediaserver".equals(name)) {
@@ -230,10 +226,8 @@
             }
             iconId = R.drawable.ic_power_system;
             icon = context.getDrawable(iconId);
-            return;
-        } else {
-            //name = packages[0];
         }
+
         if (sHandler != null) {
             synchronized (mRequestQueue) {
                 mRequestQueue.add(this);
@@ -249,79 +243,82 @@
         if (sipper.uidObj == null) {
             return;
         }
+
         PackageManager pm = context.getPackageManager();
         final int uid = sipper.uidObj.getUid();
-        final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
         sipper.mPackages = pm.getPackagesForUid(uid);
-        if (sipper.mPackages == null) {
-            name = Integer.toString(uid);
-            return;
-        }
+        if (sipper.mPackages != null) {
+            String[] packageLabels = new String[sipper.mPackages.length];
+            System.arraycopy(sipper.mPackages, 0, packageLabels, 0, sipper.mPackages.length);
 
-        String[] packageLabels = new String[sipper.mPackages.length];
-        System.arraycopy(sipper.mPackages, 0, packageLabels, 0, sipper.mPackages.length);
-
-        // Convert package names to user-facing labels where possible
-        IPackageManager ipm = AppGlobals.getPackageManager();
-        final int userId = UserHandle.getUserId(uid);
-        for (int i = 0; i < packageLabels.length; i++) {
-            try {
-                final ApplicationInfo ai = ipm.getApplicationInfo(packageLabels[i],
-                        0 /* no flags */, userId);
-                if (ai == null) {
-                    Log.d(PowerUsageSummary.TAG, "Retrieving null app info for package "
-                            + packageLabels[i] + ", user " + userId);
-                    continue;
-                }
-                CharSequence label = ai.loadLabel(pm);
-                if (label != null) {
-                    packageLabels[i] = label.toString();
-                }
-                if (ai.icon != 0) {
-                    defaultPackageName = sipper.mPackages[i];
-                    icon = ai.loadIcon(pm);
-                    break;
-                }
-            } catch (RemoteException e) {
-                Log.d(PowerUsageSummary.TAG, "Error while retrieving app info for package "
-                        + packageLabels[i] + ", user " + userId, e);
-            }
-        }
-        if (icon == null) {
-            icon = defaultActivityIcon;
-        }
-
-        if (packageLabels.length == 1) {
-            name = packageLabels[0];
-        } else {
-            // Look for an official name for this UID.
-            for (String pkgName : sipper.mPackages) {
+            // Convert package names to user-facing labels where possible
+            IPackageManager ipm = AppGlobals.getPackageManager();
+            final int userId = UserHandle.getUserId(uid);
+            for (int i = 0; i < packageLabels.length; i++) {
                 try {
-                    final PackageInfo pi = ipm.getPackageInfo(pkgName, 0 /* no flags */, userId);
-                    if (pi == null) {
-                        Log.d(PowerUsageSummary.TAG, "Retrieving null package info for package "
-                                + pkgName + ", user " + userId);
+                    final ApplicationInfo ai = ipm.getApplicationInfo(packageLabels[i],
+                            0 /* no flags */, userId);
+                    if (ai == null) {
+                        Log.d(PowerUsageSummary.TAG, "Retrieving null app info for package "
+                                + packageLabels[i] + ", user " + userId);
                         continue;
                     }
-                    if (pi.sharedUserLabel != 0) {
-                        final CharSequence nm = pm.getText(pkgName,
-                                pi.sharedUserLabel, pi.applicationInfo);
-                        if (nm != null) {
-                            name = nm.toString();
-                            if (pi.applicationInfo.icon != 0) {
-                                defaultPackageName = pkgName;
-                                icon = pi.applicationInfo.loadIcon(pm);
-                            }
-                            break;
-                        }
+                    CharSequence label = ai.loadLabel(pm);
+                    if (label != null) {
+                        packageLabels[i] = label.toString();
+                    }
+                    if (ai.icon != 0) {
+                        defaultPackageName = sipper.mPackages[i];
+                        icon = ai.loadIcon(pm);
+                        break;
                     }
                 } catch (RemoteException e) {
-                    Log.d(PowerUsageSummary.TAG, "Error while retrieving package info for package "
-                            + pkgName + ", user " + userId, e);
+                    Log.d(PowerUsageSummary.TAG, "Error while retrieving app info for package "
+                            + packageLabels[i] + ", user " + userId, e);
+                }
+            }
+
+            if (packageLabels.length == 1) {
+                name = packageLabels[0];
+            } else {
+                // Look for an official name for this UID.
+                for (String pkgName : sipper.mPackages) {
+                    try {
+                        final PackageInfo pi = ipm.getPackageInfo(pkgName, 0 /* no flags */, userId);
+                        if (pi == null) {
+                            Log.d(PowerUsageSummary.TAG, "Retrieving null package info for package "
+                                    + pkgName + ", user " + userId);
+                            continue;
+                        }
+                        if (pi.sharedUserLabel != 0) {
+                            final CharSequence nm = pm.getText(pkgName,
+                                    pi.sharedUserLabel, pi.applicationInfo);
+                            if (nm != null) {
+                                name = nm.toString();
+                                if (pi.applicationInfo.icon != 0) {
+                                    defaultPackageName = pkgName;
+                                    icon = pi.applicationInfo.loadIcon(pm);
+                                }
+                                break;
+                            }
+                        }
+                    } catch (RemoteException e) {
+                        Log.d(PowerUsageSummary.TAG, "Error while retrieving package info for package "
+                                + pkgName + ", user " + userId, e);
+                    }
                 }
             }
         }
-        final String uidString = Integer.toString(sipper.uidObj.getUid());
+
+        final String uidString = Integer.toString(uid);
+        if (name == null) {
+            name = uidString;
+        }
+
+        if (icon == null) {
+            icon = pm.getDefaultActivityIcon();
+        }
+
         UidToDetail utd = new UidToDetail();
         utd.name = name;
         utd.icon = icon;
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 9248075..445896d 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -76,7 +76,7 @@
     private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
 
     private static final int MIN_POWER_THRESHOLD_MILLI_AMP = 5;
-    private static final int MAX_ITEMS_TO_LIST = 10;
+    private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10;
     private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
     private static final int SECONDS_IN_HOUR = 60 * 60;
 
@@ -181,11 +181,19 @@
         mAppListGroup.addPreference(notAvailable);
     }
 
+    private static boolean isSharedGid(int uid) {
+        return UserHandle.getAppIdFromSharedAppGid(uid) > 0;
+    }
+
+    private static boolean isSystemUid(int uid) {
+        return uid >= Process.SYSTEM_UID && uid < Process.FIRST_APPLICATION_UID;
+    }
+
     /**
      * We want to coalesce some UIDs. For example, dex2oat runs under a shared gid that
      * exists for all users of the same app. We detect this case and merge the power use
      * for dex2oat to the device OWNER's use of the app.
-     * @return A sorted list of app's using power.
+     * @return A sorted list of apps using power.
      */
     private static List<BatterySipper> getCoalescedUsageList(final List<BatterySipper> sippers) {
         final SparseArray<BatterySipper> uidList = new SparseArray<>();
@@ -193,30 +201,62 @@
         final ArrayList<BatterySipper> results = new ArrayList<>();
         final int numSippers = sippers.size();
         for (int i = 0; i < numSippers; i++) {
-            final BatterySipper sipper = sippers.get(i);
+            BatterySipper sipper = sippers.get(i);
             if (sipper.getUid() > 0) {
                 int realUid = sipper.getUid();
-                if (sipper.getUid() >= Process.FIRST_SHARED_APPLICATION_GID &&
-                        sipper.getUid() <= Process.LAST_SHARED_APPLICATION_GID) {
-                    // This is a shared gid being used to do work on behalf of an app across all
-                    // users. But we'll blame the power on the device OWNER.
+
+                // Check if this UID is a shared GID. If so, we combine it with the OWNER's
+                // actual app UID.
+                if (isSharedGid(sipper.getUid())) {
                     realUid = UserHandle.getUid(UserHandle.USER_OWNER,
                             UserHandle.getAppIdFromSharedAppGid(sipper.getUid()));
                 }
 
+                // Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc).
+                if (isSystemUid(realUid)
+                        && !"mediaserver".equals(sipper.packageWithHighestDrain)) {
+                    // Use the system UID for all UIDs running in their own sandbox that
+                    // are not apps. We exclude mediaserver because we already are expected to
+                    // report that as a separate item.
+                    realUid = Process.SYSTEM_UID;
+                }
+
+                if (realUid != sipper.getUid()) {
+                    // Replace the BatterySipper with a new one with the real UID set.
+                    BatterySipper newSipper = new BatterySipper(sipper.drainType,
+                            new FakeUid(realUid), 0.0);
+                    newSipper.add(sipper);
+                    newSipper.packageWithHighestDrain = sipper.packageWithHighestDrain;
+                    newSipper.mPackages = sipper.mPackages;
+                    sipper = newSipper;
+                }
+
                 int index = uidList.indexOfKey(realUid);
                 if (index < 0) {
+                    // New entry.
                     uidList.put(realUid, sipper);
                 } else {
-                    BatterySipper existingSipper = uidList.valueAt(index);
-                    if (existingSipper.getUid() >= Process.FIRST_SHARED_APPLICATION_GID &&
-                            existingSipper.getUid() <= Process.FIRST_SHARED_APPLICATION_GID) {
-                        // If the app already under this uid is a dex2oat run, then combine and
-                        // substitute it with the actual app.
-                        sipper.add(existingSipper);
-                        uidList.setValueAt(index, sipper);
-                    } else {
-                        existingSipper.add(sipper);
+                    // Combine BatterySippers if we already have one with this UID.
+                    final BatterySipper existingSipper = uidList.valueAt(index);
+                    existingSipper.add(sipper);
+                    if (existingSipper.packageWithHighestDrain == null
+                            && sipper.packageWithHighestDrain != null) {
+                        existingSipper.packageWithHighestDrain = sipper.packageWithHighestDrain;
+                    }
+
+                    final int existingPackageLen = existingSipper.mPackages != null ?
+                            existingSipper.mPackages.length : 0;
+                    final int newPackageLen = sipper.mPackages != null ?
+                            sipper.mPackages.length : 0;
+                    if (newPackageLen > 0) {
+                        String[] newPackages = new String[existingPackageLen + newPackageLen];
+                        if (existingPackageLen > 0) {
+                            System.arraycopy(existingSipper.mPackages, 0, newPackages, 0,
+                                    existingPackageLen);
+                        }
+                        System.arraycopy(sipper.mPackages, 0, newPackages, existingPackageLen,
+                                newPackageLen);
+                        existingSipper.mPackages = newPackages;
                     }
                 }
             } else {
@@ -355,6 +395,15 @@
         sipper.packageWithHighestDrain = "dex2oat";
         stats.add(sipper);
 
+        sipper = new BatterySipper(DrainType.APP,
+                new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID + 1)), 10.0f);
+        sipper.packageWithHighestDrain = "dex2oat";
+        stats.add(sipper);
+
+        sipper = new BatterySipper(DrainType.APP,
+                new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID)), 9.0f);
+        stats.add(sipper);
+
         return stats;
     }