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

Commit 56c451a0 authored by Kevin Han's avatar Kevin Han
Browse files

Unhibernate when an app is no longer force-stopped.

To ensure we don't end up in scenarios where an app is hibernated but
not force-stopped, we unhibernate at both the user and package level
when an app is no longer force-stopped.

Bug: 175829330
Test: adb shell cmd app_hibernation set-state
com.google.android.deskclock true
Launch the app
adb shell cmd app_hibernation get-state com.google.android.deskclock

Change-Id: I0a0b1747b129a64f63f08b6d0c51954a77c3c73d
parent 0dac4408
Loading
Loading
Loading
Loading
+2 −11
Original line number Original line Diff line number Diff line
@@ -314,18 +314,9 @@ public final class AppHibernationService extends SystemService {
    private void unhibernatePackageForUser(@NonNull String packageName, int userId,
    private void unhibernatePackageForUser(@NonNull String packageName, int userId,
            UserLevelState pkgState) {
            UserLevelState pkgState) {
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
        final long caller = Binder.clearCallingIdentity();
        try {
            mIPackageManager.setPackageStoppedState(packageName, false, userId);
        pkgState.hibernated = false;
        pkgState.hibernated = false;
        } catch (RemoteException e) {
            throw new IllegalStateException(
                    "Failed to unhibernate due to manager not being available", e);
        } finally {
            Binder.restoreCallingIdentity(caller);
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
    }
    }


    /**
    /**
     * Put a package into global hibernation, optimizing its storage at a package / APK level.
     * Put a package into global hibernation, optimizing its storage at a package / APK level.
+11 −0
Original line number Original line Diff line number Diff line
@@ -367,6 +367,7 @@ import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.SystemConfig;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.Watchdog;
import com.android.server.Watchdog;
import com.android.server.apphibernation.AppHibernationManagerInternal;
import com.android.server.compat.CompatChange;
import com.android.server.compat.CompatChange;
import com.android.server.compat.PlatformCompat;
import com.android.server.compat.PlatformCompat;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -23400,15 +23401,25 @@ public class PackageManagerService extends IPackageManager.Stub
        final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
        final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
        enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
        enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
                true /* checkShell */, "stop package");
                true /* checkShell */, "stop package");
        boolean shouldUnhibernate = false;
        // writer
        // writer
        synchronized (mLock) {
        synchronized (mLock) {
            final PackageSetting ps = mSettings.getPackageLPr(packageName);
            final PackageSetting ps = mSettings.getPackageLPr(packageName);
            if (ps.getStopped(userId) && !stopped) {
                shouldUnhibernate = true;
            }
            if (!shouldFilterApplicationLocked(ps, callingUid, userId)
            if (!shouldFilterApplicationLocked(ps, callingUid, userId)
                    && mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
                    && mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
                            allowedByPermission, callingUid, userId)) {
                            allowedByPermission, callingUid, userId)) {
                scheduleWritePackageRestrictionsLocked(userId);
                scheduleWritePackageRestrictionsLocked(userId);
            }
            }
        }
        }
        if (shouldUnhibernate) {
            AppHibernationManagerInternal ah =
                    mInjector.getLocalService(AppHibernationManagerInternal.class);
            ah.setHibernatingForUser(packageName, userId, false);
            ah.setHibernatingGlobally(packageName, false);
        }
    }
    }
    @Override
    @Override
+1 −0
Original line number Original line Diff line number Diff line
@@ -287,6 +287,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
        whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO)
        whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO)
        whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
        whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
        whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
        whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
        whenever(mocks.settings.snapshot()).thenReturn(mocks.settings)
        whenever(mocks.packageAbiHelper.derivePackageAbi(
        whenever(mocks.packageAbiHelper.derivePackageAbi(
                any(AndroidPackage::class.java), anyBoolean(), nullable(), any(File::class.java))) {
                any(AndroidPackage::class.java), anyBoolean(), nullable(), any(File::class.java))) {
            android.util.Pair(PackageAbiHelper.Abis("", ""),
            android.util.Pair(PackageAbiHelper.Abis("", ""),
+81 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2021 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.pm

import android.os.Build
import com.android.server.apphibernation.AppHibernationManagerInternal
import com.android.server.testutils.whenever
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@RunWith(JUnit4::class)
class PackageManagerServiceHibernationTests {

    companion object {
        val TEST_PACKAGE_NAME = "test.package"
        val TEST_USER_ID = 0
    }

    @Rule
    @JvmField
    val rule = MockSystemRule()

    @Mock
    lateinit var appHibernationManager: AppHibernationManagerInternal

    @Before
    @Throws(Exception::class)
    fun setup() {
        MockitoAnnotations.initMocks(this)
        rule.system().stageNominalSystemState()
        whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java))
            .thenReturn(appHibernationManager)
    }

    @Test
    fun testExitForceStopExitsHibernation() {
        rule.system().stageScanExistingPackage(
            TEST_PACKAGE_NAME,
            1L,
            rule.system().dataAppDirectory)
        val pm = createPackageManagerService()
        rule.system().validateFinalState()
        val ps = pm.getPackageSetting(TEST_PACKAGE_NAME)
        ps!!.setStopped(true, TEST_USER_ID)

        pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
        verify(appHibernationManager).setHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID, false)
        verify(appHibernationManager).setHibernatingGlobally(TEST_PACKAGE_NAME, false)
    }

    private fun createPackageManagerService(): PackageManagerService {
        return PackageManagerService(rule.mocks().injector,
            false /*coreOnly*/,
            false /*factoryTest*/,
            MockSystem.DEFAULT_VERSION_INFO.fingerprint,
            false /*isEngBuild*/,
            false /*isUserDebugBuild*/,
            Build.VERSION_CODES.CUR_DEVELOPMENT,
            Build.VERSION.INCREMENTAL)
    }
}