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

Commit 32dbdca4 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Start process of next activity with top priority in advance

In common cases, to resume the next activity we need to wait for the
current one to be paused. Since starting a process for activity is
asynchronous, if we already know the process of next activity has not
started yet, we can start the process earlier so the time waiting for
the pause to complete can be saved.

Also if the launching activity is going to be the top app, we can set
the top schedule group right after its process is started so the start
time before actually launching the activity can be improved.

Although before the current activity is paused, the next top activity
may still change and results some empty processes. That should not be
a common case and the process is still useful when going back the stack,
and the empty background processes are easier to be reclaimed.

Bug: 123043091
Test: AppLaunchTest
Test: Launch calculator from launcher, the event log am_proc_start will
      show "pre-top-activity".
Test: Cold launch a top activity, the system log should not show
      "not expected top priority".
Test: Use startActivities to start serveral activities in a sequence.
      Check "adb shell cat /proc/$pid/task/$pid/cgroup" for each process.
      Only the last one has top-app, others are background.

Change-Id: I9601b66e7cc0855fd7c2b573ded31fcf8d0711ae
parent 33562e9a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -318,7 +318,7 @@ public abstract class ActivityManagerInternal {

    /** Starts a given process. */
    public abstract void startProcess(String processName, ApplicationInfo info,
            boolean knownToBeDead, String hostingType, ComponentName hostingName);
            boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName);

    /** Starts up the starting activity process for debugging if needed.
     * This function needs to be called synchronously from WindowManager context so the caller
+4 −2
Original line number Diff line number Diff line
@@ -511,6 +511,7 @@ public class Process {
     * @param appDataDir null-ok the data directory of the app.
     * @param invokeWith null-ok the command to invoke with.
     * @param packageName null-ok the name of the package this process belongs to.
     * @param isTopApp whether the process starts for high priority application.
     *
     * @param zygoteArgs Additional arguments to supply to the zygote process.
     * @return An object that describes the result of the attempt to start the process.
@@ -530,11 +531,12 @@ public class Process {
                                           @Nullable String appDataDir,
                                           @Nullable String invokeWith,
                                           @Nullable String packageName,
                                           boolean isTopApp,
                                           @Nullable String[] zygoteArgs) {
        return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, packageName,
                    /*useUsapPool=*/ true, zygoteArgs);
                    /*useUsapPool=*/ true, isTopApp, zygoteArgs);
    }

    /** @hide */
@@ -554,7 +556,7 @@ public class Process {
        return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, packageName,
                    /*useUsapPool=*/ false, zygoteArgs);
                    /*useUsapPool=*/ false, /*isTopApp=*/ false, zygoteArgs);
    }

    /**
+10 −2
Original line number Diff line number Diff line
@@ -307,6 +307,7 @@ public class ZygoteProcess {
     * @param invokeWith null-ok the command to invoke with.
     * @param packageName null-ok the name of the package this process belongs to.
     * @param zygoteArgs Additional arguments to supply to the zygote process.
     * @param isTopApp Whether the process starts for high priority application.
     *
     * @return An object that describes the result of the attempt to start the process.
     * @throws RuntimeException on fatal start failure
@@ -323,6 +324,7 @@ public class ZygoteProcess {
                                                  @Nullable String invokeWith,
                                                  @Nullable String packageName,
                                                  boolean useUsapPool,
                                                  boolean isTopApp,
                                                  @Nullable String[] zygoteArgs) {
        // TODO (chriswailes): Is there a better place to check this value?
        if (fetchUsapPoolEnabledPropWithMinInterval()) {
@@ -333,7 +335,7 @@ public class ZygoteProcess {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
                    packageName, useUsapPool, zygoteArgs);
                    packageName, useUsapPool, isTopApp, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
@@ -534,6 +536,7 @@ public class ZygoteProcess {
     * @param startChildZygote Start a sub-zygote. This creates a new zygote process
     * that has its state cloned from this zygote process.
     * @param packageName null-ok the name of the package this process belongs to.
     * @param isTopApp Whether the process starts for high priority application.
     * @param extraArgs Additional arguments to supply to the zygote process.
     * @return An object that describes the result of the attempt to start the process.
     * @throws ZygoteStartFailedEx if process start failed for any reason
@@ -552,6 +555,7 @@ public class ZygoteProcess {
                                                      boolean startChildZygote,
                                                      @Nullable String packageName,
                                                      boolean useUsapPool,
                                                      boolean isTopApp,
                                                      @Nullable String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<>();
@@ -623,6 +627,10 @@ public class ZygoteProcess {
            argsForZygote.add("--package-name=" + packageName);
        }

        if (isTopApp) {
            argsForZygote.add(Zygote.START_AS_TOP_APP_ARG);
        }

        argsForZygote.add(processClass);

        if (extraArgs != null) {
@@ -1142,7 +1150,7 @@ public class ZygoteProcess {
                    gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
                    abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
                    true /* startChildZygote */, null /* packageName */,
                    false /* useUsapPool */, extraArgs);
                    false /* useUsapPool */, false /* isTopApp */, extraArgs);
        } catch (ZygoteStartFailedEx ex) {
            throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
        }
+12 −7
Original line number Diff line number Diff line
@@ -130,6 +130,9 @@ public final class Zygote {
    /** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */
    static final int USAP_MANAGEMENT_MESSAGE_BYTES = 8;

    /** Make the new process have top application priority. */
    public static final String START_AS_TOP_APP_ARG = "--is-top-app";

    /**
     * An extraArg passed when a zygote process is forking a child-zygote, specifying a name
     * in the abstract socket namespace. This socket name is what the new child zygote
@@ -232,6 +235,7 @@ public final class Zygote {
     * new zygote process.
     * @param instructionSet null-ok the instruction set to use.
     * @param appDataDir null-ok the data directory of the app.
     * @param isTopApp true if the process is for top (high priority) application.
     *
     * @return 0 if this is the child, pid of the child
     * if this is the parent, or -1 on error.
@@ -239,12 +243,12 @@ public final class Zygote {
    static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
            int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
            int targetSdkVersion) {
            int targetSdkVersion, boolean isTopApp) {
        ZygoteHooks.preFork();

        int pid = nativeForkAndSpecialize(
                uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                fdsToIgnore, startChildZygote, instructionSet, appDataDir);
                fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp);
        // Enable tracing as soon as possible for the child process.
        if (pid == 0) {
            Zygote.disableExecuteOnly(targetSdkVersion);
@@ -264,7 +268,7 @@ public final class Zygote {
    private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids,
            int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
            int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
            String appDataDir);
            String appDataDir, boolean isTopApp);

    /**
     * Specialize an unspecialized app process.  The current VM must have been started
@@ -286,12 +290,13 @@ public final class Zygote {
     * new zygote process.
     * @param instructionSet null-ok  The instruction set to use.
     * @param appDataDir null-ok  The data directory of the app.
     * @param isTopApp  True if the process is for top (high priority) application.
     */
    private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, int mountExternal, String seInfo, String niceName,
            boolean startChildZygote, String instructionSet, String appDataDir) {
            boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp) {
        nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
                                 niceName, startChildZygote, instructionSet, appDataDir);
                niceName, startChildZygote, instructionSet, appDataDir, isTopApp);

        // Enable tracing as soon as possible for the child process.
        Trace.setTracingEnabled(true, runtimeFlags);
@@ -313,7 +318,7 @@ public final class Zygote {

    private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
            int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
            boolean startChildZygote, String instructionSet, String appDataDir);
            boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp);

    /**
     * Called to do any initialization before starting an application.
@@ -642,7 +647,7 @@ public final class Zygote {
            specializeAppProcess(args.mUid, args.mGid, args.mGids,
                                 args.mRuntimeFlags, rlimits, args.mMountExternal,
                                 args.mSeInfo, args.mNiceName, args.mStartChildZygote,
                                 args.mInstructionSet, args.mAppDataDir);
                                 args.mInstructionSet, args.mAppDataDir, args.mIsTopApp);

            disableExecuteOnly(args.mTargetSdkVersion);

+7 −0
Original line number Diff line number Diff line
@@ -204,6 +204,11 @@ class ZygoteArguments {
     */
    int mHiddenApiAccessStatslogSampleRate = -1;

    /**
     * @see Zygote#START_AS_TOP_APP_ARG
     */
    boolean mIsTopApp;

    /**
     * Constructs instance and parses args
     *
@@ -405,6 +410,8 @@ class ZygoteArguments {
                mUsapPoolStatusSpecified = true;
                mUsapPoolEnabled = Boolean.parseBoolean(getAssignmentValue(arg));
                expectRuntimeArgs = false;
            } else if (arg.startsWith(Zygote.START_AS_TOP_APP_ARG)) {
                mIsTopApp = true;
            } else {
                break;
            }
Loading