Merge "Don't hold hibernation lock when calling other services" into sc-v2-dev
This commit is contained in:
@@ -277,16 +277,16 @@ public final class AppHibernationService extends SystemService {
|
|||||||
getContext().enforceCallingOrSelfPermission(
|
getContext().enforceCallingOrSelfPermission(
|
||||||
android.Manifest.permission.MANAGE_APP_HIBERNATION,
|
android.Manifest.permission.MANAGE_APP_HIBERNATION,
|
||||||
"Caller does not have MANAGE_APP_HIBERNATION permission.");
|
"Caller does not have MANAGE_APP_HIBERNATION permission.");
|
||||||
userId = handleIncomingUser(userId, methodName);
|
final int realUserId = handleIncomingUser(userId, methodName);
|
||||||
if (!checkUserStatesExist(userId, methodName)) {
|
if (!checkUserStatesExist(realUserId, methodName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final Map<String, UserLevelState> packageStates = mUserStates.get(userId);
|
final Map<String, UserLevelState> packageStates = mUserStates.get(realUserId);
|
||||||
final UserLevelState pkgState = packageStates.get(packageName);
|
final UserLevelState pkgState = packageStates.get(packageName);
|
||||||
if (pkgState == null) {
|
if (pkgState == null) {
|
||||||
Slog.e(TAG, String.format("Package %s is not installed for user %s",
|
Slog.e(TAG, String.format("Package %s is not installed for user %s",
|
||||||
packageName, userId));
|
packageName, realUserId));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,13 +294,17 @@ public final class AppHibernationService extends SystemService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pkgState.hibernated = isHibernating;
|
||||||
if (isHibernating) {
|
if (isHibernating) {
|
||||||
hibernatePackageForUser(packageName, userId, pkgState);
|
mBackgroundExecutor.execute(() -> hibernatePackageForUser(packageName, realUserId));
|
||||||
} else {
|
} else {
|
||||||
unhibernatePackageForUser(packageName, userId, pkgState);
|
mBackgroundExecutor.execute(
|
||||||
|
() -> unhibernatePackageForUser(packageName, realUserId));
|
||||||
|
pkgState.lastUnhibernatedMs = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
final UserLevelState stateSnapshot = new UserLevelState(pkgState);
|
final UserLevelState stateSnapshot = new UserLevelState(pkgState);
|
||||||
final int userIdSnapshot = userId;
|
final int userIdSnapshot = realUserId;
|
||||||
mBackgroundExecutor.execute(() -> {
|
mBackgroundExecutor.execute(() -> {
|
||||||
FrameworkStatsLog.write(
|
FrameworkStatsLog.write(
|
||||||
FrameworkStatsLog.USER_LEVEL_HIBERNATION_STATE_CHANGED,
|
FrameworkStatsLog.USER_LEVEL_HIBERNATION_STATE_CHANGED,
|
||||||
@@ -308,8 +312,8 @@ public final class AppHibernationService extends SystemService {
|
|||||||
userIdSnapshot,
|
userIdSnapshot,
|
||||||
stateSnapshot.hibernated);
|
stateSnapshot.hibernated);
|
||||||
});
|
});
|
||||||
List<UserLevelState> states = new ArrayList<>(mUserStates.get(userId).values());
|
List<UserLevelState> states = new ArrayList<>(mUserStates.get(realUserId).values());
|
||||||
mUserDiskStores.get(userId).scheduleWriteHibernationStates(states);
|
mUserDiskStores.get(realUserId).scheduleWriteHibernationStates(states);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,10 +338,12 @@ public final class AppHibernationService extends SystemService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (state.hibernated != isHibernating) {
|
if (state.hibernated != isHibernating) {
|
||||||
|
state.hibernated = isHibernating;
|
||||||
if (isHibernating) {
|
if (isHibernating) {
|
||||||
hibernatePackageGlobally(packageName, state);
|
mBackgroundExecutor.execute(() -> hibernatePackageGlobally(packageName, state));
|
||||||
} else {
|
} else {
|
||||||
unhibernatePackageGlobally(packageName, state);
|
state.savedByte = 0;
|
||||||
|
state.lastUnhibernatedMs = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
List<GlobalLevelState> states = new ArrayList<>(mGlobalHibernationStates.values());
|
List<GlobalLevelState> states = new ArrayList<>(mGlobalHibernationStates.values());
|
||||||
mGlobalLevelHibernationDiskStore.scheduleWriteHibernationStates(states);
|
mGlobalLevelHibernationDiskStore.scheduleWriteHibernationStates(states);
|
||||||
@@ -374,20 +380,16 @@ public final class AppHibernationService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put an app into hibernation for a given user, allowing user-level optimizations to occur.
|
* Put an app into hibernation for a given user, allowing user-level optimizations to occur. Do
|
||||||
*
|
* not hold {@link #mLock} while calling this to avoid deadlock scenarios.
|
||||||
* @param pkgState package hibernation state
|
|
||||||
*/
|
*/
|
||||||
@GuardedBy("mLock")
|
private void hibernatePackageForUser(@NonNull String packageName, int userId) {
|
||||||
private void hibernatePackageForUser(@NonNull String packageName, int userId,
|
|
||||||
@NonNull UserLevelState pkgState) {
|
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
|
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
|
||||||
final long caller = Binder.clearCallingIdentity();
|
final long caller = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
mIActivityManager.forceStopPackage(packageName, userId);
|
mIActivityManager.forceStopPackage(packageName, userId);
|
||||||
mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
|
mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
|
||||||
null /* observer */);
|
null /* observer */);
|
||||||
pkgState.hibernated = true;
|
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Failed to hibernate due to manager not being available", e);
|
"Failed to hibernate due to manager not being available", e);
|
||||||
@@ -398,16 +400,11 @@ public final class AppHibernationService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a package from hibernation for a given user.
|
* Remove a package from hibernation for a given user. Do not hold {@link #mLock} while calling
|
||||||
*
|
* this.
|
||||||
* @param pkgState package hibernation state
|
|
||||||
*/
|
*/
|
||||||
@GuardedBy("mLock")
|
private void unhibernatePackageForUser(@NonNull String packageName, int userId) {
|
||||||
private void unhibernatePackageForUser(@NonNull String packageName, int userId,
|
|
||||||
UserLevelState pkgState) {
|
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
|
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
|
||||||
pkgState.hibernated = false;
|
|
||||||
pkgState.lastUnhibernatedMs = System.currentTimeMillis();
|
|
||||||
final long caller = Binder.clearCallingIdentity();
|
final long caller = Binder.clearCallingIdentity();
|
||||||
// Deliver LOCKED_BOOT_COMPLETE AND BOOT_COMPLETE broadcast so app can re-register
|
// Deliver LOCKED_BOOT_COMPLETE AND BOOT_COMPLETE broadcast so app can re-register
|
||||||
// their alarms/jobs/etc.
|
// their alarms/jobs/etc.
|
||||||
@@ -458,29 +455,20 @@ public final class AppHibernationService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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. Do
|
||||||
|
* not hold {@link #mLock} while calling this.
|
||||||
*/
|
*/
|
||||||
@GuardedBy("mLock")
|
|
||||||
private void hibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
|
private void hibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
|
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
|
||||||
|
long savedBytes = 0;
|
||||||
if (mOatArtifactDeletionEnabled) {
|
if (mOatArtifactDeletionEnabled) {
|
||||||
state.savedByte = Math.max(
|
savedBytes = Math.max(
|
||||||
mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName),
|
mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName),
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
state.hibernated = true;
|
synchronized (mLock) {
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
|
state.savedByte = savedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Unhibernate a package from global hibernation.
|
|
||||||
*/
|
|
||||||
@GuardedBy("mLock")
|
|
||||||
private void unhibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
|
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackageGlobally");
|
|
||||||
state.hibernated = false;
|
|
||||||
state.savedByte = 0;
|
|
||||||
state.lastUnhibernatedMs = System.currentTimeMillis();
|
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
|
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,12 +146,15 @@ public final class AppHibernationServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetHibernatingForUser_packageIsHibernating() {
|
public void testSetHibernatingForUser_packageIsHibernating() throws Exception {
|
||||||
// WHEN we hibernate a package for a user
|
// WHEN we hibernate a package for a user
|
||||||
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
|
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
|
||||||
|
|
||||||
// THEN the package is marked hibernating for the user
|
// THEN the package is marked hibernating for the user
|
||||||
assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
|
assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
|
||||||
|
verify(mIActivityManager).forceStopPackage(PACKAGE_NAME_1, USER_ID_1);
|
||||||
|
verify(mIPackageManager).deleteApplicationCacheFilesAsUser(
|
||||||
|
eq(PACKAGE_NAME_1), eq(USER_ID_1), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -204,6 +207,7 @@ public final class AppHibernationServiceTest {
|
|||||||
|
|
||||||
// THEN the package is marked hibernating for the user
|
// THEN the package is marked hibernating for the user
|
||||||
assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
|
assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
|
||||||
|
verify(mPackageManagerInternal).deleteOatArtifactsOfPackage(PACKAGE_NAME_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user