mAllowStartForeground
是否允许后台启动前台Service
// allow the service becomes foreground service? Service started from background may not be
// allowed to become a foreground service.
@PowerExemptionManager.ReasonCode int mAllowStartForeground = REASON_DENIED;
mAllowStartForeground不等于REASON_DENIED,即被允许
((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
mLoggedInfoAllowStartForeground
// Is the same mInfoAllowStartForeground string has been logged before? Used for dedup.
boolean mLoggedInfoAllowStartForeground;
是否相同的前台Service被允许或者不被允许从后台启动的相关信息已经被记录过。
mInfoAllowStartForeground
// Debug info why mAllowStartForeground is allowed or denied.
String mInfoAllowStartForeground;
存储被拒绝和被允许的相关信息
isFgsBgStart
/* Reason code range 10-49 are reserved for BG-FGS-launch allowed proc states */
/** @hide */
public static final int REASON_PROC_STATE_PERSISTENT = 10;
/** @hide */
public static final int REASON_PROC_STATE_PERSISTENT_UI = 11;
/** @hide */
public static final int REASON_PROC_STATE_TOP = 12;
/** @hide */
public static final int REASON_PROC_STATE_BTOP = 13;
/** @hide */
public static final int REASON_PROC_STATE_FGS = 14;
/** @hide */
public static final int REASON_PROC_STATE_BFGS = 15;
预留10-49状态码,用于标记允许后台启动前台Service的进程状态。
/* Reason code range 50-99 are reserved for BG-FGS-launch allowed reasons */
/** @hide */
public static final int REASON_UID_VISIBLE = 50;
/** @hide */
public static final int REASON_SYSTEM_UID = 51;
/** @hide */
public static final int REASON_ACTIVITY_STARTER = 52;
/** @hide */
public static final int REASON_START_ACTIVITY_FLAG = 53;
/** @hide */
public static final int REASON_FGS_BINDING = 54;
/** @hide */
public static final int REASON_DEVICE_OWNER = 55;
/** @hide */
public static final int REASON_PROFILE_OWNER = 56;
/** @hide */
public static final int REASON_COMPANION_DEVICE_MANAGER = 57;
/**
* START_ACTIVITIES_FROM_BACKGROUND permission.
* @hide
*/
public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION = 58;
/**
* START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
* @hide
*/
public static final int REASON_BACKGROUND_FGS_PERMISSION = 59;
预留50-99状态码,用于标记允许后台启动前台Service的原因。
private static boolean isFgsBgStart(@ReasonCode int code) {
return code != REASON_PROC_STATE_PERSISTENT
&& code != REASON_PROC_STATE_PERSISTENT_UI
&& code != REASON_PROC_STATE_TOP
&& code != REASON_UID_VISIBLE;
}
isFgsBgStart,顾名思义,即前台Service是否是从后台启动的。如果参数code不等于REASON_PROC_STATE_PERSISTENT、不等于REASON_PROC_STATE_PERSISTENT_UI、不等于REASON_PROC_STATE_TOP、不等于REASON_UID_VISIBLE,就认为是从后台启动的。
// Only log if FGS is started from background.
if (!isFgsBgStart(r.mAllowStartForeground)) {
return;
}
前台Service从后台启动的时候,才打印日志信息。
Slog.wtfQuiet
/**
* Similar to {@link #wtf(String, String)}, but does not output anything to the log.
*/
public static void wtfQuiet(@Nullable String tag, @NonNull String msg) {
Log.wtfQuiet(Log.LOG_ID_SYSTEM, tag, msg, true);
}
wtfQuiet与wtf的区别有两个地方:
- wtfQuiet是往system日志缓冲区中写,wtf是往main日志缓冲区中写。
- wtfQuiet不会输出wtf的日志,wtf会输出wtf的日志。
mFgsStartAllowedLogSampleRate
/**
* Sample rate for the allowed FGS start WTF logs.
*
* If the value is 0.1, 10% of the logs would be sampled.
*/
volatile float mFgsStartAllowedLogSampleRate = DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE;
前台Service被允许从后台启动这一事件会被写到wtf中,mFgsStartAllowedLogSampleRate管控写入速度。如果值为0.1,就意味着10%会被记录。
private static final float DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE = 0.25f; // 25%
默认25%的wtf会被记录。
mFgsStartDeniedLogSampleRate
/**
* Sample rate for the denied FGS start WTF logs.
*
* If the value is 0.1, 10% of the logs would be sampled.
*/
volatile float mFgsStartDeniedLogSampleRate = DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE;
前台Service不被允许从后台启动这一事件会被写到wtf中,mFgsStartDeniedLogSampleRate管控写入速度。如果值为0.1,就意味着10%会被记录。
private static final float DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE = 1; // 100%
默认100%的wtf会被记录。
shouldSamplePackageForAtom
/**
* @return whether a package should be logged, using a random value based on the ANDROID_ID,
* with a given sampling rate.
*/
public static boolean shouldSamplePackageForAtom(String packageName, float rate) {
if (rate <= 0) {
return false;
}
if (rate >= 1) {
return true;
}
final int hash = getUnsignedHashCached(packageName) ^ getAndroidIdHash();
return (((double) hash) / Integer.MAX_VALUE) <= rate;
}
rate如果小于0,则不输出wtf,如果大于等于1,则一定会输出wtf。后续算法有点繁杂,就不在这里分析了。
logFgsBackgroundStart
private void logFgsBackgroundStart(ServiceRecord r) {
// Only log if FGS is started from background.
if (!isFgsBgStart(r.mAllowStartForeground)) {
return;
}
if (!r.mLoggedInfoAllowStartForeground) {
final String msg = "Background started FGS: "
+ ((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
+ r.mInfoAllowStartForeground;
if (r.mAllowStartForeground != REASON_DENIED) {
if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
mAm.mConstants.mFgsStartAllowedLogSampleRate)) {
Slog.wtfQuiet(TAG, msg);
}
Slog.i(TAG, msg);
} else {
if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
mAm.mConstants.mFgsStartDeniedLogSampleRate)) {
Slog.wtfQuiet(TAG, msg);
}
Slog.w(TAG, msg);
}
r.mLoggedInfoAllowStartForeground = true;
}
}
- 如果前台Service从后台启动的,则将相关信息输出到日志。
- 输出到日志的内容有两类,一类是wtf,一类是普通的日志。
- 不重复记录启动信息。