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

Commit 805d08ae authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "Enable FGS BG start restriction for apps targeting S"

parents dba641eb 16d42932
Loading
Loading
Loading
Loading
+55 −11
Original line number Diff line number Diff line
@@ -61,7 +61,6 @@ import android.app.admin.DevicePolicyEventLogger;
import android.app.compat.CompatChanges;
import android.appwidget.AppWidgetManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.ComponentName.WithComponentName;
@@ -108,6 +107,7 @@ import android.webkit.WebViewZygote;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ServiceState;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.notification.SystemNotificationChannels;
@@ -275,7 +275,7 @@ public final class ActiveServices {
     * is higher than R.
     */
    @ChangeId
    @Disabled
    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
    static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;

    /**
@@ -307,9 +307,40 @@ public final class ActiveServices {
     */
    private static final ArraySet<String> sFgsBgStartExemptedPackages = new ArraySet<>();

    private static final ArrayList<String> sFgsBgStartExemptedPackagePrefixes = new ArrayList<>();

    /**
     * List of packages that are exempted from the FGS restriction *for now*.
     *
     * STOPSHIP(/b/176844961) Remove it. Also update ActiveServicesTest.java.
     */
    private static final String[] FGS_BG_START_EXEMPTED_PACKAGES = {
            "com.google.pixel.exo.bootstrapping",
    };

    /**
     * List of packages that are exempted from the FGS restriction *for now*. We also allow
     * any packages that
     *
     * STOPSHIP(/b/176844961) Remove it. Also update ActiveServicesTest.java.
     */
    private static final String[] FGS_BG_START_EXEMPTED_PACKAGES_PREFIXED_ALLOWED = {
            "com.android.webview",
            "com.google.android.webview",
            "com.android.chrome",
            "com.google.android.apps.chrome",
            "com.chrome",
    };

    static {
        sFgsBgStartExemptedPackages.add("com.google.pixel.exo.bootstrapping"); //STOPSHIP Remove it.
        sFgsBgStartExemptedPackages.add("com.android.chrome"); // STOPSHIP Remove it.
        for (String s : FGS_BG_START_EXEMPTED_PACKAGES) {
            sFgsBgStartExemptedPackages.add(s);
        }

        for (String s : FGS_BG_START_EXEMPTED_PACKAGES_PREFIXED_ALLOWED) {
            sFgsBgStartExemptedPackages.add(s); // Add it for an exact match.
            sFgsBgStartExemptedPackagePrefixes.add(s + "."); // Add it for an prefix match.
        }
    }

    final Runnable mLastAnrDumpClearer = new Runnable() {
@@ -5365,10 +5396,25 @@ public final class ActiveServices {
        return ret;
    }

    private boolean isPackageExemptedFromFgsRestriction(String packageName, int uid) {
        if (!sFgsBgStartExemptedPackages.contains(packageName)) {
            return false;
    @VisibleForTesting
    static boolean isPackageExemptedFromFgsRestriction(String packageName, int uid) {
        boolean exempted = false;
        if (sFgsBgStartExemptedPackages.contains(packageName)) {
            exempted = true;
        } else {
            for (String pkg : sFgsBgStartExemptedPackagePrefixes) {
                if (packageName.startsWith(pkg)) {
                    exempted = true;
                    break;
                }
            }
        }
        if (!exempted) {
            return false; // Package isn't exempted.
        }
        // Allow exempted packages to be subject to the restriction using this compat ID.
        // (so that, for example, the webview developer will be able to test the restriction
        // locally.)
        return CompatChanges.isChangeEnabled(FGS_BG_START_USE_EXEMPTION_LIST_CHANGE_ID, uid);
    }

@@ -5451,9 +5497,7 @@ public final class ActiveServices {
    }

    private boolean isBgFgsRestrictionEnabled(ServiceRecord r) {
        if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) {
            return true;
        }
        return CompatChanges.isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r.appInfo.uid);
        return mAm.mConstants.mFlagFgsStartRestrictionEnabled
                && CompatChanges.isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r.appInfo.uid);
    }
}
+4 −3
Original line number Diff line number Diff line
@@ -360,10 +360,11 @@ final class ActivityManagerConstants extends ContentObserver {
    // started, the restriction is on while-in-use permissions.)
    volatile boolean mFlagBackgroundFgsStartRestrictionEnabled = true;

    // Indicates whether the foreground service background start restriction is enabled.
    // Indicates whether the foreground service background start restriction is enabled for
    // apps targeting S+.
    // When the restriction is enabled, service is not allowed to startForeground from background
    // at all.
    volatile boolean mFlagFgsStartRestrictionEnabled = false;
    volatile boolean mFlagFgsStartRestrictionEnabled = true;

    // Whether we defer FGS notifications a few seconds following their transition to
    // the foreground state.  Applies only to S+ apps; enabled by default.
@@ -792,7 +793,7 @@ final class ActivityManagerConstants extends ContentObserver {
        mFlagFgsStartRestrictionEnabled = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED,
                /*defaultValue*/ false);
                /*defaultValue*/ true);
    }

    private void updateFgsNotificationDeferralEnable() {
+95 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server.am;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.am.ActiveServices.FGS_BG_START_USE_EXEMPTION_LIST_CHANGE_ID;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;

import android.app.compat.CompatChanges;

import androidx.test.runner.AndroidJUnit4;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;



@RunWith(AndroidJUnit4.class)
public class ActiveServicesTest {

    private MockitoSession mMockingSession;

    @Before
    public void setUp() {
        mMockingSession = mockitoSession()
                .initMocks(this)
                .strictness(Strictness.LENIENT)
                .mockStatic(CompatChanges.class)
                .startMocking();
    }

    @After
    public void tearDown() {
        if (mMockingSession != null) {
            mMockingSession.finishMocking();
        }
    }

    private void checkPackageExempted(String pkg, int uid, boolean expected) {
        assertEquals("Package=" + pkg + " uid=" + uid,
                expected, ActiveServices.isPackageExemptedFromFgsRestriction(pkg, uid));
    }

    @Test
    public void isPackageExemptedFromFgsRestriction() {
        // Compat changes are enabled by default.
        when(CompatChanges.isChangeEnabled(anyLong(), anyInt())).thenReturn(true);

        checkPackageExempted("", 1, false);
        checkPackageExempted("abc", 1, false);
        checkPackageExempted("com.random", 1, false);

        // This package is exempted but not its subpackages.
        checkPackageExempted("com.google.pixel.exo.bootstrapping", 1, true);
        checkPackageExempted("com.google.pixel.exo.bootstrapping.subpackage", 1, false);

        // Subpackages are also exempted.
        checkPackageExempted("com.android.webview", 1, true);
        checkPackageExempted("com.android.webview.beta", 1, true);
        checkPackageExempted("com.chrome", 1, true);
        checkPackageExempted("com.chrome.canary", 1, true);

        checkPackageExempted("com.android.webviewx", 1, false);

        // Now toggle the compat ID for a specific UID.
        when(CompatChanges.isChangeEnabled(FGS_BG_START_USE_EXEMPTION_LIST_CHANGE_ID, 10))
                .thenReturn(false);
        // Exempted package, but compat id is disabled for the UID.
        checkPackageExempted("com.android.webview", 10, false);

        // Exempted package, but compat id is still enabled for the UID.
        checkPackageExempted("com.android.webview", 11, true);
    }
}