Merge changes from topic "app_hibernation_permission"
* changes: Add API to get hibernating packages Add MANAGE_APP_HIBERNATION permission
This commit is contained in:
@@ -113,6 +113,7 @@ package android {
|
|||||||
field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO";
|
field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO";
|
||||||
field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
|
field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
|
||||||
field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
|
field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
|
||||||
|
field public static final String MANAGE_APP_HIBERNATION = "android.permission.MANAGE_APP_HIBERNATION";
|
||||||
field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
|
field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
|
||||||
field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
|
field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
|
||||||
field public static final String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
|
field public static final String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
|
||||||
@@ -1421,10 +1422,11 @@ package android.app.usage {
|
|||||||
package android.apphibernation {
|
package android.apphibernation {
|
||||||
|
|
||||||
public final class AppHibernationManager {
|
public final class AppHibernationManager {
|
||||||
method public boolean isHibernatingForUser(@NonNull String);
|
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public java.util.List<java.lang.String> getHibernatingPackagesForUser();
|
||||||
method public boolean isHibernatingGlobally(@NonNull String);
|
method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingForUser(@NonNull String);
|
||||||
method public void setHibernatingForUser(@NonNull String, boolean);
|
method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingGlobally(@NonNull String);
|
||||||
method public void setHibernatingGlobally(@NonNull String, boolean);
|
method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void setHibernatingForUser(@NonNull String, boolean);
|
||||||
|
method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void setHibernatingGlobally(@NonNull String, boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,15 @@
|
|||||||
package android.apphibernation;
|
package android.apphibernation;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.RequiresPermission;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.annotation.SystemService;
|
import android.annotation.SystemService;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides an API surface for system apps to manipulate the app hibernation
|
* This class provides an API surface for system apps to manipulate the app hibernation
|
||||||
* state of a package for the user provided in the context.
|
* state of a package for the user provided in the context.
|
||||||
@@ -54,6 +57,7 @@ public final class AppHibernationManager {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@SystemApi
|
@SystemApi
|
||||||
|
@RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
|
||||||
public boolean isHibernatingForUser(@NonNull String packageName) {
|
public boolean isHibernatingForUser(@NonNull String packageName) {
|
||||||
try {
|
try {
|
||||||
return mIAppHibernationService.isHibernatingForUser(packageName, mContext.getUserId());
|
return mIAppHibernationService.isHibernatingForUser(packageName, mContext.getUserId());
|
||||||
@@ -68,6 +72,7 @@ public final class AppHibernationManager {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@SystemApi
|
@SystemApi
|
||||||
|
@RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
|
||||||
public void setHibernatingForUser(@NonNull String packageName, boolean isHibernating) {
|
public void setHibernatingForUser(@NonNull String packageName, boolean isHibernating) {
|
||||||
try {
|
try {
|
||||||
mIAppHibernationService.setHibernatingForUser(packageName, mContext.getUserId(),
|
mIAppHibernationService.setHibernatingForUser(packageName, mContext.getUserId(),
|
||||||
@@ -83,6 +88,7 @@ public final class AppHibernationManager {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@SystemApi
|
@SystemApi
|
||||||
|
@RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
|
||||||
public boolean isHibernatingGlobally(@NonNull String packageName) {
|
public boolean isHibernatingGlobally(@NonNull String packageName) {
|
||||||
try {
|
try {
|
||||||
return mIAppHibernationService.isHibernatingGlobally(packageName);
|
return mIAppHibernationService.isHibernatingGlobally(packageName);
|
||||||
@@ -99,6 +105,7 @@ public final class AppHibernationManager {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@SystemApi
|
@SystemApi
|
||||||
|
@RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
|
||||||
public void setHibernatingGlobally(@NonNull String packageName, boolean isHibernating) {
|
public void setHibernatingGlobally(@NonNull String packageName, boolean isHibernating) {
|
||||||
try {
|
try {
|
||||||
mIAppHibernationService.setHibernatingGlobally(packageName, isHibernating);
|
mIAppHibernationService.setHibernatingGlobally(packageName, isHibernating);
|
||||||
@@ -106,4 +113,20 @@ public final class AppHibernationManager {
|
|||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the hibernating packages for the user. This is equivalent to the list of packages for
|
||||||
|
* the user that return true for {@link #isHibernatingForUser}.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
@RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
|
||||||
|
public @NonNull List<String> getHibernatingPackagesForUser() {
|
||||||
|
try {
|
||||||
|
return mIAppHibernationService.getHibernatingPackagesForUser(mContext.getUserId());
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,4 +25,5 @@ interface IAppHibernationService {
|
|||||||
void setHibernatingForUser(String packageName, int userId, boolean isHibernating);
|
void setHibernatingForUser(String packageName, int userId, boolean isHibernating);
|
||||||
boolean isHibernatingGlobally(String packageName);
|
boolean isHibernatingGlobally(String packageName);
|
||||||
void setHibernatingGlobally(String packageName, boolean isHibernating);
|
void setHibernatingGlobally(String packageName, boolean isHibernating);
|
||||||
|
List<String> getHibernatingPackagesForUser(int userId);
|
||||||
}
|
}
|
||||||
@@ -5172,6 +5172,10 @@
|
|||||||
<permission android:name="android.permission.INPUT_CONSUMER"
|
<permission android:name="android.permission.INPUT_CONSUMER"
|
||||||
android:protectionLevel="signature" />
|
android:protectionLevel="signature" />
|
||||||
|
|
||||||
|
<!-- @hide @SystemApi Allows an application to manage app hibernation state. -->
|
||||||
|
<permission android:name="android.permission.MANAGE_APP_HIBERNATION"
|
||||||
|
android:protectionLevel="signature|installer" />
|
||||||
|
|
||||||
<!-- Attribution for Country Detector. -->
|
<!-- Attribution for Country Detector. -->
|
||||||
<attribution android:tag="CountryDetector" android:label="@string/country_detector"/>
|
<attribution android:tag="CountryDetector" android:label="@string/country_detector"/>
|
||||||
<!-- Attribution for Location service. -->
|
<!-- Attribution for Location service. -->
|
||||||
|
|||||||
@@ -451,6 +451,7 @@ applications that come with the platform
|
|||||||
<permission name="android.permission.MANAGE_SOUND_TRIGGER" />
|
<permission name="android.permission.MANAGE_SOUND_TRIGGER" />
|
||||||
<permission name="android.permission.CAPTURE_AUDIO_HOTWORD" />
|
<permission name="android.permission.CAPTURE_AUDIO_HOTWORD" />
|
||||||
<permission name="android.permission.MODIFY_QUIET_MODE" />
|
<permission name="android.permission.MODIFY_QUIET_MODE" />
|
||||||
|
<permission name="android.permission.MANAGE_APP_HIBERNATION"/>
|
||||||
</privapp-permissions>
|
</privapp-permissions>
|
||||||
|
|
||||||
<privapp-permissions package="com.android.statementservice">
|
<privapp-permissions package="com.android.statementservice">
|
||||||
|
|||||||
@@ -367,6 +367,7 @@
|
|||||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
|
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
|
||||||
<uses-permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE" />
|
<uses-permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
|
||||||
|
|
||||||
<application android:label="@string/app_label"
|
<application android:label="@string/app_label"
|
||||||
android:theme="@android:style/Theme.DeviceDefault.DayNight"
|
android:theme="@android:style/Theme.DeviceDefault.DayNight"
|
||||||
|
|||||||
@@ -173,7 +173,9 @@ public final class AppHibernationService extends SystemService {
|
|||||||
if (!checkHibernationEnabled("isHibernatingForUser")) {
|
if (!checkHibernationEnabled("isHibernatingForUser")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
getContext().enforceCallingOrSelfPermission(
|
||||||
|
android.Manifest.permission.MANAGE_APP_HIBERNATION,
|
||||||
|
"Caller does not have MANAGE_APP_HIBERNATION permission.");
|
||||||
userId = handleIncomingUser(userId, "isHibernating");
|
userId = handleIncomingUser(userId, "isHibernating");
|
||||||
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
|
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
|
||||||
Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
|
Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
|
||||||
@@ -202,6 +204,9 @@ public final class AppHibernationService extends SystemService {
|
|||||||
if (!checkHibernationEnabled("isHibernatingGlobally")) {
|
if (!checkHibernationEnabled("isHibernatingGlobally")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
getContext().enforceCallingOrSelfPermission(
|
||||||
|
android.Manifest.permission.MANAGE_APP_HIBERNATION,
|
||||||
|
"Caller does not have MANAGE_APP_HIBERNATION permission.");
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
GlobalLevelState state = mGlobalHibernationStates.get(packageName);
|
GlobalLevelState state = mGlobalHibernationStates.get(packageName);
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
@@ -223,6 +228,9 @@ public final class AppHibernationService extends SystemService {
|
|||||||
if (!checkHibernationEnabled("setHibernatingForUser")) {
|
if (!checkHibernationEnabled("setHibernatingForUser")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getContext().enforceCallingOrSelfPermission(
|
||||||
|
android.Manifest.permission.MANAGE_APP_HIBERNATION,
|
||||||
|
"Caller does not have MANAGE_APP_HIBERNATION permission.");
|
||||||
userId = handleIncomingUser(userId, "setHibernating");
|
userId = handleIncomingUser(userId, "setHibernating");
|
||||||
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
|
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
|
||||||
Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
|
Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
|
||||||
@@ -263,6 +271,9 @@ public final class AppHibernationService extends SystemService {
|
|||||||
if (!checkHibernationEnabled("setHibernatingGlobally")) {
|
if (!checkHibernationEnabled("setHibernatingGlobally")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getContext().enforceCallingOrSelfPermission(
|
||||||
|
android.Manifest.permission.MANAGE_APP_HIBERNATION,
|
||||||
|
"Caller does not have MANAGE_APP_HIBERNATION permission.");
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
GlobalLevelState state = mGlobalHibernationStates.get(packageName);
|
GlobalLevelState state = mGlobalHibernationStates.get(packageName);
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
@@ -281,6 +292,35 @@ public final class AppHibernationService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the hibernating packages for the given user. This is equivalent to the list of
|
||||||
|
* packages for the user that return true for {@link #isHibernatingForUser}.
|
||||||
|
*/
|
||||||
|
@NonNull List<String> getHibernatingPackagesForUser(int userId) {
|
||||||
|
ArrayList<String> hibernatingPackages = new ArrayList<>();
|
||||||
|
if (!checkHibernationEnabled("getHibernatingPackagesForUser")) {
|
||||||
|
return hibernatingPackages;
|
||||||
|
}
|
||||||
|
getContext().enforceCallingOrSelfPermission(
|
||||||
|
android.Manifest.permission.MANAGE_APP_HIBERNATION,
|
||||||
|
"Caller does not have MANAGE_APP_HIBERNATION permission.");
|
||||||
|
userId = handleIncomingUser(userId, "getHibernatingPackagesForUser");
|
||||||
|
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
|
||||||
|
Slog.w(TAG, "Attempt to get hibernating packages for a stopped or nonexistent user "
|
||||||
|
+ userId);
|
||||||
|
return hibernatingPackages;
|
||||||
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
|
Map<String, UserLevelState> userStates = mUserStates.get(userId);
|
||||||
|
for (UserLevelState state : userStates.values()) {
|
||||||
|
if (state.hibernated) {
|
||||||
|
hibernatingPackages.add(state.packageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hibernatingPackages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
@@ -607,6 +647,11 @@ public final class AppHibernationService extends SystemService {
|
|||||||
return mService.isHibernatingGlobally(packageName);
|
return mService.isHibernatingGlobally(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getHibernatingPackagesForUser(int userId) {
|
||||||
|
return mService.getHibernatingPackagesForUser(userId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
|
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
|
||||||
@Nullable FileDescriptor err, @NonNull String[] args,
|
@Nullable FileDescriptor err, @NonNull String[] args,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.server.apphibernation;
|
|||||||
|
|
||||||
import static android.content.pm.PackageManager.MATCH_ANY_USER;
|
import static android.content.pm.PackageManager.MATCH_ANY_USER;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.AdditionalAnswers.returnsArgAt;
|
import static org.mockito.AdditionalAnswers.returnsArgAt;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -67,6 +68,7 @@ public final class AppHibernationServiceTest {
|
|||||||
private static final String PACKAGE_SCHEME = "package";
|
private static final String PACKAGE_SCHEME = "package";
|
||||||
private static final String PACKAGE_NAME_1 = "package1";
|
private static final String PACKAGE_NAME_1 = "package1";
|
||||||
private static final String PACKAGE_NAME_2 = "package2";
|
private static final String PACKAGE_NAME_2 = "package2";
|
||||||
|
private static final String PACKAGE_NAME_3 = "package3";
|
||||||
private static final int USER_ID_1 = 1;
|
private static final int USER_ID_1 = 1;
|
||||||
private static final int USER_ID_2 = 2;
|
private static final int USER_ID_2 = 2;
|
||||||
|
|
||||||
@@ -107,6 +109,8 @@ public final class AppHibernationServiceTest {
|
|||||||
|
|
||||||
List<PackageInfo> packages = new ArrayList<>();
|
List<PackageInfo> packages = new ArrayList<>();
|
||||||
packages.add(makePackageInfo(PACKAGE_NAME_1));
|
packages.add(makePackageInfo(PACKAGE_NAME_1));
|
||||||
|
packages.add(makePackageInfo(PACKAGE_NAME_2));
|
||||||
|
packages.add(makePackageInfo(PACKAGE_NAME_3));
|
||||||
doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages(
|
doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages(
|
||||||
intThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
|
intThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
|
||||||
mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
|
mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
|
||||||
@@ -179,6 +183,26 @@ public final class AppHibernationServiceTest {
|
|||||||
assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
|
assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetHibernatingPackagesForUser_returnsCorrectPackages() throws RemoteException {
|
||||||
|
// GIVEN an unlocked user with all packages installed
|
||||||
|
UserInfo userInfo =
|
||||||
|
addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3});
|
||||||
|
mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
|
||||||
|
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
|
||||||
|
|
||||||
|
// WHEN packages are hibernated for the user
|
||||||
|
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
|
||||||
|
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_2, true);
|
||||||
|
|
||||||
|
// THEN the hibernating packages returned matches
|
||||||
|
List<String> hibernatingPackages =
|
||||||
|
mAppHibernationService.getHibernatingPackagesForUser(USER_ID_2);
|
||||||
|
assertEquals(2, hibernatingPackages.size());
|
||||||
|
assertTrue(hibernatingPackages.contains(PACKAGE_NAME_1));
|
||||||
|
assertTrue(hibernatingPackages.contains(PACKAGE_NAME_2));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a mock user with one package.
|
* Add a mock user with one package.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user