1.问题描述 小程序应用是部分生态应用的入口,类似于launcher的生态应用的入口合集。测试同学反馈从小程序点击进入真实应用之后,多操作几次会发现从应用无法返回小程序应用,直接返回的是Launcher。
2.问题调查 1 2 3 4 5 6 7 8 I/ActivityManager( 784): Killing 4672:com.android.keychain/1000 (adj 906): empty #17 I/am_kill ( 784): [0,4672,com.android.keychain,906,empty #17] I/ActivityManager( 784): Killing 4451:com.android.printspooler/u0a73 (adj 906): empty #17 I/am_kill ( 784): [0,4451,com.android.printspooler,906,empty #17] I/ActivityManager( 784): Killing 4803:com.android.managedprovisioning/u0a10 (adj 906): empty #17 I/am_kill ( 784): [0,4803,com.android.managedprovisioning,906,empty #17] I/ActivityManager( 784): Killing 4982:com.qualcomm.timeservice/u0a95 (adj 906): empty #17 I/am_kill ( 784): [0,4982,com.qualcomm.timeservice,906,empty #17]
从以上日志中搜索am_kill
可以看到有很多应用被杀掉。
为什么会被杀呢? 通常情况下内存不够用了,AMS处通过杀进程来回收部分内存。因此看一下内存情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 225,572K: Cached 41,353K: com.gxatek.cockpit.settings (pid 23328 / activities) 33,412K: com.gxatek.cockpit.diagnostic (pid 27166 / activities) 33,314K: com.gxatek.cockpit.diagnostic (pid 27231 / activities) 30,598K: com.gxatek.cockpit.globalsearch (pid 32533 / activities) 20,520K: com.gxa.service.weather (pid 4621) 19,520K: com.gxa.service.weather (pid 4596) 14,718K: com.android.support.car.lenspicker (pid 27122) 14,063K: android.process.acore (pid 14054) 13,764K: com.android.deskclock (pid 2167) 13,464K: com.android.deskclock (pid 2189) 13,138K: com.android.providers.calendar (pid 3033) 12,145K: com.android.mtp (pid 32723) 12,049K: com.android.printspooler (pid 13469) 11,199K: com.android.externalstorage (pid 32696) 8,613K: android.process.media (pid 2887)
我们当前车机系统是多用户系统,可以看到很多进程会有多个进程存在。而且Cached空进程项
展示的进程会有很多重复的进程。通过如下源码可以看到空进程项
最大只有16个,如果超过的话,会杀掉LRU中最前面的进程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 final void updateOomAdjLocked () { ...... switch (app.curProcState) { case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: mNumCachedHiddenProcs++; numCached++; if (numCached > cachedProcessLimit) { app.kill("cached #" + numCached, true ); } break ; case ActivityManager.PROCESS_STATE_CACHED_EMPTY: if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES && app.lastActivityTime < oldTime) { app.kill("empty for " + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime) / 1000 ) + "s" , true ); } else { numEmpty++; if (numEmpty > emptyProcessLimit) { app.kill("empty #" + numEmpty, true ); } } break ; default : mNumNonCachedProcs++; break ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;private void updateMaxCachedProcesses () { CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0 ? MAX_CACHED_PROCESSES : mOverrideMaxCachedProcesses; CUR_MAX_EMPTY_PROCESSES = computeEmptyProcessLimit(CUR_MAX_CACHED_PROCESSES); final int rawMaxEmptyProcesses = computeEmptyProcessLimit(MAX_CACHED_PROCESSES); CUR_TRIM_EMPTY_PROCESSES = rawMaxEmptyProcesses/2 ; CUR_TRIM_CACHED_PROCESSES = (MAX_CACHED_PROCESSES-rawMaxEmptyProcesses)/3 ; }
1 2 3 4 5 6 7 public static int computeEmptyProcessLimit (int totalProcessLimit) { return totalProcessLimit/2 ; } private static final int DEFAULT_MAX_CACHED_PROCESSES = 32 ;public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
因此如果Cached进程
进程超过16个,也会触发杀进程机制。因此为了保证小程序后台进程进入被系统放入Cached进程不被杀,就要限制Cached进程尽量少于16。
3.解决方案 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ArrayList<String> mCachePackageList= new ArrayList<>(); final void updateOomAdjLocked () { ...... mCachePackageList.clear(); for (int i=N-1 ; i>=0 ; i--) { ProcessRecord app = mLruProcesses.get(i); if (!app.killedByAm && app.thread != null ) { applyOomAdjLocked(app, true , now, nowElapsed); switch (app.curProcState) { case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: if (mCachePackageList.contains(app.info.processName)) { app.kill("multi user process:" + app.info.processName, true ); break ; } else { mCachePackageList.add(app.info.processName); } mNumCachedHiddenProcs++; numCached++; if (numCached > cachedProcessLimit) { app.kill("cached #" + numCached, true ); } break ; case ActivityManager.PROCESS_STATE_CACHED_EMPTY: if (mCachePackageList.contains(app.info.processName)) { app.kill("multi user process:" + app.info.processName, true ); break ; } else { mCachePackageList.add(app.info.processName); } if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES && app.lastActivityTime < oldTime) { app.kill("empty for " + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime) / 1000 ) + "s" , true ); } else { numEmpty++; if (numEmpty > emptyProcessLimit) { app.kill("empty #" + numEmpty, true ); } } break ; default : mNumNonCachedProcs++; break ; } }
从上面逻辑可以看到修复的方案就是当Cached的进程中如果有相同进程的话,就直接杀掉,如果没有的话就保存下来。
此方案不能完全解决小程序后台被杀的情况,但是可以防止小程序进程被放入Cached
进程被杀。
当从生态应用回到小程序应用的时候,进程也不会是后台进程了,优先级升高了,因此也不会被放入Cached
进程中。
版权声明: 此文章版权归Jack Ou所有,如有转载,请註明来自原作者