Loading api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -4863,6 +4863,7 @@ package android.permission { method public final android.os.IBinder onBind(android.content.Intent); method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean); method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String); method public abstract void onGetRuntimePermissionsBackup(android.os.UserHandle, java.io.OutputStream); method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String); method public abstract java.util.Map<java.lang.String, java.util.List<java.lang.String>> onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.lang.String); field public static final java.lang.String SERVICE_INTERFACE = "android.permission.PermissionControllerService"; Loading core/java/android/permission/IPermissionController.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package android.permission; import android.os.RemoteCallback; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.UserHandle; /** * Interface for system apps to communication with the permission controller. Loading @@ -27,6 +29,7 @@ import android.os.Bundle; oneway interface IPermissionController { void revokeRuntimePermissions(in Bundle request, boolean doDryRun, int reason, String callerPackageName, in RemoteCallback callback); void getRuntimePermissionBackup(in UserHandle user, in ParcelFileDescriptor pipe); void getAppPermissions(String packageName, in RemoteCallback callback); void revokeRuntimePermission(String packageName, String permissionName); void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted, Loading core/java/android/permission/PermissionControllerManager.java +187 −0 Original line number Diff line number Diff line Loading @@ -36,10 +36,12 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.AsyncTask; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.UserHandle; Loading @@ -51,6 +53,11 @@ import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; import com.android.internal.infra.AbstractRemoteService; import com.android.internal.util.Preconditions; import libcore.io.IoUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; Loading @@ -58,6 +65,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * Interface for communicating with the permission controller. Loading Loading @@ -117,6 +125,20 @@ public final class PermissionControllerManager { public abstract void onRevokeRuntimePermissions(@NonNull Map<String, List<String>> revoked); } /** * Callback for delivering the result of {@link #getRuntimePermissionBackup}. * * @hide */ public interface OnGetRuntimePermissionBackupCallback { /** * The result for {@link #getRuntimePermissionBackup}. * * @param backup The backup file */ void onGetRuntimePermissionsBackup(@NonNull byte[] backup); } /** * Callback for delivering the result of {@link #getAppPermissions}. * Loading Loading @@ -218,6 +240,26 @@ public final class PermissionControllerManager { request, doDryRun, reason, mContext.getPackageName(), executor, callback)); } /** * Create a backup of the runtime permissions. * * @param user The user to be backed up * @param executor Executor on which to invoke the callback * @param callback Callback to receive the result * * @hide */ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull OnGetRuntimePermissionBackupCallback callback) { checkNotNull(executor); checkNotNull(callback); sRemoteService.scheduleRequest(new PendingGetRuntimePermissionBackup(sRemoteService, user, executor, callback)); } /** * Gets the runtime permissions for an app. * Loading Loading @@ -354,6 +396,89 @@ public final class PermissionControllerManager { } } /** * Task to read a large amount of data from a remote service. */ private static class FileReaderTask<Callback extends Consumer<byte[]>> extends AsyncTask<Void, Void, byte[]> { private ParcelFileDescriptor mLocalPipe; private ParcelFileDescriptor mRemotePipe; private final @NonNull Callback mCallback; FileReaderTask(@NonNull Callback callback) { mCallback = callback; } @Override protected void onPreExecute() { ParcelFileDescriptor[] pipe; try { pipe = ParcelFileDescriptor.createPipe(); } catch (IOException e) { Log.e(TAG, "Could not create pipe needed to get runtime permission backup", e); return; } mLocalPipe = pipe[0]; mRemotePipe = pipe[1]; } /** * Get the file descriptor the remote service should write the data to. * * <p>Needs to be closed <u>locally</u> before the FileReader can finish. * * @return The file the data should be written to */ ParcelFileDescriptor getRemotePipe() { return mRemotePipe; } @Override protected byte[] doInBackground(Void... ignored) { ByteArrayOutputStream combinedBuffer = new ByteArrayOutputStream(); try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(mLocalPipe)) { byte[] buffer = new byte[16 * 1024]; while (!isCancelled()) { int numRead = in.read(buffer); if (numRead == -1) { break; } combinedBuffer.write(buffer, 0, numRead); } } catch (IOException | NullPointerException e) { Log.e(TAG, "Error reading runtime permission backup", e); combinedBuffer.reset(); } return combinedBuffer.toByteArray(); } /** * Interrupt the reading of the data. * * <p>Needs to be called when canceling this task as it might be hung. */ void interruptRead() { IoUtils.closeQuietly(mLocalPipe); } @Override protected void onCancelled() { onPostExecute(new byte[]{}); } @Override protected void onPostExecute(byte[] backup) { IoUtils.closeQuietly(mLocalPipe); mCallback.accept(backup); } } /** * Request for {@link #revokeRuntimePermissions} */ Loading Loading @@ -440,6 +565,68 @@ public final class PermissionControllerManager { } } /** * Request for {@link #getRuntimePermissionBackup} */ private static final class PendingGetRuntimePermissionBackup extends AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> implements Consumer<byte[]> { private final @NonNull FileReaderTask<PendingGetRuntimePermissionBackup> mBackupReader; private final @NonNull Executor mExecutor; private final @NonNull OnGetRuntimePermissionBackupCallback mCallback; private final @NonNull UserHandle mUser; private PendingGetRuntimePermissionBackup(@NonNull RemoteService service, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull OnGetRuntimePermissionBackupCallback callback) { super(service); mUser = user; mExecutor = executor; mCallback = callback; mBackupReader = new FileReaderTask<>(this); } @Override protected void onTimeout(RemoteService remoteService) { mBackupReader.cancel(true); mBackupReader.interruptRead(); } @Override public void run() { mBackupReader.execute(); ParcelFileDescriptor remotePipe = mBackupReader.getRemotePipe(); try { getService().getServiceInterface().getRuntimePermissionBackup(mUser, remotePipe); } catch (RemoteException e) { Log.e(TAG, "Error getting runtime permission backup", e); } finally { // Remote pipe end is duped by binder call. Local copy is not needed anymore IoUtils.closeQuietly(remotePipe); } } /** * Called when the {@link #mBackupReader} finished reading the file. * * @param backup The data read */ @Override public void accept(byte[] backup) { long token = Binder.clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onGetRuntimePermissionsBackup(backup)); } finally { Binder.restoreCallingIdentity(token); } finish(); } } /** * Request for {@link #getAppPermissions} */ Loading core/java/android/permission/PermissionControllerService.java +36 −0 Original line number Diff line number Diff line Loading @@ -33,11 +33,16 @@ import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteCallback; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; import com.android.internal.util.Preconditions; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; Loading @@ -51,6 +56,7 @@ import java.util.Map; */ @SystemApi public abstract class PermissionControllerService extends Service { private static final String LOG_TAG = PermissionControllerService.class.getSimpleName(); /** * The {@link Intent} action that must be declared as handled by a service Loading Loading @@ -82,6 +88,15 @@ public abstract class PermissionControllerService extends Service { @NonNull Map<String, List<String>> requests, boolean doDryRun, @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName); /** * Create a backup of the runtime permissions. * * @param user The user to back up * @param out The stream to write the backup to */ public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user, @NonNull OutputStream out); /** * Gets the runtime permissions for an app. * Loading Loading @@ -162,6 +177,18 @@ public abstract class PermissionControllerService extends Service { callerPackageName, callback)); } @Override public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) { checkNotNull(user); checkNotNull(pipe); enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null); mHandler.sendMessage(obtainMessage( PermissionControllerService::getRuntimePermissionsBackup, PermissionControllerService.this, user, pipe)); } @Override public void getAppPermissions(String packageName, RemoteCallback callback) { checkNotNull(packageName, "packageName"); Loading Loading @@ -237,6 +264,15 @@ public abstract class PermissionControllerService extends Service { callback.sendResult(result); } private void getRuntimePermissionsBackup(@NonNull UserHandle user, @NonNull ParcelFileDescriptor outFile) { try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(outFile)) { onGetRuntimePermissionsBackup(user, out); } catch (IOException e) { Log.e(LOG_TAG, "Could not open pipe to write backup tp", e); } } private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) { List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName); if (permissions != null && !permissions.isEmpty()) { Loading services/core/java/com/android/server/pm/PackageManagerService.java +25 −78 Original line number Diff line number Diff line Loading @@ -239,6 +239,7 @@ import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; import android.permission.PermissionControllerManager; import android.provider.MediaStore; import android.provider.Settings.Global; import android.provider.Settings.Secure; Loading Loading @@ -317,7 +318,6 @@ import com.android.server.pm.permission.PermissionManagerInternal; import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback; import com.android.server.pm.permission.PermissionManagerService; import com.android.server.pm.permission.PermissionsState; import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.security.VerityUtils; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.wm.ActivityTaskManagerInternal; Loading Loading @@ -370,6 +370,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Predicate; Loading Loading @@ -443,6 +444,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final boolean ENABLE_FREE_CACHE_V2 = SystemProperties.getBoolean("fw.free_cache_v2", true); private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60); private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; private static final int NFC_UID = Process.NFC_UID; Loading Loading @@ -19573,28 +19576,32 @@ public class PackageManagerService extends IPackageManager.Stub throw new SecurityException("Only the system may call getPermissionGrantBackup()"); } ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); try { final XmlSerializer serializer = new FastXmlSerializer(); serializer.setOutput(dataStream, StandardCharsets.UTF_8.name()); serializer.startDocument(null, true); serializer.startTag(null, TAG_PERMISSION_BACKUP); synchronized (mPackages) { serializeRuntimePermissionGrantsLPr(serializer, userId); AtomicReference<byte[]> backup = new AtomicReference<>(); mContext.getSystemService(PermissionControllerManager.class).getRuntimePermissionBackup( UserHandle.of(userId), mContext.getMainExecutor(), (b) -> { synchronized (backup) { backup.set(b); backup.notifyAll(); } }); serializer.endTag(null, TAG_PERMISSION_BACKUP); serializer.endDocument(); serializer.flush(); } catch (Exception e) { if (DEBUG_BACKUP) { Slog.e(TAG, "Unable to write default apps for backup", e); long start = System.currentTimeMillis(); synchronized (backup) { while (backup.get() == null) { long timeLeft = start + BACKUP_TIMEOUT_MILLIS - System.currentTimeMillis(); if (timeLeft <= 0) { return null; } try { backup.wait(timeLeft); } catch (InterruptedException ignored) { return null; } } } return dataStream.toByteArray(); return backup.get(); } @Override Loading @@ -19619,66 +19626,6 @@ public class PackageManagerService extends IPackageManager.Stub } } @GuardedBy("mPackages") private void serializeRuntimePermissionGrantsLPr(XmlSerializer serializer, final int userId) throws IOException { serializer.startTag(null, TAG_ALL_GRANTS); final int N = mSettings.mPackages.size(); for (int i = 0; i < N; i++) { final PackageSetting ps = mSettings.mPackages.valueAt(i); boolean pkgGrantsKnown = false; PermissionsState packagePerms = ps.getPermissionsState(); for (PermissionState state : packagePerms.getRuntimePermissionStates(userId)) { final int grantFlags = state.getFlags(); // only look at grants that are not system/policy fixed if ((grantFlags & SYSTEM_RUNTIME_GRANT_MASK) == 0) { final boolean isGranted = state.isGranted(); // And only back up the user-twiddled state bits if (isGranted || (grantFlags & USER_RUNTIME_GRANT_MASK) != 0) { final String packageName = mSettings.mPackages.keyAt(i); if (!pkgGrantsKnown) { serializer.startTag(null, TAG_GRANT); serializer.attribute(null, ATTR_PACKAGE_NAME, packageName); pkgGrantsKnown = true; } final boolean userSet = (grantFlags & FLAG_PERMISSION_USER_SET) != 0; final boolean userFixed = (grantFlags & FLAG_PERMISSION_USER_FIXED) != 0; final boolean revoke = (grantFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0; serializer.startTag(null, TAG_PERMISSION); serializer.attribute(null, ATTR_PERMISSION_NAME, state.getName()); if (isGranted) { serializer.attribute(null, ATTR_IS_GRANTED, "true"); } if (userSet) { serializer.attribute(null, ATTR_USER_SET, "true"); } if (userFixed) { serializer.attribute(null, ATTR_USER_FIXED, "true"); } if (revoke) { serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true"); } serializer.endTag(null, TAG_PERMISSION); } } } if (pkgGrantsKnown) { serializer.endTag(null, TAG_GRANT); } } serializer.endTag(null, TAG_ALL_GRANTS); } @GuardedBy("mPackages") private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId) throws XmlPullParserException, IOException { Loading
api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -4863,6 +4863,7 @@ package android.permission { method public final android.os.IBinder onBind(android.content.Intent); method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean); method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String); method public abstract void onGetRuntimePermissionsBackup(android.os.UserHandle, java.io.OutputStream); method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String); method public abstract java.util.Map<java.lang.String, java.util.List<java.lang.String>> onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.lang.String); field public static final java.lang.String SERVICE_INTERFACE = "android.permission.PermissionControllerService"; Loading
core/java/android/permission/IPermissionController.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package android.permission; import android.os.RemoteCallback; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.UserHandle; /** * Interface for system apps to communication with the permission controller. Loading @@ -27,6 +29,7 @@ import android.os.Bundle; oneway interface IPermissionController { void revokeRuntimePermissions(in Bundle request, boolean doDryRun, int reason, String callerPackageName, in RemoteCallback callback); void getRuntimePermissionBackup(in UserHandle user, in ParcelFileDescriptor pipe); void getAppPermissions(String packageName, in RemoteCallback callback); void revokeRuntimePermission(String packageName, String permissionName); void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted, Loading
core/java/android/permission/PermissionControllerManager.java +187 −0 Original line number Diff line number Diff line Loading @@ -36,10 +36,12 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.AsyncTask; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.UserHandle; Loading @@ -51,6 +53,11 @@ import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; import com.android.internal.infra.AbstractRemoteService; import com.android.internal.util.Preconditions; import libcore.io.IoUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; Loading @@ -58,6 +65,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * Interface for communicating with the permission controller. Loading Loading @@ -117,6 +125,20 @@ public final class PermissionControllerManager { public abstract void onRevokeRuntimePermissions(@NonNull Map<String, List<String>> revoked); } /** * Callback for delivering the result of {@link #getRuntimePermissionBackup}. * * @hide */ public interface OnGetRuntimePermissionBackupCallback { /** * The result for {@link #getRuntimePermissionBackup}. * * @param backup The backup file */ void onGetRuntimePermissionsBackup(@NonNull byte[] backup); } /** * Callback for delivering the result of {@link #getAppPermissions}. * Loading Loading @@ -218,6 +240,26 @@ public final class PermissionControllerManager { request, doDryRun, reason, mContext.getPackageName(), executor, callback)); } /** * Create a backup of the runtime permissions. * * @param user The user to be backed up * @param executor Executor on which to invoke the callback * @param callback Callback to receive the result * * @hide */ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull OnGetRuntimePermissionBackupCallback callback) { checkNotNull(executor); checkNotNull(callback); sRemoteService.scheduleRequest(new PendingGetRuntimePermissionBackup(sRemoteService, user, executor, callback)); } /** * Gets the runtime permissions for an app. * Loading Loading @@ -354,6 +396,89 @@ public final class PermissionControllerManager { } } /** * Task to read a large amount of data from a remote service. */ private static class FileReaderTask<Callback extends Consumer<byte[]>> extends AsyncTask<Void, Void, byte[]> { private ParcelFileDescriptor mLocalPipe; private ParcelFileDescriptor mRemotePipe; private final @NonNull Callback mCallback; FileReaderTask(@NonNull Callback callback) { mCallback = callback; } @Override protected void onPreExecute() { ParcelFileDescriptor[] pipe; try { pipe = ParcelFileDescriptor.createPipe(); } catch (IOException e) { Log.e(TAG, "Could not create pipe needed to get runtime permission backup", e); return; } mLocalPipe = pipe[0]; mRemotePipe = pipe[1]; } /** * Get the file descriptor the remote service should write the data to. * * <p>Needs to be closed <u>locally</u> before the FileReader can finish. * * @return The file the data should be written to */ ParcelFileDescriptor getRemotePipe() { return mRemotePipe; } @Override protected byte[] doInBackground(Void... ignored) { ByteArrayOutputStream combinedBuffer = new ByteArrayOutputStream(); try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(mLocalPipe)) { byte[] buffer = new byte[16 * 1024]; while (!isCancelled()) { int numRead = in.read(buffer); if (numRead == -1) { break; } combinedBuffer.write(buffer, 0, numRead); } } catch (IOException | NullPointerException e) { Log.e(TAG, "Error reading runtime permission backup", e); combinedBuffer.reset(); } return combinedBuffer.toByteArray(); } /** * Interrupt the reading of the data. * * <p>Needs to be called when canceling this task as it might be hung. */ void interruptRead() { IoUtils.closeQuietly(mLocalPipe); } @Override protected void onCancelled() { onPostExecute(new byte[]{}); } @Override protected void onPostExecute(byte[] backup) { IoUtils.closeQuietly(mLocalPipe); mCallback.accept(backup); } } /** * Request for {@link #revokeRuntimePermissions} */ Loading Loading @@ -440,6 +565,68 @@ public final class PermissionControllerManager { } } /** * Request for {@link #getRuntimePermissionBackup} */ private static final class PendingGetRuntimePermissionBackup extends AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> implements Consumer<byte[]> { private final @NonNull FileReaderTask<PendingGetRuntimePermissionBackup> mBackupReader; private final @NonNull Executor mExecutor; private final @NonNull OnGetRuntimePermissionBackupCallback mCallback; private final @NonNull UserHandle mUser; private PendingGetRuntimePermissionBackup(@NonNull RemoteService service, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull OnGetRuntimePermissionBackupCallback callback) { super(service); mUser = user; mExecutor = executor; mCallback = callback; mBackupReader = new FileReaderTask<>(this); } @Override protected void onTimeout(RemoteService remoteService) { mBackupReader.cancel(true); mBackupReader.interruptRead(); } @Override public void run() { mBackupReader.execute(); ParcelFileDescriptor remotePipe = mBackupReader.getRemotePipe(); try { getService().getServiceInterface().getRuntimePermissionBackup(mUser, remotePipe); } catch (RemoteException e) { Log.e(TAG, "Error getting runtime permission backup", e); } finally { // Remote pipe end is duped by binder call. Local copy is not needed anymore IoUtils.closeQuietly(remotePipe); } } /** * Called when the {@link #mBackupReader} finished reading the file. * * @param backup The data read */ @Override public void accept(byte[] backup) { long token = Binder.clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onGetRuntimePermissionsBackup(backup)); } finally { Binder.restoreCallingIdentity(token); } finish(); } } /** * Request for {@link #getAppPermissions} */ Loading
core/java/android/permission/PermissionControllerService.java +36 −0 Original line number Diff line number Diff line Loading @@ -33,11 +33,16 @@ import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteCallback; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; import com.android.internal.util.Preconditions; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; Loading @@ -51,6 +56,7 @@ import java.util.Map; */ @SystemApi public abstract class PermissionControllerService extends Service { private static final String LOG_TAG = PermissionControllerService.class.getSimpleName(); /** * The {@link Intent} action that must be declared as handled by a service Loading Loading @@ -82,6 +88,15 @@ public abstract class PermissionControllerService extends Service { @NonNull Map<String, List<String>> requests, boolean doDryRun, @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName); /** * Create a backup of the runtime permissions. * * @param user The user to back up * @param out The stream to write the backup to */ public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user, @NonNull OutputStream out); /** * Gets the runtime permissions for an app. * Loading Loading @@ -162,6 +177,18 @@ public abstract class PermissionControllerService extends Service { callerPackageName, callback)); } @Override public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) { checkNotNull(user); checkNotNull(pipe); enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null); mHandler.sendMessage(obtainMessage( PermissionControllerService::getRuntimePermissionsBackup, PermissionControllerService.this, user, pipe)); } @Override public void getAppPermissions(String packageName, RemoteCallback callback) { checkNotNull(packageName, "packageName"); Loading Loading @@ -237,6 +264,15 @@ public abstract class PermissionControllerService extends Service { callback.sendResult(result); } private void getRuntimePermissionsBackup(@NonNull UserHandle user, @NonNull ParcelFileDescriptor outFile) { try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(outFile)) { onGetRuntimePermissionsBackup(user, out); } catch (IOException e) { Log.e(LOG_TAG, "Could not open pipe to write backup tp", e); } } private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) { List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName); if (permissions != null && !permissions.isEmpty()) { Loading
services/core/java/com/android/server/pm/PackageManagerService.java +25 −78 Original line number Diff line number Diff line Loading @@ -239,6 +239,7 @@ import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; import android.permission.PermissionControllerManager; import android.provider.MediaStore; import android.provider.Settings.Global; import android.provider.Settings.Secure; Loading Loading @@ -317,7 +318,6 @@ import com.android.server.pm.permission.PermissionManagerInternal; import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback; import com.android.server.pm.permission.PermissionManagerService; import com.android.server.pm.permission.PermissionsState; import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.security.VerityUtils; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.wm.ActivityTaskManagerInternal; Loading Loading @@ -370,6 +370,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Predicate; Loading Loading @@ -443,6 +444,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final boolean ENABLE_FREE_CACHE_V2 = SystemProperties.getBoolean("fw.free_cache_v2", true); private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60); private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; private static final int NFC_UID = Process.NFC_UID; Loading Loading @@ -19573,28 +19576,32 @@ public class PackageManagerService extends IPackageManager.Stub throw new SecurityException("Only the system may call getPermissionGrantBackup()"); } ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); try { final XmlSerializer serializer = new FastXmlSerializer(); serializer.setOutput(dataStream, StandardCharsets.UTF_8.name()); serializer.startDocument(null, true); serializer.startTag(null, TAG_PERMISSION_BACKUP); synchronized (mPackages) { serializeRuntimePermissionGrantsLPr(serializer, userId); AtomicReference<byte[]> backup = new AtomicReference<>(); mContext.getSystemService(PermissionControllerManager.class).getRuntimePermissionBackup( UserHandle.of(userId), mContext.getMainExecutor(), (b) -> { synchronized (backup) { backup.set(b); backup.notifyAll(); } }); serializer.endTag(null, TAG_PERMISSION_BACKUP); serializer.endDocument(); serializer.flush(); } catch (Exception e) { if (DEBUG_BACKUP) { Slog.e(TAG, "Unable to write default apps for backup", e); long start = System.currentTimeMillis(); synchronized (backup) { while (backup.get() == null) { long timeLeft = start + BACKUP_TIMEOUT_MILLIS - System.currentTimeMillis(); if (timeLeft <= 0) { return null; } try { backup.wait(timeLeft); } catch (InterruptedException ignored) { return null; } } } return dataStream.toByteArray(); return backup.get(); } @Override Loading @@ -19619,66 +19626,6 @@ public class PackageManagerService extends IPackageManager.Stub } } @GuardedBy("mPackages") private void serializeRuntimePermissionGrantsLPr(XmlSerializer serializer, final int userId) throws IOException { serializer.startTag(null, TAG_ALL_GRANTS); final int N = mSettings.mPackages.size(); for (int i = 0; i < N; i++) { final PackageSetting ps = mSettings.mPackages.valueAt(i); boolean pkgGrantsKnown = false; PermissionsState packagePerms = ps.getPermissionsState(); for (PermissionState state : packagePerms.getRuntimePermissionStates(userId)) { final int grantFlags = state.getFlags(); // only look at grants that are not system/policy fixed if ((grantFlags & SYSTEM_RUNTIME_GRANT_MASK) == 0) { final boolean isGranted = state.isGranted(); // And only back up the user-twiddled state bits if (isGranted || (grantFlags & USER_RUNTIME_GRANT_MASK) != 0) { final String packageName = mSettings.mPackages.keyAt(i); if (!pkgGrantsKnown) { serializer.startTag(null, TAG_GRANT); serializer.attribute(null, ATTR_PACKAGE_NAME, packageName); pkgGrantsKnown = true; } final boolean userSet = (grantFlags & FLAG_PERMISSION_USER_SET) != 0; final boolean userFixed = (grantFlags & FLAG_PERMISSION_USER_FIXED) != 0; final boolean revoke = (grantFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0; serializer.startTag(null, TAG_PERMISSION); serializer.attribute(null, ATTR_PERMISSION_NAME, state.getName()); if (isGranted) { serializer.attribute(null, ATTR_IS_GRANTED, "true"); } if (userSet) { serializer.attribute(null, ATTR_USER_SET, "true"); } if (userFixed) { serializer.attribute(null, ATTR_USER_FIXED, "true"); } if (revoke) { serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true"); } serializer.endTag(null, TAG_PERMISSION); } } } if (pkgGrantsKnown) { serializer.endTag(null, TAG_GRANT); } } serializer.endTag(null, TAG_ALL_GRANTS); } @GuardedBy("mPackages") private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId) throws XmlPullParserException, IOException {