Android adj调整时的各类进程状态
1. dump一下进程的信息
使用adb shell dumpsys activity p
可以将Android的各类进程状态信息打印出来,这通常对于分析进程的运行状态和adj有很大帮助
Process LRU list (sorted by oom_adj, 46 total, non-act at 6, non-svc at 6):
PERS #45: sys F/ /PER
LCMN t: 0 1240:system/1000 (fixed)
PERS #46: pers T/ /PERU
LCMN t: 0 1484:com.android.systemui/u0a113 (pers-top-ui)
如上面PER
和PERU
代表什么意思呢?(本次讲解的主题,至于上面的其它信息最后一节会全部解释一下)
具体dump的代码(代码基于Android S)在:frameworks\base\services\core\java\com\android\server\am\ProcessList.java
其打印的是ProcessStateRecord
的mCurProcState
(通过getCurProcState()
获得)
void dumpProcessesLSP(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage, int dumpAppId) {
//...
pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)");
//...
dumpProcessOomList(pw, mService, mLruProcesses, " ", "Proc", "PERS", false,
dumpPackage);
//...
}
private static boolean dumpProcessOomList(PrintWriter pw,
ActivityManagerService service, List<ProcessRecord> origList,
String prefix, String normalLabel, String persistentLabel,
boolean inclDetails, String dumpPackage) {
//...
final ProcessStateRecord state = r.mState;
//...
String procState = makeProcStateString(state.getCurProcState());
//...
}
public static String makeProcStateString(int curProcState) {
return ActivityManager.procStateToString(curProcState);
}
2. ProcState的枚举值和打印字串的对应关系
具体在ActivityManager.java
中有对应关系,到这里大家应该知道
system_server
的PER
代表PROCESS_STATE_PERSISTENT
状态,systemui
的PERU
代表PROCESS_STATE_PERSISTENT_UI
状态
public static String procStateToString(int procState) {
final String procStateStr;
switch (procState) {
case ActivityManager.PROCESS_STATE_PERSISTENT:
procStateStr = "PER ";
break;
case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
procStateStr = "PERU";
break;
case ActivityManager.PROCESS_STATE_TOP:
procStateStr = "TOP ";
break;
case ActivityManager.PROCESS_STATE_BOUND_TOP:
procStateStr = "BTOP";
break;
case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
procStateStr = "FGS ";
break;
case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
procStateStr = "BFGS";
break;
case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
procStateStr = "IMPF";
break;
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
procStateStr = "IMPB";
break;
case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
procStateStr = "TRNB";
break;
case ActivityManager.PROCESS_STATE_BACKUP:
procStateStr = "BKUP";
break;
case ActivityManager.PROCESS_STATE_SERVICE:
procStateStr = "SVC ";
break;
case ActivityManager.PROCESS_STATE_RECEIVER:
procStateStr = "RCVR";
break;
case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
procStateStr = "TPSL";
break;
case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
procStateStr = "HVY ";
break;
case ActivityManager.PROCESS_STATE_HOME:
procStateStr = "HOME";
break;
case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
procStateStr = "LAST";
break;
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
procStateStr = "CAC ";
break;
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
procStateStr = "CACC";
break;
case ActivityManager.PROCESS_STATE_CACHED_RECENT:
procStateStr = "CRE ";
break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
procStateStr = "CEM ";
break;
case ActivityManager.PROCESS_STATE_NONEXISTENT:
procStateStr = "NONE";
break;
default:
procStateStr = "??";
break;
}
return procStateStr;
}
public static final int PROCESS_STATE_UNKNOWN = ProcessStateEnum.UNKNOWN;
public static final int PROCESS_STATE_PERSISTENT = ProcessStateEnum.PERSISTENT;
public static final int PROCESS_STATE_PERSISTENT_UI = ProcessStateEnum.PERSISTENT_UI;
public static final int PROCESS_STATE_TOP = ProcessStateEnum.TOP;
public static final int PROCESS_STATE_BOUND_TOP = ProcessStateEnum.BOUND_TOP;
public static final int PROCESS_STATE_FOREGROUND_SERVICE = ProcessStateEnum.FOREGROUND_SERVICE;
public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE =
ProcessStateEnum.BOUND_FOREGROUND_SERVICE;
public static final int PROCESS_STATE_IMPORTANT_FOREGROUND =
ProcessStateEnum.IMPORTANT_FOREGROUND;
public static final int PROCESS_STATE_IMPORTANT_BACKGROUND =
ProcessStateEnum.IMPORTANT_BACKGROUND;
public static final int PROCESS_STATE_TRANSIENT_BACKGROUND =
ProcessStateEnum.TRANSIENT_BACKGROUND;
public static final int PROCESS_STATE_BACKUP = ProcessStateEnum.BACKUP;
public static final int PROCESS_STATE_SERVICE = ProcessStateEnum.SERVICE;
public static final int PROCESS_STATE_RECEIVER = ProcessStateEnum.RECEIVER;
public static final int PROCESS_STATE_TOP_SLEEPING = ProcessStateEnum.TOP_SLEEPING;
public static final int PROCESS_STATE_HEAVY_WEIGHT = ProcessStateEnum.HEAVY_WEIGHT;
public static final int PROCESS_STATE_HOME = ProcessStateEnum.HOME;
public static final int PROCESS_STATE_LAST_ACTIVITY = ProcessStateEnum.LAST_ACTIVITY;
public static final int PROCESS_STATE_CACHED_ACTIVITY = ProcessStateEnum.CACHED_ACTIVITY;
public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT =
ProcessStateEnum.CACHED_ACTIVITY_CLIENT;
public static final int PROCESS_STATE_CACHED_RECENT = ProcessStateEnum.CACHED_RECENT;
public static final int PROCESS_STATE_CACHED_EMPTY = ProcessStateEnum.CACHED_EMPTY;
public static final int PROCESS_STATE_NONEXISTENT = ProcessStateEnum.NONEXISTENT;
3. ProcState的各类状态都是在什么时候设置,都代表什么意思
下面是关于ProcessStateRecord
的mCurProcState
都是在哪些情况下会设置有解释,
这个其实和adj调整有密不可分的关系,大部分逻辑也是在ADJ调整的时候设置了adj的值、adj的状态、还有进程状态mCurProcState
这三者一般都是密切相关的
这里先做一个记录
//frameworks\base\core\java\android\app\ProcessStateEnum.aidl
//各类进程状态,注意这个不是adj的值,是进程状态的值,
//一般情况越小代表进程状态优先级越高(但是有很多例外,
//如SERVICE、RECEIVER状态时优先级可以较高,先不要简单认为是绝对优先级)
enum ProcessStateEnum {
//PROCESS_STATE_UNKNOWN未知状态
UNKNOWN = -1,
//PROCESS_STATE_PERSISTENT常驻内存进程
//1. system_server系统服务,adj是SYSTEM_ADJ
//2. 没有界面的常驻进程会设置,此时adj是常驻进程PERSISTENT_PROC_ADJ级别
//3. service服务依赖:设置了BIND_ABOVE_CLIENT或者BIND_IMPORTANT,
//而且clinet的adj小于PERSISTENT_SERVICE_ADJ会设置,
//此时adj是常驻服务PERSISTENT_SERVICE_ADJ级别
//(也就是所谓的Persistent Service)
PERSISTENT = 0,
//PROCESS_STATE_PERSISTENT_UI带有界面的常驻内存进程
//目前只有常驻进程,且是当前topApp
//或者有hasTopUi(mHasTopUi==true,目前只有systemui通过AMS设置)
//或者getCachedHasVisibleActivities有可见的活动对象activity的时候,
//且(非睡眠状态)(或者播放远端动画时),才会设置
PERSISTENT_UI = 1,
//PROCESS_STATE_TOP当前最顶端top的activity,
//只有当前app时mTopApp(top的activity)而且非睡眠状态的时候才会设置为top
//PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp,
//这些状态需要从ActivityTaskManagerService获得
TOP = 2,
//PROCESS_STATE_BOUND_TOP绑定了前台进程
//1.service服务依赖:client时PROCESS_STATE_TOP状态的时候会设置
//2.provider依赖:client时PROCESS_STATE_TOP状态的时候会设置
BOUND_TOP = 3,
//PROCESS_STATE_FOREGROUND_SERVICE前台运行的服务,
//1.运行instrumentation(如自动化测试中,
//部分三方app也会使用(很少,有保活效果))的时候设置
//2.或者当其有前台运行的服务hasForegroundServices=true
//时会进行设置(这种情况时最普遍的情况),
//adj会设置成PERCEPTIBLE_APP_ADJ用户可感知的
FOREGROUND_SERVICE = 4,
//PROCESS_STATE_BOUND_FOREGROUND_SERVICE绑定了前台的进程
//(虽然说是服务,但是其实provider等也会设置该值)
//1.常驻进程如果是top app或者top ui的进程或者存在可见的activity,
//在唤醒时(如亮屏)设置是PROCESS_STATE_PERSISTENT_UI,
//休眠(如灭屏)且非播放远端动画时设置的就是BOUND_FOREGROUND_SERVICE
//2.service服务依赖:客户端的优先级比top还小,如系统服务和常驻进程,
//且设置了BIND_FOREGROUND_SERVICE
//或者唤醒时状态而且设置了BIND_FOREGROUND_SERVICE_WHILE_AWAKE时
//会设置BOUND_FOREGROUND_SERVICE
//3.provider依赖:客户端的状态优先级小于等于PROCESS_STATE_FOREGROUND_SERVICE,
//且客户端的状态非PROCESS_STATE_TOP(如果是TOP则设置
//PROCESS_STATE_BOUND_TOP)时设置BOUND_FOREGROUND_SERVICE
BOUND_FOREGROUND_SERVICE = 5,
//PROCESS_STATE_IMPORTANT_FOREGROUND重要的前台进程
//1.在mHasOverlayUi=true的时候(覆盖的界面),如mAppOverlaySurfaces存在,
//此时adj也是设置成PERCEPTIBLE_APP_ADJ用户可感知的
//2.service服务依赖:客户端的优先级比top还小,如系统服务和常驻进程,
//没有设置BIND_FOREGROUND_SERVICE/BIND_FOREGROUND_SERVICE_WHILE_AWAKE
//或者设置了BIND_FOREGROUND_SERVICE_WHILE_AWAKE但是在睡眠状态时
//会设置该值
//3.provider原因(自身非依赖):cpr.hasExternalProcessHandles为true,
//代表provider存在外部进程依赖的时候(如AMS的getContentProviderExternal
//调用时),会设置该值
IMPORTANT_FOREGROUND = 6,
//PROCESS_STATE_IMPORTANT_BACKGROUND重要的后台进程
//service服务依赖:如果设置了BIND_IMPORTANT_BACKGROUND(绑定重要后台)
//的时候,且客户端状态优先级小于该值时,会设置该值(目前只有该种情况)
IMPORTANT_BACKGROUND = 7,
//PROCESS_STATE_TRANSIENT_BACKGROUND后台临时的一个状态(一般的含义,
//如toasts)
//1.如果设置了getForcingToImportant不为null(调用AMS的setProcessImportant
//设置),会设置该状态,
//而且adj是用户可感知的PERCEPTIBLE_APP_ADJ,例如toasts是这种情况
//(NotificationManagerService中调用setProcessImportant)
//2.AMS的mBackupTargets是该app,且其adj大于BACKUP_APP_ADJ,会设置该值
//3.service服务依赖:如果设置了BIND_NOT_FOREGROUND(非前台绑定)
//而且没有设置BIND_IMPORTANT_BACKGROUND(绑定重要后台)的时候,
//且客户端状态优先级小于该值时,会设置该值
TRANSIENT_BACKGROUND = 8,
//AMS的mBackupTargets(备份的app)是该app,
//其状态最低优先级是PROCESS_STATE_BACKUP
BACKUP = 9,
//PROCESS_STATE_SERVICE处于服务状态的进程
//1.有正在执行任务exec-service的服务numberOfExecutingServices,
//此时adj是FOREGROUND_APP_ADJ前台
//2.运行的服务中startRequested启动请求的(started-services)
SERVICE = 10,
//PROCESS_STATE_RECEIVER
//在广播队列中存在接收者的时候getCachedIsReceivingBroadcast,
//此时adj是FOREGROUND_APP_ADJ前台
RECEIVER = 11,
//PROCESS_STATE_TOP_SLEEPING
//休眠时会将top app的状态设置成该值(如top-sleeping)、
//或者非top app在isRunningRemoteAnimation的时候且休眠的时候也会设置
TOP_SLEEPING = 12,
//PROCESS_STATE_HEAVY_WEIGHT重要的app
//当app无法保存状态,如AndroidManifest.xml设置了
//"android:cantSaveState="true",
//由于其无法保存状态,故尽量不要杀死,
//而且系统默认只有一个mHeavyWeightProcess,如果多个进程有类似的状态,
//那很可能是非原生修改),
//同时adj最小也是HEAVY_WEIGHT_APP_ADJ,adj类型时"heavy"
//同时系统配置了<feature name="android.software.cant_save_state" />
//这个feature
//默认是有FEATURE_CANT_SAVE_STATE这个feature的
//dumpsys package f | grep "cant_save_state"
HEAVY_WEIGHT = 13,
//PROCESS_STATE_HOME 桌面app
//如果是ActivityTaskManagerService中mHomeProcess,
//那么会设置这种状态
HOME = 14,
//PROCESS_STATE_LAST_ACTIVITY上一个启动的app
//1.如果是上一个activity在activityStopped(ActivityRecord中)之后
//RootWindowContainer中updatePreviousProcess会更新
//ActivityTaskManagerService的mPreviousProcess,
//adj类型是"previous",adj是PREVIOUS_APP_ADJ
//2.最近20s内使用的provider,adj类型是"recent-provider",
//adj是PREVIOUS_APP_ADJ
//3.正在停止的activity,OomAdjuster中
//onStoppingActivity(WindowProcessController会探查activity的情况),
//这个状态是activity正在停止,但是不是所有的allStoppingFinishing都停止了,
//才会设置,adj类型是stop-activity,看起来是临时状态
LAST_ACTIVITY = 15,
//PROCESS_STATE_CACHED_ACTIVITY 缓存activity
//1.WindowProcessController的computeOomAdjFromActivities中没有提取出
//activity状态, 则设置该状态,并设置adj类型为cch-act
//大致流程是computeOomAdjLSP(OomAdjuster)->
//computeOomAdjFromActivitiesIfNecessary(ProcessStateRecord)
//->computeOomAdjFromActivities(WindowProcessController)
//->onOtherActivity(OomAdjuster)
//2.service服务依赖:在service链接设置了BIND_TREAT_LIKE_ACTIVITY,
//服务端psr则设置setTreatLikeActivity的标记位,
//也就是服务端被认为是一个activity
//此时如果computeOomAdjLSP到后面都没有将procState提升到
//PROCESS_STATE_CACHED_EMPTY之上,那么就会设置这个状态,
//adj类型为"cch-as-act"
CACHED_ACTIVITY = 16,
//PROCESS_STATE_CACHED_ACTIVITY_CLIENT 缓存的client客户端,
//一般如果是服务的客户端包含activity才有可能设置这个状态
//hasClientActivities链接service的客户端中有Activity(ActiveServices的
//updateServiceClientActivitiesLocked中会设置),
//而且computeOomAdjLSP到后面都没有将procState提升到
//PROCESS_STATE_CACHED_EMPTY之上,那么就会设置这个状态
CACHED_ACTIVITY_CLIENT = 17,
//PROCESS_STATE_CACHED_RECENT 已经处于缓存状态,但是最近有启动过activity
//如果getCachedHasRecentTasks返回true(有activity在最近任务mRecentTasks
//中),那么最低状态就是设置这个,这个adj类型为"cch-rec"
//realStartActivityLocked(ActivityTaskSupervisor)
//->setProcess(ActivityRecord)
//->setRootProcess(Task.java没有设置FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS时)
//->addRecentTask(WindowProcessController)/mRecentTasks.add/
//mHasRecentTasks = true
CACHED_RECENT = 18,
//PROCESS_STATE_CACHED_EMPTY 空进程的状态,
//目前cached进程最常见的状态就是这个
//1. 默认adj调整时,如果是空进程则初始化成该状态PROCESS_STATE_CACHED_EMPTY
//2. 如果app.getThread() = null,没有ApplicationThread(应用线程),
//那么也就设置该状态
//3. service服务依赖:客户端client的状态大于等于
//PROCESS_STATE_CACHED_ACTIVITY(也就是优先级低于等于
//PROCESS_STATE_CACHED_ACTIVITY)时,
//服务端也会考虑设置成该状态(前提是前面没有更高优先的状态设置过)
//4. provider依赖:和service依赖一样,客户端client的状态大于等于
//PROCESS_STATE_CACHED_ACTIVITY(也就是优先级低于等于
//PROCESS_STATE_CACHED_ACTIVITY)时,
//本地端也会考虑设置成该状态(前提是前面没有更高优先的状态设置过)
CACHED_EMPTY = 19,
//PROCESS_STATE_NONEXISTENT 默认的初始化状态,
//在进程还未创建之前会是这种状态
//ProcessStateRecord中m***ProcState默认初始化的状态,
//下面是启动进程的时候的流程
//startProcessLocked(ProcessList.java)->
//在ProcessList的startProcess之前,会调用
//newProcessRecordLocked(ProcessList.java)
//-> new ProcessRecord -> new ProcessStateRecord
NONEXISTENT = 20,
}
上面说的system_server
、systemui
现在可以进一步说明一下,至于其进程状态也是类似的
system_server
的PER
代表PROCESS_STATE_PERSISTENT
状态: 一般是系统服务、没有界面的常驻进程、常驻进程服务Persistent Service
(可以动态启动和停止)
systemui
的PERU
代表PROCESS_STATE_PERSISTENT_UI
状态:常驻进程带有UI的时候(如下拉systemui的时候,systemui就会是这个状态)
其实systemui还经常出现下面2中状态
=> 不带界面的时候
PERS #45: pers F/ /
PER
LCMN t: 0 1484:com.android.systemui/u0a113 (fixed)
=> 灭屏幕后(从PERU
(锁屏界面是systemui的)切换到BFGS
(具体原因可以查看上面的BOUND_FOREGROUND_SERVICE
注释))
PERS #45: pers R/ /
BFGS
LCMN t: 0 1484:com.android.systemui/u0a113 (pers-top-ui)
4. 剩下的其它信息
如下面的全部信息,这些信息对于了解手机当时运行状态非常有帮助,包括了很多有用的信息,如:在mLruProcesses中的位置、adj、cgroup分组、是否有前台activity、进程状态、内存状态、进程能力、pid、uid、进程名字、依赖关系等
PERS #36: sys F/ /PER LCMN t:15 1421:system/1000 (fixed)
PERS #35: pers F/ /PER LCMN t:15 1729:com.android.systemui/u0a110 (fixed)
Proc # 0: fg T/A/TOP LCMN t:15 13122:com.taobao.taobao/u0a219 (top-activity)
Proc #20: psvc F/ /PER LCMN t:15 3194:com.google.android.providers.media.module/u0a212 (service) com.google.android.providers.media.module/com.android.providers.media.fuse.ExternalStorageServiceImpl<=Proc{1421:system/1000}
Proc #12: cch+ 5 b/ /CEM ---- t:80 12971:com.eg.android.AlipayGphone:tools/u0a221 (cch-empty)
这里再来说一下上面的全部意思吧,
1、" “是:传入dumpProcessOomList的” “,用于对齐
2、PERS
或者Proc
:如果是常驻进程则是"PERS”,非常驻进程则是"Proc"
3、#36:
:代表原有mLruProcesses的序列值,如一共37个应用,数组下标从0到36,此处36代表其是mLruProcesses的第0个元素
4、fg
或者cch+ 5
等:代表adj值,fg代表adj = 0,cch+ 5代表adj = 905,具体请查看ProcessList的makeOomAdjString
5、T/A/TOP
等:第一个T代表cgroup分组是SCHED_GROUP_TOP_APP(top app), 第二个A代表hasForegroundActivities拥有前台activity,第三个TOP就是我们之前说的进程状态ProcState
6、LCMN
:进程可以拥有定位、camara、打电话、网络的能力(注意这里是可以拥有),具体请查看printCapabilitiesSummary
7、t:15
:当前进程的mTrimMemoryLevel,15代表ComponentCallbacks2的TRIM_MEMORY_RUNNING_CRITICAL,内存已经比较紧张了,该值用于回收内存和标定当前内存紧张程度
8、1421
: 代表进程号,具体查看ProcessRecord的toShortString
9、system
: 代表进程名字,具体查看ProcessRecord的toShortString
10、1000或者u0a110
: 代表进程的uid,具体查看ProcessRecord的toShortString
11、top-activity
: 代表adj的类型mAdjType
12、com.google.android.providers.media.module/com.android.providers.media.fuse.ExternalStorageServiceImpl<=Proc{1421:system/1000}
:
代表adj依赖关系调整时的调整对象state.getAdjTarget()
<= 调整原因state.getAdjSource()
,
如这里的调整对象是ExternalStorageServiceImpl
,调整原因是system
去绑定了这个服务
具体代码逻辑如下 =>
//ProcessList.java
public static String makeOomAdjString(int setAdj, boolean compact) {
if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
return buildOomTag("cch", "cch", " ", setAdj,
ProcessList.CACHED_APP_MIN_ADJ, compact);
} else if (setAdj >= ProcessList.SERVICE_B_ADJ) {
return buildOomTag("svcb ", "svcb", null, setAdj,
ProcessList.SERVICE_B_ADJ, compact);
} else if (setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
return buildOomTag("prev ", "prev", null, setAdj,
ProcessList.PREVIOUS_APP_ADJ, compact);
} else if (setAdj >= ProcessList.HOME_APP_ADJ) {
return buildOomTag("home ", "home", null, setAdj,
ProcessList.HOME_APP_ADJ, compact);
} else if (setAdj >= ProcessList.SERVICE_ADJ) {
return buildOomTag("svc ", "svc", null, setAdj,
ProcessList.SERVICE_ADJ, compact);
} else if (setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
return buildOomTag("hvy ", "hvy", null, setAdj,
ProcessList.HEAVY_WEIGHT_APP_ADJ, compact);
} else if (setAdj >= ProcessList.BACKUP_APP_ADJ) {
return buildOomTag("bkup ", "bkup", null, setAdj,
ProcessList.BACKUP_APP_ADJ, compact);
} else if (setAdj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
return buildOomTag("prcl ", "prcl", null, setAdj,
ProcessList.PERCEPTIBLE_LOW_APP_ADJ, compact);
} else if (setAdj >= ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ) {
return buildOomTag("prcm ", "prcm", null, setAdj,
ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ, compact);
} else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
return buildOomTag("prcp ", "prcp", null, setAdj,
ProcessList.PERCEPTIBLE_APP_ADJ, compact);
} else if (setAdj >= ProcessList.VISIBLE_APP_ADJ) {
return buildOomTag("vis", "vis", " ", setAdj,
ProcessList.VISIBLE_APP_ADJ, compact);
} else if (setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
return buildOomTag("fg ", "fg ", " ", setAdj,
ProcessList.FOREGROUND_APP_ADJ, compact);
} else if (setAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
return buildOomTag("psvc ", "psvc", null, setAdj,
ProcessList.PERSISTENT_SERVICE_ADJ, compact);
} else if (setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
return buildOomTag("pers ", "pers", null, setAdj,
ProcessList.PERSISTENT_PROC_ADJ, compact);
} else if (setAdj >= ProcessList.SYSTEM_ADJ) {
return buildOomTag("sys ", "sys", null, setAdj,
ProcessList.SYSTEM_ADJ, compact);
} else if (setAdj >= ProcessList.NATIVE_ADJ) {
return buildOomTag("ntv ", "ntv", null, setAdj,
ProcessList.NATIVE_ADJ, compact);
} else {
return Integer.toString(setAdj);
}
}
private static boolean dumpProcessOomList(PrintWriter pw,
ActivityManagerService service, List<ProcessRecord> origList,
String prefix, String normalLabel, String persistentLabel,
boolean inclDetails, String dumpPackage) {
ArrayList<Pair<ProcessRecord, Integer>> list = sortProcessOomList(origList, dumpPackage);
if (list.isEmpty()) return false;
final long curUptime = SystemClock.uptimeMillis();
final long uptimeSince = curUptime - service.mLastPowerCheckUptime;
for (int i = list.size() - 1; i >= 0; i--) {
ProcessRecord r = list.get(i).first;
final ProcessStateRecord state = r.mState;
final ProcessServiceRecord psr = r.mServices;
String oomAdj = makeOomAdjString(state.getSetAdj(), false);
char schedGroup;
switch (state.getSetSchedGroup()) {
case SCHED_GROUP_BACKGROUND:
schedGroup = 'b';
break;
case SCHED_GROUP_DEFAULT:
schedGroup = 'F';
break;
case SCHED_GROUP_TOP_APP:
schedGroup = 'T';
break;
case SCHED_GROUP_RESTRICTED:
schedGroup = 'R';
break;
case SCHED_GROUP_TOP_APP_BOUND:
schedGroup = 'B';
break;
default:
schedGroup = '?';
break;
}
char foreground;
if (state.hasForegroundActivities()) {
foreground = 'A';
} else if (psr.hasForegroundServices()) {
foreground = 'S';
} else {
foreground = ' ';
}
String procState = makeProcStateString(state.getCurProcState());
pw.print(prefix);
pw.print(r.isPersistent() ? persistentLabel : normalLabel);
pw.print(" #");
int num = (origList.size() - 1) - list.get(i).second;
if (num < 10) pw.print(' ');
pw.print(num);
pw.print(": ");
pw.print(oomAdj);
pw.print(' ');
pw.print(schedGroup);
pw.print('/');
pw.print(foreground);
pw.print('/');
pw.print(procState);
pw.print(' ');
ActivityManager.printCapabilitiesSummary(pw, state.getCurCapability());
pw.print(' ');
pw.print(" t:");
if (r.mProfile.getTrimMemoryLevel() < 10) pw.print(' ');
pw.print(r.mProfile.getTrimMemoryLevel());
pw.print(' ');
pw.print(r.toShortString());
pw.print(" (");
pw.print(state.getAdjType());
pw.println(')');
if (state.getAdjSource() != null || state.getAdjTarget() != null) {
pw.print(prefix);
pw.print(" ");
if (state.getAdjTarget() instanceof ComponentName) {
pw.print(((ComponentName) state.getAdjTarget()).flattenToShortString());
} else if (state.getAdjTarget() != null) {
pw.print(state.getAdjTarget().toString());
} else {
pw.print("{null}");
}
pw.print("<=");
if (state.getAdjSource() instanceof ProcessRecord) {
pw.print("Proc{");
pw.print(((ProcessRecord) state.getAdjSource()).toShortString());
pw.println("}");
} else if (state.getAdjSource() != null) {
pw.println(state.getAdjSource().toString());
} else {
pw.println("{null}");
}
}
if (inclDetails) {
pw.print(prefix);
pw.print(" ");
pw.print("oom: max="); pw.print(state.getMaxAdj());
pw.print(" curRaw="); pw.print(state.getCurRawAdj());
pw.print(" setRaw="); pw.print(state.getSetRawAdj());
pw.print(" cur="); pw.print(state.getCurAdj());
pw.print(" set="); pw.println(state.getSetAdj());
pw.print(prefix);
pw.print(" ");
pw.print("state: cur="); pw.print(makeProcStateString(state.getCurProcState()));
pw.print(" set="); pw.print(makeProcStateString(state.getSetProcState()));
pw.print(" lastPss=");
DebugUtils.printSizeValue(pw, r.mProfile.getLastPss() * 1024);
pw.print(" lastSwapPss=");
DebugUtils.printSizeValue(pw, r.mProfile.getLastSwapPss() * 1024);
pw.print(" lastCachedPss=");
DebugUtils.printSizeValue(pw, r.mProfile.getLastCachedPss() * 1024);
pw.println();
pw.print(prefix);
pw.print(" ");
pw.print("cached="); pw.print(state.isCached());
pw.print(" empty="); pw.print(state.isEmpty());
pw.print(" hasAboveClient="); pw.println(psr.hasAboveClient());
if (state.getSetProcState() >= ActivityManager.PROCESS_STATE_SERVICE) {
long lastCpuTime = r.mProfile.mLastCpuTime.get();
if (lastCpuTime != 0 && uptimeSince > 0) {
long timeUsed = r.mProfile.mCurCpuTime.get() - lastCpuTime;
pw.print(prefix);
pw.print(" ");
pw.print("run cpu over ");
TimeUtils.formatDuration(uptimeSince, pw);
pw.print(" used ");
TimeUtils.formatDuration(timeUsed, pw);
pw.print(" (");
pw.print((timeUsed * 100) / uptimeSince);
pw.println("%)");
}
}
}
}
return true;
}
//ActivityManager.java
public static void printCapabilitiesSummary(PrintWriter pw, @ProcessCapability int caps) {
pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0 ? 'L' : '-');
pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0 ? 'C' : '-');
pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-');
pw.print((caps & PROCESS_CAPABILITY_NETWORK) != 0 ? 'N' : '-');
}
//ComponentCallbacks2.java
/**
* Level for {@link #onTrimMemory(int)}: the process is nearing the end
* of the background LRU list, and if more memory isn't found soon it will
* be killed.
*/
static final int TRIM_MEMORY_COMPLETE = 80;
/**
* Level for {@link #onTrimMemory(int)}: the process is around the middle
* of the background LRU list; freeing memory can help the system keep
* other processes running later in the list for better overall performance.
*/
static final int TRIM_MEMORY_MODERATE = 60;
/**
* Level for {@link #onTrimMemory(int)}: the process has gone on to the
* LRU list. This is a good opportunity to clean up resources that can
* efficiently and quickly be re-built if the user returns to the app.
*/
static final int TRIM_MEMORY_BACKGROUND = 40;
/**
* Level for {@link #onTrimMemory(int)}: the process had been showing
* a user interface, and is no longer doing so. Large allocations with
* the UI should be released at this point to allow memory to be better
* managed.
*/
static final int TRIM_MEMORY_UI_HIDDEN = 20;
/**
* Level for {@link #onTrimMemory(int)}: the process is not an expendable
* background process, but the device is running extremely low on memory
* and is about to not be able to keep any background processes running.
* Your running process should free up as many non-critical resources as it
* can to allow that memory to be used elsewhere. The next thing that
* will happen after this is {@link #onLowMemory()} called to report that
* nothing at all can be kept in the background, a situation that can start
* to notably impact the user.
*/
static final int TRIM_MEMORY_RUNNING_CRITICAL = 15;
/**
* Level for {@link #onTrimMemory(int)}: the process is not an expendable
* background process, but the device is running low on memory.
* Your running process should free up unneeded resources to allow that
* memory to be used elsewhere.
*/
static final int TRIM_MEMORY_RUNNING_LOW = 10;
/**
* Level for {@link #onTrimMemory(int)}: the process is not an expendable
* background process, but the device is running moderately low on memory.
* Your running process may want to release some unneeded resources for
* use elsewhere.
*/
static final int TRIM_MEMORY_RUNNING_MODERATE = 5;
//ProcessRecord.java
public String toShortString() {
final String shortStringName = mShortStringName;
if (shortStringName != null) {
return shortStringName;
}
StringBuilder sb = new StringBuilder(128);
toShortString(sb);
return mShortStringName = sb.toString();
}
void toShortString(StringBuilder sb) {
sb.append(mPid);
sb.append(':');
sb.append(processName);
sb.append('/');
if (info.uid < Process.FIRST_APPLICATION_UID) {
sb.append(uid);
} else {
sb.append('u');
sb.append(userId);
int appId = UserHandle.getAppId(info.uid);
if (appId >= Process.FIRST_APPLICATION_UID) {
sb.append('a');
sb.append(appId - Process.FIRST_APPLICATION_UID);
} else {
sb.append('s');
sb.append(appId);
}
if (uid != info.uid) {
sb.append('i');
sb.append(UserHandle.getAppId(uid) - Process.FIRST_ISOLATED_UID);
}
}
}