Merge "Remove UID from kernel cpu accounting when uninstalled" into mnc-dev
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 94f1685..46dc3fe 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -8425,6 +8425,7 @@
      * Remove the statistics object for a particular uid.
      */
     public void removeUidStatsLocked(int uid) {
+        mKernelUidCpuTimeReader.removeUid(uid);
         mUidStats.remove(uid);
     }
 
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 197e5b1..b236378 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -22,6 +22,7 @@
 
 import java.io.BufferedReader;
 import java.io.FileReader;
+import java.io.FileWriter;
 import java.io.IOException;
 
 /**
@@ -37,6 +38,7 @@
 public class KernelUidCpuTimeReader {
     private static final String TAG = "KernelUidCpuTimeReader";
     private static final String sProcFile = "/proc/uid_cputime/show_uid_stat";
+    private static final String sRemoveUidProcFile = "/proc/uid_cputime/remove_uid_range";
 
     /**
      * Callback interface for processing each line of the proc file.
@@ -66,12 +68,22 @@
                 final long systemTimeUs = Long.parseLong(splitter.next(), 10);
 
                 if (callback != null) {
+                    long userTimeDeltaUs = userTimeUs;
+                    long systemTimeDeltaUs = systemTimeUs;
                     int index = mLastUserTimeUs.indexOfKey(uid);
-                    if (index < 0) {
-                        callback.onUidCpuTime(uid, userTimeUs, systemTimeUs);
-                    } else {
-                        callback.onUidCpuTime(uid, userTimeUs - mLastUserTimeUs.valueAt(index),
-                                systemTimeUs - mLastSystemTimeUs.valueAt(index));
+                    if (index >= 0) {
+                        userTimeDeltaUs -= mLastUserTimeUs.valueAt(index);
+                        systemTimeDeltaUs -= mLastSystemTimeUs.valueAt(index);
+
+                        if (userTimeDeltaUs < 0 || systemTimeDeltaUs < 0) {
+                            // The UID must have been removed from accounting, then added back.
+                            userTimeDeltaUs = userTimeUs;
+                            systemTimeDeltaUs = systemTimeUs;
+                        }
+                    }
+
+                    if (userTimeDeltaUs != 0 || systemTimeDeltaUs != 0) {
+                        callback.onUidCpuTime(uid, userTimeDeltaUs, systemTimeDeltaUs);
                     }
                 }
                 mLastUserTimeUs.put(uid, userTimeUs);
@@ -81,4 +93,23 @@
             Slog.e(TAG, "Failed to read uid_cputime", e);
         }
     }
+
+    /**
+     * Removes the UID from the kernel module and from internal accounting data.
+     * @param uid The UID to remove.
+     */
+    public void removeUid(int uid) {
+        int index = mLastUserTimeUs.indexOfKey(uid);
+        if (index >= 0) {
+            mLastUserTimeUs.removeAt(index);
+            mLastSystemTimeUs.removeAt(index);
+        }
+
+        try (FileWriter writer = new FileWriter(sRemoveUidProcFile)) {
+            writer.write(Integer.toString(uid) + "-" + Integer.toString(uid));
+            writer.flush();
+        } catch (IOException e) {
+            Slog.e(TAG, "failed to remove uid from uid_cputime module", e);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0d7ff85..a8ab667 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16143,10 +16143,7 @@
                             final int uid = intentExtras != null
                                     ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
                             if (uid >= 0) {
-                                BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
-                                synchronized (bs) {
-                                    bs.removeUidStatsLocked(uid);
-                                }
+                                mBatteryStatsService.removeUid(uid);
                                 mAppOpsService.uidRemoved(uid);
                             }
                             break;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index e64e9d8..a61223a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -178,6 +178,15 @@
 
     // These are for direct use by the activity manager...
 
+    /**
+     * Remove a UID from the BatteryStats and BatteryStats' external dependencies.
+     */
+    void removeUid(int uid) {
+        synchronized (mStats) {
+            mStats.removeUidStatsLocked(uid);
+        }
+    }
+
     void addIsolatedUid(int isolatedUid, int appUid) {
         synchronized (mStats) {
             mStats.addIsolatedUidLocked(isolatedUid, appUid);