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

Commit f1e9e1b2 authored by Kweku Adams's avatar Kweku Adams
Browse files

Give headless system apps a higher min balance.

Pre-installed apps without a "front door" activity (an activity that
is directly from the launcher) won't be interacted with much by the
user, but can be expected to do work in the background on behalf of
the user. As such, give these apps a higher minimum satiated balance
so they can do the work they need to.

Bug: 202954395
Test: atest FrameworksMockingServicesTests:AlarmManagerEconomicPolicyTest
Test: atest FrameworksMockingServicesTests:CompleteEconomicPolicyTest
Test: atest FrameworksMockingServicesTests:JobSchedulerEconomicPolicyTest
Change-Id: I79b85c808adcba017de092525d5a0084f7c10834
parent 0b5e5e38
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
        if (mIrs.isPackageExempted(userId, pkgName)) {
            return mMinSatiatedBalanceExempted;
        }
        if (mIrs.isHeadlessSystemApp(pkgName)) {
        if (mIrs.isHeadlessSystemApp(userId, pkgName)) {
            return mMinSatiatedBalanceHeadlessSystemApp;
        }
        // TODO: take other exemptions into account
+38 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.content.Context;
import android.content.Intent;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
@@ -35,9 +36,23 @@ import com.android.internal.util.ArrayUtils;
class InstalledPackageInfo {
    static final int NO_UID = -1;

    /**
     * Flags to use when querying for front door activities. Disabled components are included
     * are included for completeness since the app can enable them at any time.
     */
    private static final int HEADLESS_APP_QUERY_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE
            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
            | PackageManager.MATCH_DISABLED_COMPONENTS;

    public final int uid;
    public final String packageName;
    public final boolean hasCode;
    /**
     * Whether the app is a system app that is "headless." Headless in this context means that
     * the app doesn't have any "front door" activities --- activities that would show in the
     * launcher.
     */
    public final boolean isHeadlessSystemApp;
    public final boolean isSystemInstaller;
    @Nullable
    public final String installerPackageName;
@@ -48,6 +63,17 @@ class InstalledPackageInfo {
        uid = applicationInfo == null ? NO_UID : applicationInfo.uid;
        packageName = packageInfo.packageName;
        hasCode = applicationInfo != null && applicationInfo.hasCode();

        final PackageManager packageManager = context.getPackageManager();
        final Intent frontDoorActivityIntent = new Intent(Intent.ACTION_MAIN)
                .addCategory(Intent.CATEGORY_LAUNCHER)
                .setPackage(packageName);
        isHeadlessSystemApp = applicationInfo != null
                && (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp())
                && ArrayUtils.isEmpty(
                        packageManager.queryIntentActivitiesAsUser(
                                frontDoorActivityIntent, HEADLESS_APP_QUERY_FLAGS, userId));

        isSystemInstaller = applicationInfo != null
                && ArrayUtils.indexOf(
                packageInfo.requestedPermissions, Manifest.permission.INSTALL_PACKAGES) >= 0
@@ -65,4 +91,16 @@ class InstalledPackageInfo {
        installerPackageName =
                installSourceInfo == null ? null : installSourceInfo.getInstallingPackageName();
    }

    @Override
    public String toString() {
        return "IPO{"
                + "uid=" + uid
                + ", pkgName=" + packageName
                + (hasCode ? " HAS_CODE" : "")
                + (isHeadlessSystemApp ? " HEADLESS_SYSTEM" : "")
                + (isSystemInstaller ? " SYSTEM_INSTALLER" : "")
                + ", installer=" + installerPackageName
                + '}';
    }
}
+40 −1
Original line number Diff line number Diff line
@@ -501,12 +501,16 @@ public class InternalResourceService extends SystemService {
        }
    }

    boolean isHeadlessSystemApp(@NonNull String pkgName) {
    boolean isHeadlessSystemApp(final int userId, @NonNull String pkgName) {
        if (pkgName == null) {
            Slog.wtfStack(TAG, "isHeadlessSystemApp called with null package");
            return false;
        }
        synchronized (mLock) {
            final InstalledPackageInfo ipo = getInstalledPackageInfo(userId, pkgName);
            if (ipo != null && ipo.isHeadlessSystemApp) {
                return true;
            }
            // The wellbeing app is pre-set on the device, not expected to be interacted with
            // much by the user, but can be expected to do work in the background on behalf of
            // the user. As such, it's a pseudo-headless system app, so treat it as a headless
@@ -1754,6 +1758,10 @@ public class InternalResourceService extends SystemService {
            pw.print("Exempted apps", mExemptedApps);
            pw.println();

            pw.println();
            pw.print("Wellbeing app=");
            pw.println(mWellbeingPackage == null ? "None" : mWellbeingPackage);

            boolean printedVips = false;
            pw.println();
            pw.print("VIPs:");
@@ -1832,6 +1840,37 @@ public class InternalResourceService extends SystemService {

            pw.println();
            mAnalyst.dump(pw);

            // Put this at the end since this may be a lot and we want to have the earlier
            // information easily accessible.
            boolean printedInterestingIpos = false;
            pw.println();
            pw.print("Interesting apps:");
            pw.increaseIndent();
            for (int u = 0; u < mPkgCache.numMaps(); ++u) {
                for (int p = 0; p < mPkgCache.numElementsForKeyAt(u); ++p) {
                    final InstalledPackageInfo ipo = mPkgCache.valueAt(u, p);

                    // Printing out every single app will be too much. Only print apps that
                    // have some interesting characteristic.
                    final boolean isInteresting = ipo.hasCode
                            && ipo.isHeadlessSystemApp
                            && !UserHandle.isCore(ipo.uid);
                    if (!isInteresting) {
                        continue;
                    }

                    printedInterestingIpos = true;
                    pw.println();
                    pw.print(ipo);
                }
            }
            if (printedInterestingIpos) {
                pw.println();
            } else {
                pw.print(" None");
            }
            pw.decreaseIndent();
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -197,7 +197,7 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
        final long baseBalance;
        if (mIrs.isPackageExempted(userId, pkgName)) {
            baseBalance = mMinSatiatedBalanceExempted;
        } else if (mIrs.isHeadlessSystemApp(pkgName)) {
        } else if (mIrs.isHeadlessSystemApp(userId, pkgName)) {
            baseBalance = mMinSatiatedBalanceHeadlessSystemApp;
        } else {
            baseBalance = mMinSatiatedBalanceOther;
+3 −3
Original line number Diff line number Diff line
@@ -150,7 +150,7 @@ public class AlarmManagerEconomicPolicyTest {
                mEconomicPolicy.getMaxSatiatedBalance(0, pkgExempted));

        final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
        when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
        when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
        assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES,
                mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
        assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
@@ -184,7 +184,7 @@ public class AlarmManagerEconomicPolicyTest {
        when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
        assertEquals(arcToCake(9), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
        final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
        when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
        when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
        assertEquals(arcToCake(8), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
        assertEquals(arcToCake(7), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
    }
@@ -212,7 +212,7 @@ public class AlarmManagerEconomicPolicyTest {
        when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
        assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
        final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
        when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
        when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
        assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
        assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));

Loading