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

Commit 37298b68 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Added FGS logic change detection with WTF

See go/fgs-u-qpr-logic for the details.

Bug: 276963716
Test: atest CtsShortFgsTestCasesatest android.app.cts.ActivityManagerFgsBgStartTest
Change-Id: I01dc87d6cc02ead0a178b562a401b1cffb0a85d0
parent d3813b18
Loading
Loading
Loading
Loading
+68 −44
Original line number Diff line number Diff line
@@ -256,7 +256,7 @@ import java.util.function.Predicate;
public final class ActiveServices {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
    private static final String TAG_MU = TAG + POSTFIX_MU;
    private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
    static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
    private static final String TAG_SERVICE_EXECUTING = TAG + POSTFIX_SERVICE_EXECUTING;

    private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE;
@@ -850,8 +850,7 @@ public final class ActiveServices {
        // Service.startForeground()), at that point we will consult the BFSL check and the timeout
        // and make the necessary decisions.
        setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId,
                backgroundStartPrivileges, false /* isBindService */,
                !fgRequired /* isStartService */);
                backgroundStartPrivileges, false /* isBindService */);

        if (!mAm.mUserController.exists(r.userId)) {
            Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
@@ -894,7 +893,7 @@ public final class ActiveServices {

        if (fgRequired) {
            logFgsBackgroundStart(r);
            if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
            if (!r.isFgsAllowedStart() && isBgFgsRestrictionEnabled(r)) {
                String msg = "startForegroundService() not allowed due to "
                        + "mAllowStartForeground false: service "
                        + r.shortInstanceName;
@@ -1060,7 +1059,7 @@ public final class ActiveServices {
            // Use that as a shortcut if possible to avoid having to recheck all the conditions.
            final boolean whileInUseAllowsUiJobScheduling =
                    ActivityManagerService.doesReasonCodeAllowSchedulingUserInitiatedJobs(
                            r.mAllowWhileInUsePermissionInFgsReason);
                            r.getFgsAllowWIU());
            r.updateAllowUiJobScheduling(whileInUseAllowsUiJobScheduling
                    || mAm.canScheduleUserInitiatedJobs(callingUid, callingPid, callingPackage));
        } else {
@@ -2178,12 +2177,12 @@ public final class ActiveServices {
                        // on a SHORT_SERVICE FGS.

                        // See if the app could start an FGS or not.
                        r.mAllowStartForeground = REASON_DENIED;
                        r.clearFgsAllowStart();
                        setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
                                r.appInfo.uid, r.intent.getIntent(), r, r.userId,
                                BackgroundStartPrivileges.NONE,
                                false /* isBindService */, false /* isStartService */);
                        if (r.mAllowStartForeground == REASON_DENIED) {
                                false /* isBindService */);
                        if (!r.isFgsAllowedStart()) {
                            Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: "
                                    + " BFSL DENIED.");
                        } else {
@@ -2191,13 +2190,13 @@ public final class ActiveServices {
                                Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: "
                                        + " BFSL Allowed: "
                                        + PowerExemptionManager.reasonCodeToString(
                                                r.mAllowStartForeground));
                                                r.getFgsAllowStart()));
                            }
                        }

                        final boolean fgsStartAllowed =
                                !isBgFgsRestrictionEnabledForService
                                        || (r.mAllowStartForeground != REASON_DENIED);
                                        || r.isFgsAllowedStart();

                        if (fgsStartAllowed) {
                            if (isNewTypeShortFgs) {
@@ -2246,7 +2245,7 @@ public final class ActiveServices {
                                setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
                                        r.appInfo.uid, r.intent.getIntent(), r, r.userId,
                                        BackgroundStartPrivileges.NONE,
                                        false /* isBindService */, false /* isStartService */);
                                        false /* isBindService */);
                                final String temp = "startForegroundDelayMs:" + delayMs;
                                if (r.mInfoAllowStartForeground != null) {
                                    r.mInfoAllowStartForeground += "; " + temp;
@@ -2266,20 +2265,21 @@ public final class ActiveServices {
                        setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
                                r.appInfo.uid, r.intent.getIntent(), r, r.userId,
                                BackgroundStartPrivileges.NONE,
                                false /* isBindService */, false /* isStartService */);
                                false /* isBindService */);
                    }

                    // If the foreground service is not started from TOP process, do not allow it to
                    // have while-in-use location/camera/microphone access.
                    if (!r.mAllowWhileInUsePermissionInFgs) {
                    if (!r.isFgsAllowedWIU()) {
                        Slog.w(TAG,
                                "Foreground service started from background can not have "
                                        + "location/camera/microphone access: service "
                                        + r.shortInstanceName);
                    }
                    r.maybeLogFgsLogicChange();
                    if (!bypassBfslCheck) {
                        logFgsBackgroundStart(r);
                        if (r.mAllowStartForeground == REASON_DENIED
                        if (!r.isFgsAllowedStart()
                                && isBgFgsRestrictionEnabledForService) {
                            final String msg = "Service.startForeground() not allowed due to "
                                    + "mAllowStartForeground false: service "
@@ -2378,9 +2378,9 @@ public final class ActiveServices {
                        // The logging of FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER event could
                        // be deferred, make a copy of mAllowStartForeground and
                        // mAllowWhileInUsePermissionInFgs.
                        r.mAllowStartForegroundAtEntering = r.mAllowStartForeground;
                        r.mAllowStartForegroundAtEntering = r.getFgsAllowStart();
                        r.mAllowWhileInUsePermissionInFgsAtEntering =
                                r.mAllowWhileInUsePermissionInFgs;
                                r.isFgsAllowedWIU();
                        r.mStartForegroundCount++;
                        r.mFgsEnterTime = SystemClock.uptimeMillis();
                        if (!stopProcStatsOp) {
@@ -2558,7 +2558,7 @@ public final class ActiveServices {
                policy.getForegroundServiceTypePolicyInfo(type, defaultToType);
        final @ForegroundServicePolicyCheckCode int code = policy.checkForegroundServiceTypePolicy(
                mAm.mContext, r.packageName, r.app.uid, r.app.getPid(),
                r.mAllowWhileInUsePermissionInFgs, policyInfo);
                r.isFgsAllowedWIU(), policyInfo);
        RuntimeException exception = null;
        switch (code) {
            case FGS_TYPE_POLICY_CHECK_DEPRECATED: {
@@ -3744,8 +3744,7 @@ public final class ActiveServices {
                }
            }
            setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId,
                    BackgroundStartPrivileges.NONE, true /* isBindService */,
                    false /* isStartService */);
                    BackgroundStartPrivileges.NONE, true /* isBindService */);

            if (s.app != null) {
                ProcessServiceRecord servicePsr = s.app.mServices;
@@ -7443,54 +7442,80 @@ public final class ActiveServices {
     * @param callingUid caller app's uid.
     * @param intent intent to start/bind service.
     * @param r the service to start.
     * @param isStartService True if it's called from Context.startService().
     *                       False if it's called from Context.startForegroundService() or
     *                       Service.startForeground().
     * @param isBindService True if it's called from bindService().
     * @return true if allow, false otherwise.
     */
    private void setFgsRestrictionLocked(String callingPackage,
            int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId,
            BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService,
            boolean isStartService) {
            BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) {

        @ReasonCode int allowWIU;
        @ReasonCode int allowStart;

        // If called from bindService(), do not update the actual fields, but instead
        // keep it in a separate set of fields.
        if (isBindService) {
            allowWIU = r.mAllowWIUInBindService;
            allowStart = r.mAllowStartInBindService;
        } else {
            allowWIU = r.mAllowWhileInUsePermissionInFgsReasonNoBinding;
            allowStart = r.mAllowStartForegroundNoBinding;
        }

        // Check DeviceConfig flag.
        if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
            if (!r.mAllowWhileInUsePermissionInFgs) {
            if (allowWIU == REASON_DENIED) {
                // BGFGS start restrictions are disabled. We're allowing while-in-use permissions.
                // Note REASON_OTHER since there's no other suitable reason.
                r.mAllowWhileInUsePermissionInFgsReason = REASON_OTHER;
                allowWIU = REASON_OTHER;
            }
            r.mAllowWhileInUsePermissionInFgs = true;
        }

        if (!r.mAllowWhileInUsePermissionInFgs
                || (r.mAllowStartForeground == REASON_DENIED)) {
        if ((allowWIU == REASON_DENIED)
                || (allowStart == REASON_DENIED)) {
            @ReasonCode final int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
                    callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges);
            // We store them to compare the old and new while-in-use logics to each other.
            // (They're not used for any other purposes.)
            if (!r.mAllowWhileInUsePermissionInFgs) {
                r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED);
                r.mAllowWhileInUsePermissionInFgsReason = allowWhileInUse;
            if (allowWIU == REASON_DENIED) {
                allowWIU = allowWhileInUse;
            }
            if (r.mAllowStartForeground == REASON_DENIED) {
                r.mAllowStartForeground = shouldAllowFgsStartForegroundWithBindingCheckLocked(
            if (allowStart == REASON_DENIED) {
                allowStart = shouldAllowFgsStartForegroundWithBindingCheckLocked(
                        allowWhileInUse, callingPackage, callingPid, callingUid, intent, r,
                        backgroundStartPrivileges, isBindService);
            }
        }

        if (isBindService) {
            r.mAllowWIUInBindService = allowWIU;
            r.mAllowStartInBindService = allowStart;
        } else {
            r.mAllowWhileInUsePermissionInFgsReasonNoBinding = allowWIU;
            r.mAllowStartForegroundNoBinding = allowStart;

            // Also do a binding client check, unless called from bindService().
            if (r.mAllowWIUByBindings == REASON_DENIED) {
                r.mAllowWIUByBindings =
                        shouldAllowFgsWhileInUsePermissionByBindingsLocked(callingUid);
            }
            if (r.mAllowStartByBindings == REASON_DENIED) {
                r.mAllowStartByBindings = r.mAllowWIUByBindings;
            }
        }
    }

    /**
     * Reset various while-in-use and BFSL related information.
     */
    void resetFgsRestrictionLocked(ServiceRecord r) {
        r.mAllowWhileInUsePermissionInFgs = false;
        r.mAllowWhileInUsePermissionInFgsReason = REASON_DENIED;
        r.mAllowStartForeground = REASON_DENIED;
        r.clearFgsAllowWIU();
        r.clearFgsAllowStart();

        r.mInfoAllowStartForeground = null;
        r.mInfoTempFgsAllowListReason = null;
        r.mLoggedInfoAllowStartForeground = false;
        r.updateAllowUiJobScheduling(r.mAllowWhileInUsePermissionInFgs);
        r.updateAllowUiJobScheduling(r.isFgsAllowedWIU());
    }

    boolean canStartForegroundServiceLocked(int callingPid, int callingUid, String callingPackage) {
@@ -8062,10 +8087,10 @@ public final class ActiveServices {
        */
        if (!r.mLoggedInfoAllowStartForeground) {
            final String msg = "Background started FGS: "
                    + ((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
                    + (r.isFgsAllowedStart() ? "Allowed " : "Disallowed ")
                    + r.mInfoAllowStartForeground
                    + (r.isShortFgs() ? " (Called on SHORT_SERVICE)" : "");
            if (r.mAllowStartForeground != REASON_DENIED) {
            if (r.isFgsAllowedStart()) {
                if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
                        mAm.mConstants.mFgsStartAllowedLogSampleRate)) {
                    Slog.wtfQuiet(TAG, msg);
@@ -8105,8 +8130,8 @@ public final class ActiveServices {
            allowWhileInUsePermissionInFgs = r.mAllowWhileInUsePermissionInFgsAtEntering;
            fgsStartReasonCode = r.mAllowStartForegroundAtEntering;
        } else {
            allowWhileInUsePermissionInFgs = r.mAllowWhileInUsePermissionInFgs;
            fgsStartReasonCode = r.mAllowStartForeground;
            allowWhileInUsePermissionInFgs = r.isFgsAllowedWIU();
            fgsStartReasonCode = r.getFgsAllowStart();
        }
        final int callerTargetSdkVersion = r.mRecentCallerApplicationInfo != null
                ? r.mRecentCallerApplicationInfo.targetSdkVersion : 0;
@@ -8295,8 +8320,7 @@ public final class ActiveServices {
        r.mFgsEnterTime = SystemClock.uptimeMillis();
        r.foregroundServiceType = options.mForegroundServiceTypes;
        setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId,
                BackgroundStartPrivileges.NONE,  false /* isBindService */,
                false /* isStartService */);
                BackgroundStartPrivileges.NONE,  false /* isBindService */);
        final ProcessServiceRecord psr = callerApp.mServices;
        final boolean newService = psr.startService(r);
        // updateOomAdj.
+2 −2
Original line number Diff line number Diff line
@@ -479,8 +479,8 @@ public class ForegroundServiceTypeLoggerModule {
                r.appInfo.uid,
                r.shortInstanceName,
                fgsState, // FGS State
                r.mAllowWhileInUsePermissionInFgs, // allowWhileInUsePermissionInFgs
                r.mAllowStartForeground, // fgsStartReasonCode
                r.isFgsAllowedWIU(), // allowWhileInUsePermissionInFgs
                r.getFgsAllowStart(), // fgsStartReasonCode
                r.appInfo.targetSdkVersion,
                r.mRecentCallingUid,
                0, // callerTargetSdkVersion
+1 −1
Original line number Diff line number Diff line
@@ -2218,7 +2218,7 @@ public class OomAdjuster {

            if (s.isForeground) {
                final int fgsType = s.foregroundServiceType;
                if (s.mAllowWhileInUsePermissionInFgs) {
                if (s.isFgsAllowedWIU()) {
                    capabilityFromFGS |=
                            (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
                                    != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
+120 −8
Original line number Diff line number Diff line
@@ -21,9 +21,11 @@ import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BOUND_SERVICE;
import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.os.PowerExemptionManager.reasonCodeToString;
import static android.os.Process.INVALID_UID;

import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.server.am.ActiveServices.TAG_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -172,11 +174,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
    private BackgroundStartPrivileges mBackgroundStartPrivilegesByStartMerged =
            BackgroundStartPrivileges.NONE;

    // allow while-in-use permissions in foreground service or not.
    // Reason code for allow while-in-use permissions in foreground service.
    // If it's not DENIED, while-in-use permissions are allowed.
    // while-in-use permissions in FGS started from background might be restricted.
    boolean mAllowWhileInUsePermissionInFgs;
    @PowerExemptionManager.ReasonCode
    int mAllowWhileInUsePermissionInFgsReason = REASON_DENIED;
    int mAllowWhileInUsePermissionInFgsReasonNoBinding = REASON_DENIED;

    // A copy of mAllowWhileInUsePermissionInFgs's value when the service is entering FGS state.
    boolean mAllowWhileInUsePermissionInFgsAtEntering;
@@ -205,15 +207,114 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN

    // 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;
    @PowerExemptionManager.ReasonCode
    int mAllowStartForegroundNoBinding = REASON_DENIED;
    // A copy of mAllowStartForeground's value when the service is entering FGS state.
    @PowerExemptionManager.ReasonCode int mAllowStartForegroundAtEntering = REASON_DENIED;
    @PowerExemptionManager.ReasonCode
    int mAllowStartForegroundAtEntering = REASON_DENIED;
    // Debug info why mAllowStartForeground is allowed or denied.
    String mInfoAllowStartForeground;
    // Debug info if mAllowStartForeground is allowed because of a temp-allowlist.
    ActivityManagerService.FgsTempAllowListItem mInfoTempFgsAllowListReason;
    // Is the same mInfoAllowStartForeground string has been logged before? Used for dedup.
    boolean mLoggedInfoAllowStartForeground;

    @PowerExemptionManager.ReasonCode
    int mAllowWIUInBindService = REASON_DENIED;

    @PowerExemptionManager.ReasonCode
    int mAllowWIUByBindings = REASON_DENIED;

    @PowerExemptionManager.ReasonCode
    int mAllowStartInBindService = REASON_DENIED;

    @PowerExemptionManager.ReasonCode
    int mAllowStartByBindings = REASON_DENIED;

    @PowerExemptionManager.ReasonCode
    int getFgsAllowWIU() {
        return mAllowWhileInUsePermissionInFgsReasonNoBinding != REASON_DENIED
                ? mAllowWhileInUsePermissionInFgsReasonNoBinding
                : mAllowWIUInBindService;
    }

    boolean isFgsAllowedWIU() {
        return getFgsAllowWIU() != REASON_DENIED;
    }

    @PowerExemptionManager.ReasonCode
    int getFgsAllowStart() {
        return mAllowStartForegroundNoBinding != REASON_DENIED
                ? mAllowStartForegroundNoBinding
                : mAllowStartInBindService;
    }

    boolean isFgsAllowedStart() {
        return getFgsAllowStart() != REASON_DENIED;
    }

    void clearFgsAllowWIU() {
        mAllowWhileInUsePermissionInFgsReasonNoBinding = REASON_DENIED;
        mAllowWIUInBindService = REASON_DENIED;
        mAllowWIUByBindings = REASON_DENIED;
    }

    void clearFgsAllowStart() {
        mAllowStartForegroundNoBinding = REASON_DENIED;
        mAllowStartInBindService = REASON_DENIED;
        mAllowStartByBindings = REASON_DENIED;
    }

    @PowerExemptionManager.ReasonCode
    int reasonOr(@PowerExemptionManager.ReasonCode int first,
            @PowerExemptionManager.ReasonCode int second) {
        return first != REASON_DENIED ? first : second;
    }

    boolean allowedChanged(@PowerExemptionManager.ReasonCode int first,
            @PowerExemptionManager.ReasonCode int second) {
        return (first == REASON_DENIED) != (second == REASON_DENIED);
    }

    String changeMessage(@PowerExemptionManager.ReasonCode int first,
            @PowerExemptionManager.ReasonCode int second) {
        return reasonOr(first, second) == REASON_DENIED ? "DENIED"
                : ("ALLOWED ("
                + reasonCodeToString(first)
                + "+"
                + reasonCodeToString(second)
                + ")");
    }

    void maybeLogFgsLogicChange() {
        final int origWiu = reasonOr(mAllowWhileInUsePermissionInFgsReasonNoBinding,
                mAllowWIUInBindService);
        final int newWiu = reasonOr(mAllowWhileInUsePermissionInFgsReasonNoBinding,
                mAllowWIUByBindings);
        final int origStart = reasonOr(mAllowStartForegroundNoBinding, mAllowStartInBindService);
        final int newStart = reasonOr(mAllowStartForegroundNoBinding, mAllowStartByBindings);

        final boolean wiuChanged = allowedChanged(origWiu, newWiu);
        final boolean startChanged = allowedChanged(origStart, newStart);

        if (!wiuChanged && !startChanged) {
            return;
        }
        final String message = "FGS logic changed:"
                + (wiuChanged ? " [WIU changed]" : "")
                + (startChanged ? " [BFSL changed]" : "")
                + " OW:" // Orig-WIU
                + changeMessage(mAllowWhileInUsePermissionInFgsReasonNoBinding,
                        mAllowWIUInBindService)
                + " NW:" // New-WIU
                + changeMessage(mAllowWhileInUsePermissionInFgsReasonNoBinding, mAllowWIUByBindings)
                + " OS:" // Orig-start
                + changeMessage(mAllowStartForegroundNoBinding, mAllowStartInBindService)
                + " NS:" // New-start
                + changeMessage(mAllowStartForegroundNoBinding, mAllowStartByBindings);
        Slog.wtf(TAG_SERVICE, message);
    }

    // The number of times Service.startForeground() is called, after this service record is
    // created. (i.e. due to "bound" or "start".) It never decreases, even when stopForeground()
    // is called.
@@ -502,7 +603,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
        ProtoUtils.toDuration(proto, ServiceRecordProto.RESTART_TIME, restartTime, now);
        proto.write(ServiceRecordProto.CREATED_FROM_FG, createdFromFg);
        proto.write(ServiceRecordProto.ALLOW_WHILE_IN_USE_PERMISSION_IN_FGS,
                mAllowWhileInUsePermissionInFgs);
                isFgsAllowedWIU());

        if (startRequested || delayedStop || lastStartId != 0) {
            long startToken = proto.start(ServiceRecordProto.START);
@@ -618,7 +719,13 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
            pw.println(mBackgroundStartPrivilegesByStartMerged);
        }
        pw.print(prefix); pw.print("mAllowWhileInUsePermissionInFgsReason=");
        pw.println(PowerExemptionManager.reasonCodeToString(mAllowWhileInUsePermissionInFgsReason));
        pw.println(PowerExemptionManager.reasonCodeToString(
                mAllowWhileInUsePermissionInFgsReasonNoBinding));

        pw.print(prefix); pw.print("mAllowWIUInBindService=");
        pw.println(PowerExemptionManager.reasonCodeToString(mAllowWIUInBindService));
        pw.print(prefix); pw.print("mAllowWIUByBindings=");
        pw.println(PowerExemptionManager.reasonCodeToString(mAllowWIUByBindings));

        pw.print(prefix); pw.print("allowUiJobScheduling="); pw.println(mAllowUiJobScheduling);
        pw.print(prefix); pw.print("recentCallingPackage=");
@@ -626,7 +733,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
        pw.print(prefix); pw.print("recentCallingUid=");
        pw.println(mRecentCallingUid);
        pw.print(prefix); pw.print("allowStartForeground=");
        pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartForeground));
        pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartForegroundNoBinding));
        pw.print(prefix); pw.print("mAllowStartInBindService=");
        pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartInBindService));
        pw.print(prefix); pw.print("mAllowStartByBindings=");
        pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartByBindings));

        pw.print(prefix); pw.print("startForegroundCount=");
        pw.println(mStartForegroundCount);
        pw.print(prefix); pw.print("infoAllowStartForeground=");