Actual combat - an implementation of low memory performance optimization of Android system

Posted by artfuldrone on Mon, 03 Jan 2022 18:40:41 +0100

preface
System performance optimization is a huge topic. It can be said that most of our work in Freamwork is held around this point. In this article, we have done some work in AMS under the condition of low memory. By killing some unnecessary processes, users can ensure the smooth use of the system without jamming.

Low memory performance optimization scheme
1). By adding a black-and-white list, some third-party applications or infrequently used application processes are limited
Actual combat - Android system black and white list
2). Minimize the number of system processes and limit the start of application receiving broadcast
Actual combat - Android restricted application receiving broadcast startup
3). Limit the number of system background processes (AMS.setProcessLimit)
4). Add defined policies and Kill some processes to ensure the operation of core tasks

This part mainly focuses on Part 4).

realization
It is mainly implemented in updateOomAdjLocked of ActivityManagerService. You can directly view and modify:

diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 81d1bb7..7e753d3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -242,6 +242,9 @@ public final class ActivityManagerService extends ActivityManagerNative
+    final private int ams_killprocess_stage1 = SystemProperties.getInt("ro.ams.killprocess.stage1", 0); //Custom low memory level stage1
+    final private int ams_killprocess_stage2 = SystemProperties.getInt("ro.ams.killprocess.stage2", 0);//Custom low memory level stage2
+    final private int ams_killprocess_stage3 = SystemProperties.getInt("ro.ams.killprocess.stage3", 0);
+    final private int ams_killprocess_stage4 = SystemProperties.getInt("ro.ams.killprocess.stage4", 0);
+
 
@@ -7175,9 +7183,9 @@ public final class ActivityManagerService extends ActivityManagerNative

//Kill the process and its associated service components, etc
+    final private void killTargetProcesses(String packageName, int adj_min, int pkgUid, String reason) {
+
+        int appId = UserHandle.getAppId(pkgUid);
+        int uid = UserHandle.getUserId(pkgUid);
+        ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
+        boolean real_removed = true;
+
+        final int NP = mProcessNames.getMap().size();
+        for (int ip=0; ip<NP; ip++) {
+            SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+            final int NA = apps.size();
+            for (int ia=0; ia<NA; ia++) {
+                ProcessRecord app = apps.valueAt(ia);
+                // find its all brother processes
+                if ((!app.pkgList.containsKey(packageName)) &&
+                        (uid != UserHandle.USER_ALL && app.userId == uid) &&
+                        (UserHandle.getAppId(app.uid) != appId)) {
+                    continue;
+                }
+
+                if (app.removed) {
+                    continue;
+                }
+
+                // Skip process if one os its brother processes doesn't meet our oom adj requirement.
+                if (app.curAdj < adj_min) {
+                    real_removed = false;
+                    break;
+                }
+
+                app.removed = true;
+                procs.add(app);
+            }
+
+            if (!real_removed) {
+                break;
+            }
+        }
+
+        if (real_removed) {
+            int N = procs.size();
+            for (int i=0; i<N; i++) {
+                killUnneededProcessLocked(procs.get(i), reason);
+            }
+
+            mStackSupervisor.forceStopPackageLocked(packageName, true, false, uid);
+
+            mServices.forceStopLocked(packageName, uid, false, true);
+
+            ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
+            mProviderMap.collectForceStopProviders(packageName, appId, true, false, uid, providers);
+            N = providers.size();
+            for (int i=0; i<N; i++) {
+                removeDyingProviderLocked(null, providers.get(i), true);
+            }
+        } else {
+            int N = procs.size();
+            for (int i=0; i<N; i++) {
+                procs.get(i).removed = false;
+            }
+        }
+
+        procs.clear();
+        procs = null;
+    }
+
+    final private void killTargetProcesses(ProcessRecord app, int adj_min, int uid, String reason) {
+
+        IPackageManager pm = AppGlobals.getPackageManager();
+
+        for (int i = 0; i < app.pkgList.size(); i++) {
+            String packageName = app.pkgList.keyAt(i);
+            int pkgUid = -1;
+            try {
+                pkgUid = pm.getPackageUid(packageName, uid);
+            } catch (RemoteException e) {
+            }
+
+            killTargetProcesses(packageName, adj_min, pkgUid, reason);
+
+            Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
+                    Uri.fromParts("package", packageName, null));
+            if (!mProcessesReady) {
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                        | Intent.FLAG_RECEIVER_FOREGROUND);
+            }
+            intent.putExtra(Intent.EXTRA_UID, pkgUid);
+            intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(pkgUid));
+            broadcastIntentLocked(null, null, intent,
+                    null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+                    false, false,
+                    MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(pkgUid));
+        }
+    }
+   
+    final Boolean killTargetProcesses(ProcessRecord app) {
+        Boolean needKill = false;
+        Boolean needKillService = false;
+        int adj_min = 0;
+
+        MemInfoReader minfo = new MemInfoReader();
+        minfo.readMemInfo();
+        if (DEBUG_MEMORY)
+            Log.d(TAG_MEMORY, "free size = " + minfo.getFreeSizeKb() +
+                " kb, cached size = " + minfo.getCachedSizeKb() + " kb");
+
+        long totalFree = (minfo.getFreeSizeKb() + minfo.getCachedSizeKb()) / 1024;
+
+        if (DEBUG_MEMORY)
+            Log.d(TAG_MEMORY, "totalFree RAM = " + totalFree +
+                " app.process = " + app.processName +
+                " is platform = " + ((app.info.flags & ApplicationInfo.FLAG_PLATFORM_DATA_APK) != 0) +
+                " is system = " + ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) +
+                " app.curAdj = " + app.curAdj + " app.curProcState = " + app.curProcState);
+
+        if ((totalFree > ams_killprocess_stage1) && app.killedByAm)
+            return false;
+
+        if ((app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ) &&
+                (app.curProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) &&
+                (totalFree <= ams_killprocess_stage1)) {
+            if (DEBUG_MEMORY)
+                Log.d(TAG_MEMORY, "ams kill process stage1: " + ams_killprocess_stage1);
+            needKill = true;
+        } else if ((app.curAdj == ProcessList.SERVICE_B_ADJ) &&
+                    (app.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) &&
+                    (totalFree <= ams_killprocess_stage2)) {
+            if (DEBUG_MEMORY)
+                Log.d(TAG_MEMORY, "ams kill process stage3: " + ams_killprocess_stage3);
+            needKillService = true;
+            adj_min = ProcessList.SERVICE_B_ADJ;
+        } else if ((app.curAdj >= ProcessList.SERVICE_ADJ) &&
+                (totalFree <= ams_killprocess_stage3)) {
+            if (DEBUG_MEMORY)
+                Log.d(TAG_MEMORY, "ams kill process stage3: " + ams_killprocess_stage3);
+            needKillService = true;
+            adj_min = ProcessList.SERVICE_ADJ;
+        } else if ((totalFree <= ams_killprocess_stage3) &&
+                    (app.curAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) &&
+                    (app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) &&
+                    ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) &&
+                    ((app.info.flags & ApplicationInfo.FLAG_PLATFORM_DATA_APK) == 0)) {
+            if (DEBUG_MEMORY)
+                Log.d(TAG_MEMORY, "ams kill non-system process stage3: " + ams_killprocess_stage3);
+            needKillService = true;
+            adj_min = ProcessList.PERCEPTIBLE_APP_ADJ;
+        } else if ((totalFree <= ams_killprocess_stage4) &&
+                (app.curAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) &&
+                (app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)) {
+            if (DEBUG_MEMORY)
+                Log.d(TAG_MEMORY, "ams kill process stage4: " + ams_killprocess_stage4);
+            needKillService = true;
+            adj_min = ProcessList.HEAVY_WEIGHT_APP_ADJ;
+        }
+
+        if (needKill) {
+            killUnneededProcessLocked(app, "ams kill cached for releasing memory");
+        }
+
+        if (needKillService) {
+            Log.d(TAG_MEMORY, "kill service here");
+            killTargetProcesses(app, adj_min, 0, "ams kill service for releasing memory");
+        }
+
+        return needKill;
+    }
+
     final void updateOomAdjLocked() {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
@@ -16234,32 +16409,35 @@ public final class ActivityManagerService extends ActivityManagerNative

                 applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now);

-                // Count the number of process types.
-                switch (app.curProcState) {
-                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
-                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
-                        mNumCachedHiddenProcs++;
-                        numCached++;
-                        if (numCached > cachedProcessLimit && !isProtectedApp(app, TOP_APP)) {
-                            killUnneededProcessLocked(app, "cached #" + numCached);
-                        }
-                        break;
-                    case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
-                        if (numEmpty > ProcessList.TRIM_EMPTY_APPS
-                                && app.lastActivityTime < oldTime) {
-                            killUnneededProcessLocked(app, "empty for "
-                                    + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
-                                    / 1000) + "s");
-                        } else {
-                            numEmpty++;
-                            if (numEmpty > emptyProcessLimit) {
-                                killUnneededProcessLocked(app, "empty #" + numEmpty);
+                if (!killTargetProcesses(app))      // add by caoxin for memory, this function has high priority
+                {
+                    // Count the number of process types.
+                    switch (app.curProcState) {
+                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                            mNumCachedHiddenProcs++;
+                            numCached++;
+                            if (numCached > cachedProcessLimit) {
+                                killUnneededProcessLocked(app, "cached #" + numCached);
                             }
-                        }
-                        break;
-                    default:
-                        mNumNonCachedProcs++;
-                        break;
+                            break;
+                        case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+                            if (numEmpty > ProcessList.TRIM_EMPTY_APPS
+                                    && app.lastActivityTime < oldTime) {
+                                killUnneededProcessLocked(app, "empty for "
+                                        + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
+                                        / 1000) + "s");
+                            } else {
+                                numEmpty++;
+                                if (numEmpty > emptyProcessLimit) {
+                                    killUnneededProcessLocked(app, "empty #" + numEmpty);
+                                }
+                            }
+                            break;
+                        default:
+                            mNumNonCachedProcs++;
+                            break;
+                    }
                 }

                 if (app.isolated && app.services.size() <= 0) {
-- 
1.9.1

The main idea is to add the killTargetProcesses(app) function after updateOomAdjLocked updates oomadj to kill the process in the corresponding state according to the memory limit level.

Upgrade
When playing video in the system, the memory consumption of the system is relatively large. Taking this as the node, we have added setIsPlayingVideo interface in AMS. When playing online video, we notify AMS to clear the memory that can be released in the system.

When TV plays video:
a. Basically, the memory of all third-party app processes that are not playing video will be released.
b. The system app will kill all cache s, empty and non running service b processes according to the current state
The above two operations are performed at the beginning of each playback and only once. The purpose is to maximize the available memory during playback, and take the playback video as the node to empty the memory that can be released in the system as much as possible

When the TV does not play video:
a. Do not clean up system app s
b. For third-party app s, each time updateOomAdjLocked, clean up the cache and service b processes to free memory

diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5013d22..8e5f8bf 100755
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -383,7 +383,7 @@ public final class ActivityManagerService extends ActivityManagerNative
     public boolean mHomeStarted = false;

     private long totalFree = 0;
-    private MemInfoReader minfo = new MemInfoReader();
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -1111,6 +1111,8 @@ public final class ActivityManagerService extends ActivityManagerNative
     static final int IMMERSIVE_MODE_LOCK_MSG = 37;
     static final int PERSIST_URI_GRANTS_MSG = 38;
     static final int REQUEST_ALL_PSS_MSG = 39;
+    static final int KILL_WHEN_PLAYING = 40;
+    static final int STOP_PLAYING_TIMEOUT = 41;

     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1809,6 +1811,16 @@ public final class ActivityManagerService extends ActivityManagerNative
                 requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
                 break;
             }
+            case KILL_WHEN_PLAYING: {
+                synchronized (ActivityManagerService.this) {
+                    killTargetProcessesLocked();
+                }
+                break;
+            }
+            case STOP_PLAYING_TIMEOUT: {
+                    isPlayingVideo = false;
+                break;
+            }
             }
         }
     };
@@ -8861,7 +8873,24 @@ public final class ActivityManagerService extends ActivityManagerNative
     @Override
     public void setIsPlayingVideo(boolean playing) {
         synchronized (this) {
-            isPlayingVideo = playing;
+            if (playing) {
+                if (!isPlayingVideo) {
+                    if (DEBUG_MEMORY)
+                        Log.d(TAG_MEMORY, "start playing video, send KILL message");
+
+                    isPlayingVideo = true;
+                    mHandler.sendEmptyMessageDelayed(KILL_WHEN_PLAYING, 3000);
+                }
+            } else {
+                if (DEBUG_MEMORY)
+                    Log.d(TAG_MEMORY, "stop playing video, delete KILL message");
+
+                mHandler.sendEmptyMessageDelayed(STOP_PLAYING_TIMEOUT, 1500);
+
+                if (mHandler.hasMessages(KILL_WHEN_PLAYING)) {
+                    mHandler.removeMessages(KILL_WHEN_PLAYING);
+                }
+            }
         }
     }

@@ -16172,7 +16201,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         }
     }
// Called when updateOomAdjLocked
-    final Boolean killTargetProcesses(ProcessRecord app) {
+    final Boolean killTargetProcessesLocked(ProcessRecord app) {
         Boolean needKill = false;
         Boolean needKillService = false;
         int adj_min = 0;
@@ -16180,15 +16209,11 @@ public final class ActivityManagerService extends ActivityManagerNative
         if (ams_killprocess_stage1 == 0)
             return false;

-        if (!isPlayingVideo) {      // it's not playing video currently
-            if (totalFree == 0) {
-                minfo.readMemInfo();
-                if (DEBUG_MEMORY)
-                    Log.d(TAG_MEMORY, "killTargetProcesses start: free size = " + minfo.getFreeSizeKb() +
-                            " kb, cached size = " + minfo.getCachedSizeKb() + " kb");
+        if (Looper.getMainLooper() != Looper.myLooper()) {  // only do this in main looper
+            return false;
+        }

-                totalFree = (minfo.getFreeSizeKb() + minfo.getCachedSizeKb()) / 1024;
-            }
+        if (!isPlayingVideo) {      // it's not playing video currently

             if (DEBUG_MEMORY)
                 Log.d(TAG_MEMORY, "totalFree RAM = " + totalFree +
@@ -16198,97 +16223,32 @@ public final class ActivityManagerService extends ActivityManagerNative
                         " app.curAdj = " + app.curAdj + " app.curProcState = " + app.curProcState +
                         " app.keeping = " + app.keeping + " app.cached = " + app.cached + " app.empty = " + app.empty);

-            if ((totalFree > ams_killprocess_stage1) || app.killedByAm)
+            if (app.killedByAm)
                 return false;

             if (((app.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) &&
                     ((app.info.flags & ApplicationInfo.FLAG_PLATFORM_DATA_APK) == 0)) {     // non-system app

-                if ((app.curAdj > ProcessList.CACHED_APP_MIN_ADJ) &&
-                        (app.curProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) &&
-                        (totalFree <= ams_killprocess_stage1)) {
-                    if (DEBUG_MEMORY)
-                        Log.d(TAG_MEMORY, "ams kill non-system process stage1: " + ams_killprocess_stage1);
-                    needKill = true;
-                } else if ((app.curAdj == ProcessList.SERVICE_B_ADJ) &&
-                        (app.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) &&
-                        (totalFree <= ams_killprocess_stage2)) {
-                    if (DEBUG_MEMORY)
-                        Log.d(TAG_MEMORY, "ams kill non-process stage2: " + ams_killprocess_stage2);
-                    needKillService = true;
-                    adj_min = ProcessList.SERVICE_B_ADJ;
-                } else if ((totalFree <= ams_killprocess_stage3) &&
-                        (app.curAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) &&
-                        (app.curProcState >= ActivityManager.PROCESS_STATE_HEAVY_WEIGHT)) {
-                    if (DEBUG_MEMORY)
-                        Log.d(TAG_MEMORY, "ams kill non-system process stage3: " + ams_killprocess_stage3);
-                    needKillService = true;
-                    adj_min = ProcessList.HEAVY_WEIGHT_APP_ADJ;
-                } else if ((totalFree <= ams_killprocess_stage4) &&
-                        (app.curAdj == ProcessList.SERVICE_ADJ) &&
-                        (app.curProcState >= ActivityManager.PROCESS_STATE_SERVICE)) {
-                    if (DEBUG_MEMORY)
-                        Log.d(TAG_MEMORY, "ams kill non-system service process stage4: " + ams_killprocess_stage4);
-                    needKillService = true;
-                    adj_min = ProcessList.SERVICE_ADJ;
-                }
-
-            } else { // system app
-
-                if ((app.curAdj > ProcessList.CACHED_APP_MIN_ADJ) &&
-                        (app.curProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) &&
-                        (totalFree <= ams_killprocess_stage1) &&
-                        (!app.keeping)) {
-                    if (DEBUG_MEMORY)
-                        Log.d(TAG_MEMORY, "ams kill system process stage1: " + ams_killprocess_stage1);
-                    needKill = true;
-                } else if ((app.curAdj == ProcessList.SERVICE_B_ADJ) &&
-                        (app.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) &&
-                        (!app.keeping) &&
-                        (totalFree <= ams_killprocess_stage2)) {
-                    if (DEBUG_MEMORY)
-                        Log.d(TAG_MEMORY, "ams kill system process stage2: " + ams_killprocess_stage2);
-                    needKillService = true;
-                    adj_min = ProcessList.SERVICE_B_ADJ;
-                } else if ((totalFree <= ams_killprocess_stage4) &&
-                        (app.curAdj == ProcessList.SERVICE_ADJ) &&
-                        (app.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) &&
-                        (!app.keeping)) {
-                    if (DEBUG_MEMORY)
-                        Log.d(TAG_MEMORY, "ams kill system service process stage4: " + ams_killprocess_stage4);
-                    needKillService = true;
-                    adj_min = ProcessList.SERVICE_ADJ;
-                }
-
-            }
-        } else {    // it's playing video, kill almost all the 3rd apps running background
-            if (DEBUG_MEMORY)
-                Log.d(TAG_MEMORY, "it's playing video");
-
-            if (((app.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) &&
-                    ((app.info.flags & ApplicationInfo.FLAG_PLATFORM_DATA_APK) == 0)) {
                 needKillService = true;
-                adj_min = ProcessList.PERCEPTIBLE_APP_ADJ;
+                adj_min = ProcessList.SERVICE_ADJ;

                 if (DEBUG_MEMORY)
-                    Log.d(TAG_MEMORY, "it's playing video, kill 3rd apps");
-            } else {
+                    Log.d(TAG_MEMORY, "it stopped playing video, kill 3rd apps");
+
                 if ((app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ) &&
                         (app.curProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) &&
                         (!app.keeping)) {
-
                     if (DEBUG_MEMORY)
-                        Log.d(TAG_MEMORY, "it's playing video, kill system cached apps");
+                        Log.d(TAG_MEMORY, "ams kill non-system process stage1: " + ams_killprocess_stage1);
                     needKill = true;
-                } else if ((app.curAdj == ProcessList.SERVICE_B_ADJ) &&
-                        (app.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) &&
-                        (!app.keeping)) {
+                } else if (((app.curAdj == ProcessList.SERVICE_B_ADJ) || (app.curAdj == ProcessList.SERVICE_ADJ)) &&
+                        (app.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) ) {
                     if (DEBUG_MEMORY)
-                        Log.d(TAG_MEMORY, "it's playing video, kill system service B apps");
-
+                        Log.d(TAG_MEMORY, "ams kill non-process stage2: " + ams_killprocess_stage2);
                     needKillService = true;
-                    adj_min = ProcessList.SERVICE_B_ADJ;
+                    adj_min = app.curAdj;
                 }
+
             }
         }

@@ -16300,21 +16260,64 @@ public final class ActivityManagerService extends ActivityManagerNative
             killTargetProcesses(app, adj_min, 0, "ams kill service for releasing memory");
         }

-        if (needKill || needKillService) {
+        if (needKill || needKillService)
+            return true;

-            if (!isPlayingVideo) {      // it's not playing video, update the memory information
-                minfo.readMemInfo();
-                if (DEBUG_MEMORY)
-                    Log.d(TAG_MEMORY, "killTargetProcesses after kill: free size = " + minfo.getFreeSizeKb() +
-                            " kb, cached size = " + minfo.getCachedSizeKb() + " kb");
+        return  false;
+    }

-                totalFree = (minfo.getFreeSizeKb() + minfo.getCachedSizeKb()) / 1024;
-            }
+    //Called when playing video
+    final void killTargetProcessesLocked() {
+        final int N = mLruProcesses.size();
+        if (DEBUG_MEMORY)
+            Log.d(TAG_MEMORY, "it's playing video, clear background apps");
+
+        for (int i=N-1; i>=0; i--) {
+            Boolean needKill = false;
+            Boolean needKillService = false;
+            int adj_min = 0;
+
+            ProcessRecord app = mLruProcesses.get(i);
+
+            if (!app.killedByAm && app.thread != null) {
+
+                if (((app.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) &&
+                        ((app.info.flags & ApplicationInfo.FLAG_PLATFORM_DATA_APK) == 0)) {
+                    needKillService = true;
+                    adj_min = ProcessList.PERCEPTIBLE_APP_ADJ;
+
+                    if (DEBUG_MEMORY)
+                        Log.d(TAG_MEMORY, "it's playing video, kill 3rd apps");
+                } else {
+                    if ((app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ) &&
+                            (app.curProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) &&
+                            (!app.keeping)) {
+
+                        if (DEBUG_MEMORY)
+                            Log.d(TAG_MEMORY, "it's playing video, kill system cached apps");
+                        needKill = true;
+                    } else if ((app.curAdj == ProcessList.SERVICE_B_ADJ) &&
+                            (app.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) &&
+                            (!app.keeping)) {
+                        if (DEBUG_MEMORY)
+                            Log.d(TAG_MEMORY, "it's playing video, kill system service B apps");
+
+                        needKillService = true;
+                        adj_min = ProcessList.SERVICE_B_ADJ;
+                    }
+                }
+
+                if (needKill) {
+                    killUnneededProcessLocked(app, "ams kill cached for releasing memory");
+                }
+
+                if (needKillService) {
+                    killTargetProcesses(app, adj_min, 0, "ams kill service for releasing memory");
+                }
+            }
         }

-        return  false;
     }

     final void updateOomAdjLocked() {
@@ -16443,9 +16446,7 @@ public final class ActivityManagerService extends ActivityManagerNative

                 applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now);

-                if (!killTargetProcesses(app))      // add by for memory, this function has high priority
-                //if (true)      // add by for memory, this function has high priority
-                {
+                if (!killTargetProcessesLocked(app)) {
                     // Count the number of process types.
                     switch (app.curProcState) {
                         case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
-- 
1.9.1
Add setIsPlayingVideo interface
frameworks/av/media/libmediaplayerservice/MediaErrorManager.cpp ```c void MediaErrorManager::onPlay() { ALOGV("on play"); mResetExecuted = false; android::setPlayingStatus(true); }

void MediaErrorManager::onReset() {
ALOGV("on reset");
mResetExecuted = true;
android::setPlayingStatus(false);
}

void MediaErrorManager::onDisconnect() {
ALOGV("on disconnect");
if (!mResetExecuted) {
android::setPlayingStatus(false);
}
}

frameworks/av/media/libmediaplayerservice/ActivityManager.cpp

```c
void setPlayingStatus(bool isPlaying) {
    ALOGE("set playing status, status is %d", isPlaying);
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> am = sm->getService(String16("activity"));
    if (am != NULL) {
        Parcel data, reply;
        data.writeInterfaceToken(String16("android.app.IActivityManager"));
        data.writeInt32(static_cast<int32_t>(isPlaying));
        status_t ret = am->transact(SET_IS_PLAYING_VIDEO, data, &reply);
        if (ret == NO_ERROR) {
            int32_t exceptionCode = reply.readExceptionCode();
            if (!exceptionCode) {
                ALOGV("setPlayingStatus succeed");
            } else {
                ALOGE("setPlayingStatus caught exception %d\n", exceptionCode);
            }
        }
    }
}

IActivityManager.java

public void setIsPlayingVideo(boolean playing) throws RemoteException;
int SET_IS_PLAYING_VIDEO = IBinder.FIRST_CALL_TRANSACTION+188;

ActivityManagerNative.java

case SET_IS_PLAYING_VIDEO: {
     data.enforceInterface(IActivityManager.descriptor);
     final boolean playing = (data.readInt() == 1);
     setIsPlayingVideo(playing);
     reply.writeNoException();
     return true;
 }
 public void setIsPlayingVideo(boolean playing) throws RemoteException {
	 Parcel data = Parcel.obtain();
	 Parcel reply = Parcel.obtain();
	 data.writeInterfaceToken(IActivityManager.descriptor);
	 data.writeInt(playing ? 1 : 0);
	 mRemote.transact(SET_IS_PLAYING_VIDEO, data, reply, 0);
	 reply.readException();
	 data.recycle();
	 reply.recycle();
}

ActivityManagerService.java

 public void setIsPlayingVideo(boolean playing) {
        synchronized (this) {
            isPlayingVideo = playing;
        }
    }

Topics: Android Optimize