Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 906497c5 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Hopefully fix issue #2662536: Why is launcher being killed?

It looks like there was a subtle bug where Process.setOomAdj() could
return false just because the given process doesn't exist, even though
it is documented to only return false if OOM killing is not supported
at all.  This would cause the activity manager to fall into its code
path of trying to clean up processes itself, which it does a much
poorer problem at.  I am thinking we may be seeing this problem more
now that the activity manager is killing background processes itself
when there are too many of them.

In addition, this change cleans up and reduces some of the logging
around killing processes.

Finally, try to improve process LRU management a bit by taking
into account process dependencies.  Any dependent processes are
pulled up in the LRU list with the processes that is actually
moving.  Also, we bring a process up if someone accesses its content
provider.

Change-Id: I34ea161f839679345578ffe681e8d9c5d26ab948
parent 639a7fc2
Loading
Loading
Loading
Loading
+18 −0
Original line number Original line Diff line number Diff line
@@ -747,6 +747,24 @@ public class Process {
     */
     */
    public static final native void sendSignal(int pid, int signal);
    public static final native void sendSignal(int pid, int signal);
    
    
    /**
     * @hide
     * Private impl for avoiding a log message...  DO NOT USE without doing
     * your own log, or the Android Illuminati will find you some night and
     * beat you up.
     */
    public static final void killProcessQuiet(int pid) {
        sendSignalQuiet(pid, SIGNAL_KILL);
    }

    /**
     * @hide
     * Private impl for avoiding a log message...  DO NOT USE without doing
     * your own log, or the Android Illuminati will find you some night and
     * beat you up.
     */
    public static final native void sendSignalQuiet(int pid, int signal);
    
    /** @hide */
    /** @hide */
    public static final native long getFreeMemory();
    public static final native long getFreeMemory();
    
    
+9 −1
Original line number Original line Diff line number Diff line
@@ -311,8 +311,8 @@ jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
            sprintf(text, "%d", adj);
            sprintf(text, "%d", adj);
            write(fd, text, strlen(text));
            write(fd, text, strlen(text));
            close(fd);
            close(fd);
            return true;
        }
        }
        return true;
    }
    }
#endif
#endif
    return false;
    return false;
@@ -797,6 +797,13 @@ void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint si
    }
    }
}
}


void android_os_Process_sendSignalQuiet(JNIEnv* env, jobject clazz, jint pid, jint sig)
{
    if (pid > 0) {
        kill(pid, sig);
    }
}

static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
{
{
    struct timespec ts;
    struct timespec ts;
@@ -854,6 +861,7 @@ static const JNINativeMethod methods[] = {
    {"setUid", "(I)I", (void*)android_os_Process_setUid},
    {"setUid", "(I)I", (void*)android_os_Process_setUid},
    {"setGid", "(I)I", (void*)android_os_Process_setGid},
    {"setGid", "(I)I", (void*)android_os_Process_setGid},
    {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
    {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
    {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
    {"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
    {"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
    {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
    {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
    {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
    {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
+60 −15
Original line number Original line Diff line number Diff line
@@ -321,12 +321,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
    static final int MAX_HIDDEN_APPS = 15;
    static final int MAX_HIDDEN_APPS = 15;
    
    
    // We put empty content processes after any hidden processes that have
    // We put empty content processes after any hidden processes that have
    // been idle for less than 30 seconds.
    // been idle for less than 15 seconds.
    static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
    static final long CONTENT_APP_IDLE_OFFSET = 15*1000;
    
    
    // We put empty content processes after any hidden processes that have
    // We put empty content processes after any hidden processes that have
    // been idle for less than 60 seconds.
    // been idle for less than 120 seconds.
    static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
    static final long EMPTY_APP_IDLE_OFFSET = 120*1000;
    
    
    static {
    static {
        // These values are set in system/rootdir/init.rc on startup.
        // These values are set in system/rootdir/init.rc on startup.
@@ -879,6 +879,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
     */
     */
    int mAdjSeq = 0;
    int mAdjSeq = 0;
    /**
     * Current sequence id for process LRU updating.
     */
    int mLruSeq = 0;
    
    /**
    /**
     * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
     * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
     * is set, indicating the user wants processes started in such a way
     * is set, indicating the user wants processes started in such a way
@@ -1588,8 +1593,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
        }
        }
    }
    }
    private final void updateLruProcessLocked(ProcessRecord app,
    private final void updateLruProcessInternalLocked(ProcessRecord app,
            boolean oomAdj, boolean updateActivityTime) {
            boolean oomAdj, boolean updateActivityTime, int bestPos) {
        // put it on the LRU to keep track of when it should be exited.
        // put it on the LRU to keep track of when it should be exited.
        int lrui = mLruProcesses.indexOf(app);
        int lrui = mLruProcesses.indexOf(app);
        if (lrui >= 0) mLruProcesses.remove(lrui);
        if (lrui >= 0) mLruProcesses.remove(lrui);
@@ -1597,6 +1602,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
        int i = mLruProcesses.size()-1;
        int i = mLruProcesses.size()-1;
        int skipTop = 0;
        int skipTop = 0;
        
        
        app.lruSeq = mLruSeq;
        
        // compute the new weight for this process.
        // compute the new weight for this process.
        if (updateActivityTime) {
        if (updateActivityTime) {
            app.lastActivityTime = SystemClock.uptimeMillis();
            app.lastActivityTime = SystemClock.uptimeMillis();
@@ -1619,6 +1626,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
            // Also don't let it kick out the first few "real" hidden processes.
            // Also don't let it kick out the first few "real" hidden processes.
            skipTop = MIN_HIDDEN_APPS;
            skipTop = MIN_HIDDEN_APPS;
        }
        }
        
        while (i >= 0) {
        while (i >= 0) {
            ProcessRecord p = mLruProcesses.get(i);
            ProcessRecord p = mLruProcesses.get(i);
            // If this app shouldn't be in front of the first N background
            // If this app shouldn't be in front of the first N background
@@ -1626,7 +1634,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
            if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
            if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
                skipTop--;
                skipTop--;
            }
            }
            if (p.lruWeight <= app.lruWeight){
            if (p.lruWeight <= app.lruWeight || i < bestPos) {
                mLruProcesses.add(i+1, app);
                mLruProcesses.add(i+1, app);
                break;
                break;
            }
            }
@@ -1636,12 +1644,39 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
            mLruProcesses.add(0, app);
            mLruProcesses.add(0, app);
        }
        }
        
        
        // 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.app != null && cpr.app.lruSeq != mLruSeq) {
                    updateLruProcessInternalLocked(cpr.app, oomAdj,
                            updateActivityTime, i+1);
                }
            }
        }
        
        //Slog.i(TAG, "Putting proc to front: " + app.processName);
        //Slog.i(TAG, "Putting proc to front: " + app.processName);
        if (oomAdj) {
        if (oomAdj) {
            updateOomAdjLocked();
            updateOomAdjLocked();
        }
        }
    }
    }
    private final void updateLruProcessLocked(ProcessRecord app,
            boolean oomAdj, boolean updateActivityTime) {
        mLruSeq++;
        updateLruProcessInternalLocked(app, oomAdj, updateActivityTime, 0);
    }
    
    private final boolean updateLRUListLocked(HistoryRecord r) {
    private final boolean updateLRUListLocked(HistoryRecord r) {
        final boolean hadit = mLRUActivities.remove(r);
        final boolean hadit = mLRUActivities.remove(r);
        mLRUActivities.add(r);
        mLRUActivities.add(r);
@@ -4677,8 +4712,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
        // Clean up already done if the process has been re-started.
        // Clean up already done if the process has been re-started.
        if (app.pid == pid && app.thread != null &&
        if (app.pid == pid && app.thread != null &&
                app.thread.asBinder() == thread.asBinder()) {
                app.thread.asBinder() == thread.asBinder()) {
            if (!app.killedBackground) {
                Slog.i(TAG, "Process " + app.processName + " (pid " + pid
                Slog.i(TAG, "Process " + app.processName + " (pid " + pid
                        + ") has died.");
                        + ") has died.");
            }
            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
            if (localLOGV) Slog.v(
            if (localLOGV) Slog.v(
                TAG, "Dying app: " + app + ", pid: " + pid
                TAG, "Dying app: " + app + ", pid: " + pid
@@ -7826,6 +7863,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
                }
                }
                if (cpr.app != null) {
                if (cpr.app != null) {
                    if (r.setAdj >= VISIBLE_APP_ADJ) {
                        // If this is a visible app accessing the provider,
                        // make sure to count it as being accessed and thus
                        // back up on the LRU list.  This is good because
                        // content providers are often expensive to start.
                        updateLruProcessLocked(cpr.app, false, true);
                    }
                    updateOomAdjLocked(cpr.app);
                    updateOomAdjLocked(cpr.app);
                }
                }
@@ -8492,12 +8536,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
                    continue;
                    continue;
                }
                }
                int adj = proc.setAdj;
                int adj = proc.setAdj;
                if (adj >= worstType) {
                if (adj >= worstType && !proc.killedBackground) {
                    Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
                    Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
                    EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
                    EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
                            proc.processName, adj, reason);
                            proc.processName, adj, reason);
                    killed = true;
                    killed = true;
                    Process.killProcess(pids[i]);
                    proc.killedBackground = true;
                    Process.killProcessQuiet(pids[i]);
                }
                }
            }
            }
        }
        }
@@ -9829,6 +9874,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
                    + " mFactoryTest=" + mFactoryTest);
                    + " mFactoryTest=" + mFactoryTest);
            pw.println("  mGoingToSleep=" + mGoingToSleep);
            pw.println("  mGoingToSleep=" + mGoingToSleep);
            pw.println("  mLaunchingActivity=" + mLaunchingActivity);
            pw.println("  mLaunchingActivity=" + mLaunchingActivity);
            pw.println("  mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq);
        }
        }
        
        
        return true;
        return true;
@@ -14292,13 +14338,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
                    if (!app.killedBackground) {
                    if (!app.killedBackground) {
                        numHidden++;
                        numHidden++;
                        if (numHidden > MAX_HIDDEN_APPS) {
                        if (numHidden > MAX_HIDDEN_APPS) {
                            Slog.i(TAG, "Kill " + app.processName
                            Slog.i(TAG, "No longer want " + app.processName
                                    + " (pid " + app.pid + "): hidden #" + numHidden
                                    + " (pid " + app.pid + "): hidden #" + numHidden);
                                    + " beyond limit " + MAX_HIDDEN_APPS);
                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
                                    app.processName, app.setAdj, "too many background");
                                    app.processName, app.setAdj, "too many background");
                            app.killedBackground = true;
                            app.killedBackground = true;
                            Process.killProcess(app.pid);
                            Process.killProcessQuiet(app.pid);
                        }
                        }
                    }
                    }
                }
                }
+4 −1
Original line number Original line Diff line number Diff line
@@ -66,7 +66,8 @@ class ProcessRecord implements Watchdog.PssRequestor {
    boolean bad;                // True if disabled in the bad process list
    boolean bad;                // True if disabled in the bad process list
    boolean killedBackground;   // True when proc has been killed due to too many bg
    boolean killedBackground;   // True when proc has been killed due to too many bg
    IBinder forcingToForeground;// Token that is forcing this process to be foreground
    IBinder forcingToForeground;// Token that is forcing this process to be foreground
    int adjSeq;                 // Sequence id for identifying repeated trav
    int adjSeq;                 // Sequence id for identifying oom_adj assignment cycles
    int lruSeq;                 // Sequence id for identifying LRU update cycles
    ComponentName instrumentationClass;// class installed to instrument app
    ComponentName instrumentationClass;// class installed to instrument app
    ApplicationInfo instrumentationInfo; // the application being instrumented
    ApplicationInfo instrumentationInfo; // the application being instrumented
    String instrumentationProfileFile; // where to save profiling
    String instrumentationProfileFile; // where to save profiling
@@ -175,6 +176,8 @@ class ProcessRecord implements Watchdog.PssRequestor {
        pw.print(prefix); pw.print("persistent="); pw.print(persistent);
        pw.print(prefix); pw.print("persistent="); pw.print(persistent);
                pw.print(" removed="); pw.print(removed);
                pw.print(" removed="); pw.print(removed);
                pw.print(" persistentActivities="); pw.println(persistentActivities);
                pw.print(" persistentActivities="); pw.println(persistentActivities);
        pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
                pw.print(" lruSeq="); pw.println(lruSeq);
        if (killedBackground) {
        if (killedBackground) {
            pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground);
            pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground);
        }
        }