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;
  • 1.
  • 2.
  • 3.

mAllowStartForeground不等于REASON_DENIED,即被允许

((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
  • 1.

mLoggedInfoAllowStartForeground

// Is the same mInfoAllowStartForeground string has been logged before? Used for dedup.
boolean mLoggedInfoAllowStartForeground;
  • 1.
  • 2.

是否相同的前台Service被允许或者不被允许从后台启动的相关信息已经被记录过。

mInfoAllowStartForeground

// Debug info why mAllowStartForeground is allowed or denied.
String mInfoAllowStartForeground;
  • 1.
  • 2.

存储被拒绝和被允许的相关信息

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;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

预留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;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

预留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;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

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;
}
  • 1.
  • 2.
  • 3.
  • 4.

前台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);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

wtfQuiet与wtf的区别有两个地方:

  1. wtfQuiet是往system日志缓冲区中写,wtf是往main日志缓冲区中写。
  2. 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;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

前台Service被允许从后台启动这一事件会被写到wtf中,mFgsStartAllowedLogSampleRate管控写入速度。如果值为0.1,就意味着10%会被记录。

private static final float DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE = 0.25f; // 25%
  • 1.

默认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;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

前台Service不被允许从后台启动这一事件会被写到wtf中,mFgsStartDeniedLogSampleRate管控写入速度。如果值为0.1,就意味着10%会被记录。

private static final float DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE = 1; // 100%
  • 1.

默认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;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

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;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  1. 如果前台Service从后台启动的,则将相关信息输出到日志。
  2. 输出到日志的内容有两类,一类是wtf,一类是普通的日志。
  3. 不重复记录启动信息。

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。

Android logFgsBackgroundStart源码分析_开发语言