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

Commit 34f0857a authored by Eghosa Ewansiha-Vlachavas's avatar Eghosa Ewansiha-Vlachavas
Browse files

Exempt from app standby logic

When AppOpsManager.OP_SYSTEM_EXEMPT_FROM_APP_STANDBY is set to
AppOpsManager.MODE_ALLOWED, app should be placed into
UsageStatsManager.STANDBY_BUCKET_EXEMPT. Otherwise app standby buckets
should behave as normal.

Test: atest AppStandbyControllerTests
Test: Manual testing:
	Install test dpc and set as role holder.
	Navigate to "Set Application Exemptions" in Application
	Exemptions category.
	Choose app and select "Exempt from App Standby" and click save.
	run "adb shell am get-standby-bucket packageName" where the
	package name is the name the app selected previously (can be
	viewed in the toast followed after setting the exemptions).
	Returned value should be 5 (standby bucket exempt).
	Navigate back to "Set Application Exemptions" in testDpc and
	save exemptions with "Exempt from App Standby" unchecked.
	Running "adb shell am get-standby-bucket packageName" should now
	return a value other then 5.
Bug: 246330879
Change-Id: I8f28a15552e524cbb9cbd2c8c23fd6026d9341f9
parent 634989cd
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager.ForcedReasons;
@@ -108,6 +109,7 @@ import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.view.Display;
@@ -116,6 +118,8 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ConcurrentUtils;
@@ -279,6 +283,13 @@ public class AppStandbyController
    @GuardedBy("mPendingIdleStateChecks")
    private final SparseLongArray mPendingIdleStateChecks = new SparseLongArray();

    /**
     * Map of uids to their current app-op mode for
     * {@link AppOpsManager#OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY}.
     */
    @GuardedBy("mSystemExemptionAppOpMode")
    private final SparseIntArray mSystemExemptionAppOpMode = new SparseIntArray();

    // Cache the active network scorer queried from the network scorer service
    private volatile String mCachedNetworkScorer = null;
    // The last time the network scorer service was queried
@@ -488,6 +499,7 @@ public class AppStandbyController

    private AppWidgetManager mAppWidgetManager;
    private PackageManager mPackageManager;
    private AppOpsManager mAppOpsManager;
    Injector mInjector;

    private static class Pool<T> {
@@ -647,6 +659,28 @@ public class AppStandbyController
            settingsObserver.start();

            mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
            mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
            IAppOpsService iAppOpsService = mInjector.getAppOpsService();
            try {
                iAppOpsService.startWatchingMode(
                        AppOpsManager.OP_SYSTEM_EXEMPT_FROM_APP_STANDBY,
                        /*packageName=*/ null,
                        new IAppOpsCallback.Stub() {
                            @Override
                            public void opChanged(int op, int uid, String packageName) {
                                final int userId = UserHandle.getUserId(uid);
                                synchronized (mSystemExemptionAppOpMode) {
                                    mSystemExemptionAppOpMode.delete(uid);
                                }
                                mHandler.obtainMessage(
                                        MSG_CHECK_PACKAGE_IDLE_STATE, userId, uid, packageName)
                                        .sendToTarget();
                            }
                        });
            } catch (RemoteException e) {
                // Should not happen.
                Slog.wtf(TAG, "Failed start watching for app op", e);
            }

            mInjector.registerDisplayListener(mDisplayListener, mHandler);
            synchronized (mAppIdleLock) {
@@ -1417,6 +1451,23 @@ public class AppStandbyController
                return STANDBY_BUCKET_EXEMPTED;
            }

            final int uid = UserHandle.getUid(userId, appId);
            synchronized (mSystemExemptionAppOpMode) {
                if (mSystemExemptionAppOpMode.indexOfKey(uid) >= 0) {
                    if (mSystemExemptionAppOpMode.get(uid)
                            == AppOpsManager.MODE_ALLOWED) {
                        return STANDBY_BUCKET_EXEMPTED;
                    }
                } else {
                    int mode = mAppOpsManager.checkOpNoThrow(
                            AppOpsManager.OP_SYSTEM_EXEMPT_FROM_APP_STANDBY, uid, packageName);
                    mSystemExemptionAppOpMode.put(uid, mode);
                    if (mode == AppOpsManager.MODE_ALLOWED) {
                        return STANDBY_BUCKET_EXEMPTED;
                    }
                }
            }

            if (mAppWidgetManager != null
                    && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) {
                return STANDBY_BUCKET_ACTIVE;
@@ -2129,6 +2180,12 @@ public class AppStandbyController
                    clearAppIdleForPackage(pkgName, userId);
                }
            }
            synchronized (mSystemExemptionAppOpMode) {
                if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                    mSystemExemptionAppOpMode.delete(UserHandle.getUid(userId, getAppId(pkgName)));
                }
            }

        }
    }

@@ -2524,6 +2581,11 @@ public class AppStandbyController
            }
        }

        IAppOpsService getAppOpsService() {
            return IAppOpsService.Stub.asInterface(
                    ServiceManager.getService(Context.APP_OPS_SERVICE));
        }

        /**
         * Returns {@code true} if the supplied package is the wellbeing app. Otherwise,
         * returns {@code false}.