Process Management in Android and process management in Android
Reprinted please indicate the source:
Http://blog.csdn.net/yujun411522/article/details/46682687
This article is from: [yujun411522 blog]
In android, the concept of process has been deprecated. We know that every Android application runs in an independent DVM, and they do not affect each other. After the application exits, the process is not killed immediately and remains in the memory. The purpose of this operation is to speed up the next startup. In Android, the module used to manage processes is AMS, which mainly includes LRU weight, OOM adj, and Low Memory Killer to manage processes.
1 LRU weightLRU (least recently used) weight is mainly used to measure the LRU weight. After the android process is started, an instance is created in ProcessRecord type and saved to the mLruProcesses variable of AMS, mLurProcesses stores process information in the LRU order. Update mLruProcesses: 1. the application exits unexpectedly. 2. call AMS to explicitly kill the process. 3. the four major components of START and schedule are taken as an example. It will call the updateLruProcessLock method of AMS:
Final void updateLruProcessLocked (ProcessRecord app, boolean oomAdj, boolean updateActivityTime) {mLruSeq ++; // lru serial number plus updateLruProcessInternalLocked (app, oomAdj, updateActivityTime, 0 );}
First, add the LRU serial number to mark an operation to update the LRU, and then call updateLruProcessInternalLocked:
Private final void updateLruProcessInternalLocked (ProcessRecord app, boolean oomAdj, boolean updateActivityTime, int bestPos) {// put it on the LRU to keep track of when it shoshould be exited. int lrui = mLruProcesses. indexOf (app); if (lrui> = 0) mLruProcesses. remove (lrui); int I = mLruProcesses. size ()-1; int skipTop = 0; app. lruSeq = mLruSeq; // compute the new weight for this process. if (updateAc TivityTime) {app. lastActivityTime = SystemClock. uptimeMillis ();} if (app. activities. size ()> 0) {// If this process has activities, we more stronugly want to keep // it around. app. lruWeight = app. lastActivityTime;} else if (app. pubProviders. size ()> 0) {// If this process contains content providers, we want to keep // it a little more strongly. app. lruWeight = app. lastActivityTime-ProcessLi St. CONTENT_APP_IDLE_OFFSET; // Also don't let it kick out the first few "real" hidden processes. skipTop = ProcessList. MIN_HIDDEN_APPS;} else {// If this process doesn't have activities, we less stronugly // want to keep it around, and generally want to avoid getting // in front of any very recently used activities. app. lruWeight = app. lastActivityTime-ProcessList. EMPTY_APP_IDLE_OFFSET; // Also Don't let it kick out the first few "real" hidden processes. skipTop = ProcessList. MIN_HIDDEN_APPS;} while (I> = 0) {ProcessRecord p = mLruProcesses. get (I); // If this app shouldn't be in front of the first N background // apps, then skip over that parameter that are currently hidden. if (skipTop> 0 & p. setAdj> = ProcessList. HIDDEN_APP_MIN_ADJ) {skipTop --;} if (p. lruWeight <= app. lruWeight | I <BestPos) {mLruProcesses. add (I + 1, app); // add to the appropriate position of mLruProcesses break;} I --;} if (I <0) {mLruProcesses. add (0, app);} // If the process is followed by a cotent provider or Service, re-calculate the // If the app is currently using a content provider or service, // bump those processes as well. if (app. connections. size ()> 0) {for (ConnectionRecord cr: app. connections) {if (cr. binding! = Null & cr. binding. service! = Null & cr. binding. service. app! = Null & cr. binding. service. app. lruSeq! = MLruSeq) {updateLruProcessInternalLocked (cr. binding. service. app, oomAdj, updateActivityTime, I + 1) ;}} if (app. conProviders. size ()> 0) {for (ContentProviderRecord cpr: app. conProviders. keySet () {if (cpr. proc! = Null & cpr. proc. lruSeq! = MLruSeq) {updateLruProcessInternalLocked (cpr. proc, oomAdj, updateActivityTime, I + 1) ;}}if (oomAdj) {updateOomAdjLocked (); Call updateOomAdjLocked to update oom value }}
This function is mainly used. calculate the LRU serial number and LRU weight2. based on the calculated LRU weight, insert the process information to the appropriate location of mLRUProcesses. 3. if the content provider or service exists in the process, recalculate LRU weight4. determine whether to call the updateOomAdjLocked function to update the oom value.
Until the end of updateLruProcessLocked, we can see that this function only adjusts the LRU weight of the process and its location in mLruProcesses. it is not directly involved in process management. The updateOomAdjLocked function is actually involved in process management, this function is used to update the oom adj value, which affects process recycling.
2 OOM adjOOM adj defines a series of OOM adjustment levels, from-17 to 15. We have already introduced the Low Memory Killer mechanism. here we can see that 13 adjustment levels are defined in Android. In the ProcessList file
class ProcessList { // OOM adjustments for processes in various states: // This is a process without anything currently running in it. Definitely // the first to go! Value set in system/rootdir/init.rc on startup. // This value is initalized in the constructor, careful when refering to // this static variable externally. static final int EMPTY_APP_ADJ = 15; // This is a process only hosting activities that are not visible, // so it can be killed without any disruption. Value set in // system/rootdir/init.rc on startup. static final int HIDDEN_APP_MAX_ADJ = 15; static int HIDDEN_APP_MIN_ADJ = 7; // This is a process holding the home application -- we want to try // avoiding killing it, even if it would normally be in the background, // because the user interacts with it so much. static final int HOME_APP_ADJ = 6; // This is a process holding a secondary server -- killing it will not // have much of an impact as far as the user is concerned. Value set in // system/rootdir/init.rc on startup. static final int SECONDARY_SERVER_ADJ = 5; // This is a process currently hosting a backup operation. Killing it // is not entirely fatal but is generally a bad idea. static final int BACKUP_APP_ADJ = 4; // This is a process with a heavy-weight application. It is in the // background, but we want to try to avoid killing it. Value set in // system/rootdir/init.rc on startup. static final int HEAVY_WEIGHT_APP_ADJ = 3; // This is a process only hosting components that are perceptible to the // user, and we really want to avoid killing them, but they are not // immediately visible. An example is background music playback. Value set in // system/rootdir/init.rc on startup. static final int PERCEPTIBLE_APP_ADJ = 2; // This is a process only hosting activities that are visible to the // user, so we'd prefer they don't disappear. Value set in // system/rootdir/init.rc on startup. static final int VISIBLE_APP_ADJ = 1; // This is the process running the current foreground app. We'd really // rather not kill it! Value set in system/rootdir/init.rc on startup. static final int FOREGROUND_APP_ADJ = 0; // This is a process running a core server, such as telephony. Definitely // don't want to kill it, but doing so is not completely fatal. static final int CORE_SERVER_ADJ = -12; // The system process runs at the default adjustment. static final int SYSTEM_ADJ = -16; .....}
AMS provides a function to change this value: updateOomAdjLocked
Final void updateOomAdjLocked () {final ActivityRecord TOP_ACT = resumedAppLocked (); final ProcessRecord TOP_APP = TOP_ACT! = Null? TOP_ACT.app: null; if (false) {RuntimeException e = new RuntimeException (); e. fillInStackTrace (); Slog. I (TAG, "updateOomAdj: top =" + TOP_ACT, e);} mAdjSeq ++; // Let's determine how many processes we have running. // how many slots we have for background processes; we may want // to put multiple processes in a slot of there are enough of // them. int numSlots = ProcessList. HIDDEN_APP_MAX_ADJ -ProcessList. HIDDEN_APP_MIN_ADJ + 1; int factor = (mLruProcesses. size ()-4)/numSlots; if (factor <1) factor = 1; int step = 0; int numHidden = 0; // First update the OOM adjustment for each of the // application processes based on their current state. int I = mLruProcesses. size (); int curHiddenAdj = ProcessList. HIDDEN_APP_MIN_ADJ; int numBg = 0; while (I> 0) {I --; ProcessRecord app = mLruProces Ses. get (I); // Slog. I (TAG, "OOM" + app + ": cur hidden =" + curHiddenAdj); // call the overload function updateOomAdjLocked to update the OOM adj value updateOomAdjLocked (app, curHiddenAdj, TOP_APP); if (curHiddenAdj <ProcessList. EMPTY_APP_ADJ & app. curAdj = curHiddenAdj) {step ++; if (step >=factor) {step = 0; curHiddenAdj ++ ;}} if (! App. killedBackground) {// if the value of adj is greater than or equal to ProcessList. HIDDEN_APP_MIN_ADJ if (app. curAdj> = ProcessList. HIDDEN_APP_MIN_ADJ) {numHidden ++; if (numHidden> mProcessLimit) {Slog. I (TAG, "No longer want" + app. processName + "(pid" + app. pid + "): hidden #" + numHidden); EventLog. writeEvent (EventLogTags. AM_KILL, app. pid, app. processName, app. setAdj, "too your background"); app. killedBackground = true; Process. killProcessQuiet (app. pid); // kill the process} else {numBg ++;} else if (app. curAdj> = ProcessList. HOME_APP_ADJ) {numBg ++ ;}}}......}
The overload function updateOomAdjLocked is called. The Code is as follows:
Private final boolean updateOomAdjLocked (ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {app. hiddenAdj = hiddenAdj; if (app. thread = null) {return false;} final boolean wasKeeping = app. keeping; boolean success = true; // 1 call the computeOomAdjLocked method to calculate the oom adj value computeOomAdjLocked (app, hiddenAdj, TOP_APP, false); if (app. curRawAdj! = App. setRawAdj) {if (false) {// Removing for now. forcing GCs is not so useful anymore // with Dalvik, and the new memory level hint facility is // better for what we need to do these days. if (app. curRawAdj> ProcessList. FOREGROUND_APP_ADJ & app. setRawAdj <= ProcessList. FOREGROUND_APP_ADJ) {// If this app is transitioning from foreground to // non-foreground, have it do a gc. scheduleAppGcLoc Ked (app);} else if (app. curRawAdj> = ProcessList. HIDDEN_APP_MIN_ADJ & app. setRawAdj <ProcessList. HIDDEN_APP_MIN_ADJ) {// Likewise do a gc when an app is moving in to the // background (such as a service stopping ). scheduleAppGcLocked (app) ;}} if (wasKeeping &&! App. keeping) {// This app is no longer something we want to keep. note // its current wake lock time to later know to kill it if // it is not behaving well. batteryStatsImpl stats = mBatteryStatsService. getActiveStatistics (); synchronized (stats) {app. lastWakeTime = stats. getProcessWakeTime (app.info. uid, app. pid, SystemClock. elapsedRealtime ();} app. lastCpuTime = app. curCpuTime;} app. setRawAdj = App. curRawAdj;} if (app. curAdj! = App. setAdj) {// 2 call setOomAdj to modify the oom adj value of the Process if (Process. setOomAdj (app. pid, app. curAdj) {if (DEBUG_SWITCH | DEBUG_OOM_ADJ) Slog. v (TAG, "Set app" + app. processName + "oom adj to" + app. curAdj + "because" + app. adjType); app. setAdj = app. curAdj;} else {success = false; Slog. w (TAG, "Failed setting oom adj of" + app + "to" + app. curAdj) ;}} if (app. setSchedGroup! = App. curSchedGroup) {app. setSchedGroup = app. curSchedGroup; if (DEBUG_SWITCH | DEBUG_OOM_ADJ) Slog. v (TAG, "Setting process group of" + app. processName + "to" + app. curSchedGroup); if (app. waitingToKill! = Null & app. setSchedGroup = Process. THREAD_GROUP_BG_NONINTERACTIVE) {Slog. I (TAG, "Killing" + app. tow.string () + ":" + app. waitingToKill); EventLog. writeEvent (EventLogTags. AM_KILL, app. pid, app. processName, app. setAdj, app. waitingToKill); // 3 call killProcessQuiet to kill the Process. killProcessQuiet (app. pid); success = false;} else {if (true) {long oldId = Binder. clearCallingIdentity (); try {// 4. Call setProcessGroup to modify the scheduling group Process of the Process. setProcessGroup (app. pid, app. curSchedGroup);} catch (Exception e) {Slog. w (TAG, "Failed setting process group of" + app. pid + "to" + app. curSchedGroup); e. printStackTrace ();} finally {Binder. restoreCallingIdentity (oldId) ;}} else {if (app. thread! = Null) {try {app. thread. setSchedulingGroup (app. curSchedGroup);} catch (RemoteException e) {}}} return success ;}
The updateOomAdjLocked function updates the OOM adj value. The main tasks of this Part are: 1. call the computeOomAdjLocked method to calculate the oom embedded value. This function is complex. Through a series of operations, the oom embedded value is calculated. call setOomAdj to modify the oom adj value of the process. This function is used to write the calculated oom adj value to the/proc/<pid>/oom_adj file of the process. 3. call killProcessQuiet to kill the process. 4. call setProcessGroup to modify the scheduling Group of the Process. Here we mainly look at Step 3 killProcessQuiet. This function is in Process. in the java file:
public static final void killProcessQuiet(int pid) { sendSignalQuiet(pid, SIGNAL_KILL); }
The sendSignalQuiet function is called. This is a native function:
public static final native void sendSignalQuiet(int pid, int signal);
The corresponding implementation is in the android_util_Process.cpp file:
Void android_ OS _Process_sendSignalQuiet (JNIEnv * env, jobject clazz, jint pid, jint sig) {if (pid> 0) {kill (pid, sig); // kill process }}
So far, the process has been killed. This method directly kills the process. Similarly, android also provides a mechanism to passively kill the process. Low Memory Killer
3 Low Memory Killer mechanism the main idea of this mechanism is to define different oom adj levels and specify the minimum residual threshold for each level. When the available Memory in the Memory is less than this threshold, all processes equal to or greater than this threshold will be killed. For more information, see Low Memory Killer mechanism.
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.