summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2020-03-04 23:41:40 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2020-03-04 23:41:40 +0000
commitefbcd6752d9e9f980ae5044b9bbd35fe4b192c52 (patch)
tree4481739bc76a343fae9027607f34497857d31dcb
parent35c5908f80f7a09a7d3a74896e3f8d52b3696bdc (diff)
parent364f2500e536c61a4acb1ac7129a2ef348b684ff (diff)
downloadbase-efbcd6752d9e9f980ae5044b9bbd35fe4b192c52.tar.gz
Merge "Start process of next activity with top priority in advance"
-rw-r--r--core/java/android/app/ActivityManagerInternal.java3
-rw-r--r--core/java/android/os/Process.java6
-rw-r--r--core/java/android/os/ZygoteProcess.java12
-rw-r--r--core/java/com/android/internal/os/Zygote.java20
-rw-r--r--core/java/com/android/internal/os/ZygoteArguments.java7
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java2
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp44
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java11
-rw-r--r--services/core/java/com/android/server/am/HostingRecord.java23
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java39
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java18
15 files changed, 171 insertions, 58 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 1725db046a95..9b59ab453acf 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -29,7 +29,6 @@ import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.TransactionTooLargeException;
-import android.view.RemoteAnimationAdapter;
import java.util.ArrayList;
import java.util.List;
@@ -300,7 +299,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
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 10b4e5ddcd55..1c0f0f42a5dc 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -525,6 +525,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 disabledCompatChanges null-ok list of disabled compat changes for the process being
* started.
* @param zygoteArgs Additional arguments to supply to the zygote process.
@@ -545,12 +546,13 @@ public class Process {
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
+ boolean isTopApp,
@Nullable long[] disabledCompatChanges,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
- /*useUsapPool=*/ true, disabledCompatChanges, zygoteArgs);
+ /*useUsapPool=*/ true, isTopApp, disabledCompatChanges, zygoteArgs);
}
/** @hide */
@@ -571,7 +573,7 @@ public class Process {
return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
- /*useUsapPool=*/ false, disabledCompatChanges, zygoteArgs);
+ /*useUsapPool=*/ false, /*isTopApp=*/ false, disabledCompatChanges, zygoteArgs);
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 016823e1a07d..32df0529a41c 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -309,6 +309,7 @@ public class ZygoteProcess {
* @param disabledCompatChanges null-ok list of disabled compat changes for the process being
* started.
* @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
@@ -325,6 +326,7 @@ public class ZygoteProcess {
@Nullable String invokeWith,
@Nullable String packageName,
boolean useUsapPool,
+ boolean isTopApp,
@Nullable long[] disabledCompatChanges,
@Nullable String[] zygoteArgs) {
// TODO (chriswailes): Is there a better place to check this value?
@@ -336,7 +338,7 @@ public class ZygoteProcess {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
- packageName, useUsapPool, disabledCompatChanges, zygoteArgs);
+ packageName, useUsapPool, isTopApp, disabledCompatChanges, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -537,6 +539,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 disabledCompatChanges a list of disabled compat changes for the process being started.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
@@ -556,6 +559,7 @@ public class ZygoteProcess {
boolean startChildZygote,
@Nullable String packageName,
boolean useUsapPool,
+ boolean isTopApp,
@Nullable long[] disabledCompatChanges,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
@@ -628,6 +632,10 @@ public class ZygoteProcess {
argsForZygote.add("--package-name=" + packageName);
}
+ if (isTopApp) {
+ argsForZygote.add(Zygote.START_AS_TOP_APP_ARG);
+ }
+
if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
final StringBuilder sb = new StringBuilder();
sb.append("--disabled-compat-changes=");
@@ -1190,7 +1198,7 @@ public class ZygoteProcess {
gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
true /* startChildZygote */, null /* packageName */,
- false /* useUsapPool */,
+ false /* useUsapPool */, false /* isTopApp */,
null /* disabledCompatChanges */, extraArgs);
} catch (ZygoteStartFailedEx ex) {
throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 5f196a0e4c1c..d047415aacfb 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -164,6 +164,9 @@ public final class Zygote {
/** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */
public 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
@@ -266,18 +269,20 @@ 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.
*/
public 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[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
+ 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);
if (pid == 0) {
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -293,7 +298,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
@@ -315,12 +320,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.
*/
public 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);
// Note that this event ends at the end of handleChildProc.
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -339,7 +345,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.
@@ -662,7 +668,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);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 3915ba273dfa..4442cf0c8208 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -210,6 +210,11 @@ class ZygoteArguments {
int mHiddenApiAccessStatslogSampleRate = -1;
/**
+ * @see Zygote#START_AS_TOP_APP_ARG
+ */
+ boolean mIsTopApp;
+
+ /**
* A set of disabled app compatibility changes for the running app. From
* --disabled-compat-changes.
*/
@@ -422,6 +427,8 @@ class ZygoteArguments {
mUsapPoolStatusSpecified = true;
mUsapPoolEnabled = Boolean.parseBoolean(arg.substring(arg.indexOf('=') + 1));
expectRuntimeArgs = false;
+ } else if (arg.startsWith(Zygote.START_AS_TOP_APP_ARG)) {
+ mIsTopApp = true;
} else if (arg.startsWith("--disabled-compat-changes=")) {
if (mDisabledCompatChanges != null) {
throw new IllegalArgumentException("Duplicate arg specified");
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 24ea59ae6ac0..8f1f4cc1077c 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -257,7 +257,7 @@ class ZygoteConnection {
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
- parsedArgs.mInstructionSet, parsedArgs.mAppDataDir);
+ parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp);
try {
if (pid == 0) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index ea58cbd99179..0ce61de270f8 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -663,11 +663,25 @@ static void SetCapabilities(uint64_t permitted, uint64_t effective, uint64_t inh
}
}
-static void SetSchedulerPolicy(fail_fn_t fail_fn) {
- errno = -set_sched_policy(0, SP_DEFAULT);
+static void SetSchedulerPolicy(fail_fn_t fail_fn, bool is_top_app) {
+ SchedPolicy policy = is_top_app ? SP_TOP_APP : SP_DEFAULT;
+
+ if (is_top_app && cpusets_enabled()) {
+ errno = -set_cpuset_policy(0, policy);
+ if (errno != 0) {
+ fail_fn(CREATE_ERROR("set_cpuset_policy(0, %d) failed: %s", policy, strerror(errno)));
+ }
+ }
+
+ errno = -set_sched_policy(0, policy);
if (errno != 0) {
- fail_fn(CREATE_ERROR("set_sched_policy(0, SP_DEFAULT) failed: %s", strerror(errno)));
+ fail_fn(CREATE_ERROR("set_sched_policy(0, %d) failed: %s", policy, strerror(errno)));
}
+
+ // We are going to lose the permission to set scheduler policy during the specialization, so make
+ // sure that we don't cache the fd of cgroup path that may cause sepolicy violation by writing
+ // value to the cached fd directly when creating new thread.
+ DropTaskProfilesResourceCaching();
}
static int UnmountTree(const char* path) {
@@ -1055,7 +1069,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
jint mount_external, jstring managed_se_info,
jstring managed_nice_name, bool is_system_server,
bool is_child_zygote, jstring managed_instruction_set,
- jstring managed_app_data_dir) {
+ jstring managed_app_data_dir, bool is_top_app) {
const char* process_name = is_system_server ? "system_server" : "zygote";
auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
@@ -1118,6 +1132,9 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
// privileged syscalls used below still need to be accessible in app process.
SetUpSeccompFilter(uid, is_child_zygote);
+ // Must be called before losing the permission to set scheduler policy.
+ SetSchedulerPolicy(fail_fn, is_top_app);
+
if (setresuid(uid, uid, uid) == -1) {
fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
}
@@ -1176,8 +1193,6 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, fail_fn);
- SetSchedulerPolicy(fail_fn);
-
__android_log_close();
stats_log_close();
@@ -1446,7 +1461,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
jint runtime_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring nice_name,
jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
- jstring instruction_set, jstring app_data_dir) {
+ jstring instruction_set, jstring app_data_dir, jboolean is_top_app) {
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
if (UNLIKELY(managed_fds_to_close == nullptr)) {
@@ -1482,7 +1497,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
capabilities, capabilities,
mount_external, se_info, nice_name, false,
- is_child_zygote == JNI_TRUE, instruction_set, app_data_dir);
+ is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
+ is_top_app == JNI_TRUE);
}
return pid;
}
@@ -1514,7 +1530,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
permitted_capabilities, effective_capabilities,
MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
- false, nullptr, nullptr);
+ false, nullptr, nullptr, /* is_top_app= */ false);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -1637,18 +1653,20 @@ static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter(
* @param is_child_zygote If the process is to become a WebViewZygote
* @param instruction_set The instruction set expected/requested by the new application
* @param app_data_dir Path to the application's data directory
+ * @param is_top_app If the process is for top (high priority) application
*/
static void com_android_internal_os_Zygote_nativeSpecializeAppProcess(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring nice_name,
- jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) {
+ jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app) {
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
capabilities, capabilities,
mount_external, se_info, nice_name, false,
- is_child_zygote == JNI_TRUE, instruction_set, app_data_dir);
+ is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
+ is_top_app == JNI_TRUE);
}
/**
@@ -1845,7 +1863,7 @@ static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclas
static const JNINativeMethod gMethods[] = {
{ "nativeForkAndSpecialize",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
(void *) com_android_internal_os_Zygote_nativeForkSystemServer },
@@ -1858,7 +1876,7 @@ static const JNINativeMethod gMethods[] = {
{ "nativeForkUsap", "(II[IZ)I",
(void *) com_android_internal_os_Zygote_nativeForkUsap },
{ "nativeSpecializeAppProcess",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z)V",
(void *) com_android_internal_os_Zygote_nativeSpecializeAppProcess },
{ "nativeInitNativeState", "(Z)V",
(void *) com_android_internal_os_Zygote_nativeInitNativeState },
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 53d23842ec79..f19dc7a11eaa 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4875,7 +4875,7 @@ public class ActivityManagerService extends IActivityManager.Stub
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
- app.setCurrentSchedulingGroup(app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT);
+ mOomAdjuster.setAttachingSchedGroupLocked(app);
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, 0, false);
app.hasShownUi = false;
@@ -18473,16 +18473,19 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public void startProcess(String processName, ApplicationInfo info,
- boolean knownToBeDead, String hostingType, ComponentName hostingName) {
+ public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
+ boolean isTop, String hostingType, ComponentName hostingName) {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:"
+ processName);
}
synchronized (ActivityManagerService.this) {
+ // If the process is known as top app, set a hint so when the process is
+ // started, the top priority can be applied immediately to avoid cpu being
+ // preempted by other processes before attaching the process of top app.
startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
- new HostingRecord(hostingType, hostingName),
+ new HostingRecord(hostingType, hostingName, isTop),
false /* allowWhileBooting */, false /* isolated */,
true /* keepIfLarge */);
}
diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java
index 784dde1e98df..6bb5def26b9d 100644
--- a/services/core/java/com/android/server/am/HostingRecord.java
+++ b/services/core/java/com/android/server/am/HostingRecord.java
@@ -41,6 +41,8 @@ import android.content.ComponentName;
* {@link android.content.Context#BIND_EXTERNAL_SERVICE} service. In that case, the packageName
* and uid in the ApplicationInfo will be set to those of the caller, not of the defining package.
*
+ * {@code mIsTopApp} will be passed to {@link android.os.Process#start}. So Zygote will initialize
+ * the process with high priority.
*/
public final class HostingRecord {
@@ -53,15 +55,22 @@ public final class HostingRecord {
private final int mHostingZygote;
private final String mDefiningPackageName;
private final int mDefiningUid;
+ private final boolean mIsTopApp;
public HostingRecord(String hostingType) {
- this(hostingType, null, REGULAR_ZYGOTE, null, -1);
+ this(hostingType, null /* hostingName */, REGULAR_ZYGOTE, null /* definingPackageName */,
+ -1 /* mDefiningUid */, false /* isTopApp */);
}
public HostingRecord(String hostingType, ComponentName hostingName) {
this(hostingType, hostingName, REGULAR_ZYGOTE);
}
+ public HostingRecord(String hostingType, ComponentName hostingName, boolean isTopApp) {
+ this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE,
+ null /* definingPackageName */, -1 /* mDefiningUid */, isTopApp /* isTopApp */);
+ }
+
public HostingRecord(String hostingType, String hostingName) {
this(hostingType, hostingName, REGULAR_ZYGOTE);
}
@@ -71,16 +80,18 @@ public final class HostingRecord {
}
private HostingRecord(String hostingType, String hostingName, int hostingZygote) {
- this(hostingType, hostingName, hostingZygote, null, -1);
+ this(hostingType, hostingName, hostingZygote, null /* definingPackageName */,
+ -1 /* mDefiningUid */, false /* isTopApp */);
}
private HostingRecord(String hostingType, String hostingName, int hostingZygote,
- String definingPackageName, int definingUid) {
+ String definingPackageName, int definingUid, boolean isTopApp) {
mHostingType = hostingType;
mHostingName = hostingName;
mHostingZygote = hostingZygote;
mDefiningPackageName = definingPackageName;
mDefiningUid = definingUid;
+ mIsTopApp = isTopApp;
}
public String getType() {
@@ -91,6 +102,10 @@ public final class HostingRecord {
return mHostingName;
}
+ public boolean isTopApp() {
+ return mIsTopApp;
+ }
+
/**
* Returns the UID of the package defining the component we want to start. Only valid
* when {@link #usesAppZygote()} returns true.
@@ -130,7 +145,7 @@ public final class HostingRecord {
public static HostingRecord byAppZygote(ComponentName hostingName, String definingPackageName,
int definingUid) {
return new HostingRecord("", hostingName.toShortString(), APP_ZYGOTE,
- definingPackageName, definingUid);
+ definingPackageName, definingUid, false /* isTopApp */);
}
/**
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index dbf8acf74dbd..80e22e529ba9 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -178,9 +178,12 @@ public final class OomAdjuster {
adjusterThread.start();
Process.setThreadGroupAndCpuset(adjusterThread.getThreadId(), THREAD_GROUP_TOP_APP);
mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setProcessGroup");
final int pid = msg.arg1;
final int group = msg.arg2;
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setProcessGroup "
+ + msg.obj + " to " + group);
+ }
try {
setProcessGroup(pid, group);
} catch (Exception e) {
@@ -1758,7 +1761,7 @@ public final class OomAdjuster {
break;
}
mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage(
- 0 /* unused */, app.pid, processGroup));
+ 0 /* unused */, app.pid, processGroup, app.processName));
try {
if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
// do nothing if we already switched to RT
@@ -1949,6 +1952,38 @@ public final class OomAdjuster {
return success;
}
+ @GuardedBy("mService")
+ void setAttachingSchedGroupLocked(ProcessRecord app) {
+ int initialSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ // If the process has been marked as foreground via Zygote.START_FLAG_USE_TOP_APP_PRIORITY,
+ // then verify that the top priority is actually is applied.
+ if (app.hasForegroundActivities()) {
+ String fallbackReason = null;
+ try {
+ // The priority must be the same as how does {@link #applyOomAdjLocked} set for
+ // {@link ProcessList.SCHED_GROUP_TOP_APP}. We don't check render thread because it
+ // is not ready when attaching.
+ if (Process.getProcessGroup(app.pid) == THREAD_GROUP_TOP_APP) {
+ app.getWindowProcessController().onTopProcChanged();
+ setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);
+ } else {
+ fallbackReason = "not expected top priority";
+ }
+ } catch (Exception e) {
+ fallbackReason = e.toString();
+ }
+ if (fallbackReason == null) {
+ initialSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+ } else {
+ // The real scheduling group will depend on if there is any component of the process
+ // did something during attaching.
+ Slog.w(TAG, "Fallback pre-set sched group to default: " + fallbackReason);
+ }
+ }
+
+ app.setCurrentSchedulingGroup(app.setSchedGroup = initialSchedGroup);
+ }
+
// ONLY used for unit testing in OomAdjusterTests.java
@VisibleForTesting
void maybeUpdateUsageStats(ProcessRecord app, long nowElapsed) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 8520cb7c30b8..3996ae2172b4 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -51,7 +51,6 @@ import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppProtoEnums;
import android.app.IApplicationThread;
-import android.app.IUidObserver;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.ComponentName;
@@ -1899,6 +1898,14 @@ public final class ProcessList {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkSlow(startTime, "startProcess: asking zygote to start proc");
+ final boolean isTopApp = hostingRecord.isTopApp();
+ if (isTopApp) {
+ // Use has-foreground-activities as a temporary hint so the current scheduling
+ // group won't be lost when the process is attaching. The actual state will be
+ // refreshed when computing oom-adj.
+ app.setHasForegroundActivities(true);
+ }
+
final Process.ProcessStartResult startResult;
if (hostingRecord.usesWebviewZygote()) {
startResult = startWebView(entryPoint,
@@ -1913,13 +1920,13 @@ public final class ProcessList {
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
- /*useUsapPool=*/ false, app.mDisabledCompatChanges,
+ /*useUsapPool=*/ false, isTopApp, app.mDisabledCompatChanges,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
- app.info.dataDir, invokeWith, app.info.packageName,
+ app.info.dataDir, invokeWith, app.info.packageName, isTopApp,
app.mDisabledCompatChanges,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1d8f059a7e75..500cc38f8b66 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3551,7 +3551,7 @@ final class ActivityRecord extends ConfigurationContainer {
mStackSupervisor.scheduleRestartTimeout(this);
}
- private boolean isProcessRunning() {
+ boolean isProcessRunning() {
WindowProcessController proc = app;
if (proc == null) {
proc = mAtmService.mProcessNames.get(processName, info.applicationInfo.uid);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 242139cd2da7..848971d3b044 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2743,7 +2743,7 @@ class ActivityStack extends ConfigurationContainer {
final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0
&& !lastResumedCanPip;
- boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
+ boolean pausing = display.pauseBackStacks(userLeaving, next, false);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
@@ -2759,6 +2759,13 @@ class ActivityStack extends ConfigurationContainer {
if (next.attachedToProcess()) {
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
true /* activityChange */, false /* updateOomAdj */);
+ } else if (!next.isProcessRunning()) {
+ // Since the start-process is asynchronous, if we already know the process of next
+ // activity isn't running, we can start the process earlier to save the time to wait
+ // for the current activity to be paused.
+ final boolean isTop = this == display.getFocusedStack();
+ mService.startProcessAsync(next, false /* knownToBeDead */, isTop,
+ isTop ? "pre-top-activity" : "pre-activity");
}
if (lastResumed != null) {
lastResumed.setWillCloseOrEnterPip(true);
@@ -2827,7 +2834,7 @@ class ActivityStack extends ConfigurationContainer {
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
- final DisplayContent dc = getDisplay().mDisplayContent;
+ final DisplayContent dc = display.mDisplayContent;
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
@@ -2984,7 +2991,7 @@ class ActivityStack extends ConfigurationContainer {
next.clearOptionsLocked();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
- getDisplay().mDisplayContent.isNextTransitionForward()));
+ dc.isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 8f573c0e7234..69bd84b1267b 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -995,20 +995,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
r.notifyUnknownVisibilityLaunched();
}
- try {
- if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) {
- Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:"
- + r.processName);
- }
- // Post message to start process to avoid possible deadlock of calling into AMS with the
- // ATMS lock held.
- final Message msg = PooledLambda.obtainMessage(
- ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
- r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
- mService.mH.sendMessage(msg);
- } finally {
- Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
- }
+ final boolean isTop = andResume && r.isTopRunningActivity();
+ mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo, String resultWho,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 223205377bb9..c0fd24c39908 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5653,6 +5653,24 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mH.sendMessage(m);
}
+ void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
+ String hostingType) {
+ try {
+ if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) {
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:"
+ + activity.processName);
+ }
+ // Post message to start process to avoid possible deadlock of calling into AMS with the
+ // ATMS lock held.
+ final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
+ mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
+ isTop, hostingType, activity.intent.getComponent());
+ mH.sendMessage(m);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
+
void setBooting(boolean booting) {
mAmInternal.setBooting(booting);
}