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

Commit 6669dec0 authored by Kevin Han's avatar Kevin Han
Browse files

Move AppHibernationServices dependencies to injector

Similar to other system services, we move AppHibernationService's
dependencies to an injector class that can be mocked for testing so that
we minimize side-effects in unit tests

Also, add @GuardedBy annotations instead of having an L at the end of
method names since this is exactly what the annotation is for.

Bug: 175829330
Test: atest AppHibernationServiceTest
Change-Id: Iec51a349ff898923bacf6040c3ebccefa8831a68
parent 89575897
Loading
Loading
Loading
Loading
+66 −26
Original line number Diff line number Diff line
@@ -88,19 +88,16 @@ public final class AppHibernationService extends SystemService {
     * @param context The system server context.
     */
    public AppHibernationService(@NonNull Context context) {
        this(context, IPackageManager.Stub.asInterface(ServiceManager.getService("package")),
                ActivityManager.getService(),
                context.getSystemService(UserManager.class));
        this(new InjectorImpl(context));
    }

    @VisibleForTesting
    AppHibernationService(@NonNull Context context, IPackageManager packageManager,
            IActivityManager activityManager, UserManager userManager) {
        super(context);
        mContext = context;
        mIPackageManager = packageManager;
        mIActivityManager = activityManager;
        mUserManager = userManager;
    AppHibernationService(@NonNull Injector injector) {
        super(injector.getContext());
        mContext = injector.getContext();
        mIPackageManager = injector.getPackageManager();
        mIActivityManager = injector.getActivityManager();
        mUserManager = injector.getUserManager();

        final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);

@@ -182,9 +179,9 @@ public final class AppHibernationService extends SystemService {
            }

            if (isHibernating) {
                hibernatePackageForUserL(packageName, userId, pkgState);
                hibernatePackageForUser(packageName, userId, pkgState);
            } else {
                unhibernatePackageForUserL(packageName, userId, pkgState);
                unhibernatePackageForUser(packageName, userId, pkgState);
            }
        }
    }
@@ -200,9 +197,9 @@ public final class AppHibernationService extends SystemService {
        if (isHibernating != mGloballyHibernatedPackages.contains(packageName)) {
            synchronized (mLock) {
                if (isHibernating) {
                    hibernatePackageGloballyL(packageName);
                    hibernatePackageGlobally(packageName);
                } else {
                    unhibernatePackageGloballyL(packageName);
                    unhibernatePackageGlobally(packageName);
                }
            }
        }
@@ -210,11 +207,11 @@ public final class AppHibernationService extends SystemService {

    /**
     * Put an app into hibernation for a given user, allowing user-level optimizations to occur.
     * The caller should hold {@link #mLock}
     *
     * @param pkgState package hibernation state
     */
    private void hibernatePackageForUserL(@NonNull String packageName, int userId,
    @GuardedBy("mLock")
    private void hibernatePackageForUser(@NonNull String packageName, int userId,
            @NonNull UserPackageState pkgState) {
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
        final long caller = Binder.clearCallingIdentity();
@@ -233,11 +230,12 @@ public final class AppHibernationService extends SystemService {
    }

    /**
     * Remove a package from hibernation for a given user. The caller should hold {@link #mLock}.
     * Remove a package from hibernation for a given user.
     *
     * @param pkgState package hibernation state
     */
    private void unhibernatePackageForUserL(@NonNull String packageName, int userId,
    @GuardedBy("mLock")
    private void unhibernatePackageForUser(@NonNull String packageName, int userId,
            UserPackageState pkgState) {
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
        final long caller = Binder.clearCallingIdentity();
@@ -255,9 +253,9 @@ public final class AppHibernationService extends SystemService {

    /**
     * Put a package into global hibernation, optimizing its storage at a package / APK level.
     * The caller should hold {@link #mLock}.
     */
    private void hibernatePackageGloballyL(@NonNull String packageName) {
    @GuardedBy("mLock")
    private void hibernatePackageGlobally(@NonNull String packageName) {
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
        // TODO(175830194): Delete vdex/odex when DexManager API is built out
        mGloballyHibernatedPackages.add(packageName);
@@ -265,21 +263,22 @@ public final class AppHibernationService extends SystemService {
    }

    /**
     * Unhibernate a package from global hibernation. The caller should hold {@link #mLock}.
     * Unhibernate a package from global hibernation.
     */
    private void unhibernatePackageGloballyL(@NonNull String packageName) {
    @GuardedBy("mLock")
    private void unhibernatePackageGlobally(@NonNull String packageName) {
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackageGlobally");
        mGloballyHibernatedPackages.remove(packageName);
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }

    /**
     * Populates {@link #mUserStates} with the users installed packages. The caller should hold
     * {@link #mLock}.
     * Populates {@link #mUserStates} with the users installed packages.
     *
     * @param userId user id to add installed packages for
     */
    private void addUserPackageStatesL(int userId) {
    @GuardedBy("mLock")
    private void addUserPackageStates(int userId) {
        Map<String, UserPackageState> packages = new ArrayMap<>();
        List<PackageInfo> packageList;
        try {
@@ -298,7 +297,7 @@ public final class AppHibernationService extends SystemService {
    public void onUserUnlocking(@NonNull TargetUser user) {
        // TODO: Pull from persistent disk storage. For now, just make from scratch.
        synchronized (mLock) {
            addUserPackageStatesL(user.getUserIdentifier());
            addUserPackageStates(user.getUserIdentifier());
        }
    }

@@ -431,4 +430,45 @@ public final class AppHibernationService extends SystemService {
        public boolean hibernated;
        // TODO: Track whether hibernation is exempted by the user
    }

    /**
     * Dependency injector for {@link #AppHibernationService)}.
     */
    interface Injector {
        Context getContext();

        IPackageManager getPackageManager();

        IActivityManager getActivityManager();

        UserManager getUserManager();
    }

    private static final class InjectorImpl implements Injector {
        private final Context mContext;

        InjectorImpl(Context context) {
            mContext = context;
        }

        @Override
        public Context getContext() {
            return mContext;
        }

        @Override
        public IPackageManager getPackageManager() {
            return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
        }

        @Override
        public IActivityManager getActivityManager() {
            return ActivityManager.getService();
        }

        @Override
        public UserManager getUserManager() {
            return mContext.getSystemService(UserManager.class);
        }
    }
}
+29 −2
Original line number Diff line number Diff line
@@ -83,8 +83,7 @@ public final class AppHibernationServiceTest {
        MockitoAnnotations.initMocks(this);
        doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());

        mAppHibernationService = new AppHibernationService(mContext, mIPackageManager,
                mIActivityManager, mUserManager);
        mAppHibernationService = new AppHibernationService(new MockInjector(mContext));

        verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
        mBroadcastReceiver = mReceiverCaptor.getValue();
@@ -187,4 +186,32 @@ public final class AppHibernationServiceTest {
        pkg.packageName = packageName;
        return pkg;
    }

    private class MockInjector implements AppHibernationService.Injector {
        private final Context mContext;

        MockInjector(Context context) {
            mContext = context;
        }

        @Override
        public IActivityManager getActivityManager() {
            return mIActivityManager;
        }

        @Override
        public Context getContext() {
            return mContext;
        }

        @Override
        public IPackageManager getPackageManager() {
            return mIPackageManager;
        }

        @Override
        public UserManager getUserManager() {
            return mUserManager;
        }
    }
}