diff options
author | Svetoslav <svetoslavganov@google.com> | 2015-06-11 08:02:03 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-06-11 08:02:06 +0000 |
commit | 75a0ee081fa31b75649e164a8bf79a23a3ebd060 (patch) | |
tree | ed08df9ba6c1c59aa01314e4566d79589f87a57a | |
parent | 4ba81a0878d058734e9eb2c298d7fc4df7e597ed (diff) | |
parent | f7c06eb03ab4479b9d0656a23a4733d17e995183 (diff) | |
download | frameworks_base-75a0ee081fa31b75649e164a8bf79a23a3ebd060.zip frameworks_base-75a0ee081fa31b75649e164a8bf79a23a3ebd060.tar.gz frameworks_base-75a0ee081fa31b75649e164a8bf79a23a3ebd060.tar.bz2 |
Merge "Add system API to watch for permission changes" into mnc-dev
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | api/system-current.txt | 8 | ||||
-rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 69 | ||||
-rw-r--r-- | core/java/android/content/pm/IOnPermissionsChangeListener.aidl | 25 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 4 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageManager.java | 38 | ||||
-rw-r--r-- | core/java/android/os/RemoteCallbackList.java | 1 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 85 | ||||
-rw-r--r-- | test-runner/src/android/test/mock/MockPackageManager.java | 12 |
10 files changed, 244 insertions, 3 deletions
@@ -142,6 +142,7 @@ LOCAL_SRC_FILES += \ core/java/android/content/pm/IPackageManager.aidl \ core/java/android/content/pm/IPackageMoveObserver.aidl \ core/java/android/content/pm/IPackageStatsObserver.aidl \ + core/java/android/content/pm/IOnPermissionsChangeListener.aidl \ core/java/android/database/IContentObserver.aidl \ core/java/android/hardware/ICameraService.aidl \ core/java/android/hardware/ICameraServiceListener.aidl \ diff --git a/api/system-current.txt b/api/system-current.txt index 72e4142..010b4b1 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -9522,6 +9522,7 @@ package android.content.pm { public abstract class PackageManager { ctor public PackageManager(); + method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); method public abstract deprecated void addPackageToPreferred(java.lang.String); method public abstract boolean addPermission(android.content.pm.PermissionInfo); method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo); @@ -9595,6 +9596,7 @@ package android.content.pm { method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int); method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int); method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); method public abstract deprecated void removePackageFromPreferred(java.lang.String); method public abstract void removePermission(java.lang.String); method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int); @@ -9770,6 +9772,10 @@ package android.content.pm { ctor public PackageManager.NameNotFoundException(java.lang.String); } + public static abstract interface PackageManager.OnPermissionsChangedListener { + method public abstract void onPermissionsChanged(int); + } + public static abstract class PackageManager.PermissionFlags implements java.lang.annotation.Annotation { } @@ -34160,6 +34166,7 @@ package android.test.mock { public class MockPackageManager extends android.content.pm.PackageManager { ctor public MockPackageManager(); + method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); method public void addPackageToPreferred(java.lang.String); method public boolean addPermission(android.content.pm.PermissionInfo); method public boolean addPermissionAsync(android.content.pm.PermissionInfo); @@ -34234,6 +34241,7 @@ package android.test.mock { method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int); method public java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int); method public java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); method public void removePackageFromPreferred(java.lang.String); method public void removePermission(java.lang.String); method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 41e3db8..cb1e7aa 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -31,6 +31,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; import android.content.pm.ContainerEncryptionParams; import android.content.pm.FeatureInfo; +import android.content.pm.IOnPermissionsChangeListener; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; @@ -88,6 +89,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Objects; /*package*/ @@ -1048,6 +1050,38 @@ final class ApplicationPackageManager extends PackageManager { } } + @Override + public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) { + synchronized (mPermissionListeners) { + if (mPermissionListeners.get(listener) != null) { + return; + } + OnPermissionsChangeListenerDelegate delegate = + new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper()); + try { + mPM.addOnPermissionsChangeListener(delegate); + mPermissionListeners.put(listener, delegate); + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + } + } + + @Override + public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) { + synchronized (mPermissionListeners) { + IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener); + if (delegate != null) { + try { + mPM.removeOnPermissionsChangeListener(delegate); + mPermissionListeners.remove(listener); + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + } + } + } + static void configurationChanged() { synchronized (sSync) { sIconCache.clear(); @@ -2139,4 +2173,39 @@ final class ApplicationPackageManager extends PackageManager { = new ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>>(); private static ArrayMap<ResourceName, WeakReference<CharSequence>> sStringCache = new ArrayMap<ResourceName, WeakReference<CharSequence>>(); + + private final Map<OnPermissionsChangedListener, IOnPermissionsChangeListener> + mPermissionListeners = new ArrayMap<>(); + + public class OnPermissionsChangeListenerDelegate extends IOnPermissionsChangeListener.Stub + implements Handler.Callback{ + private static final int MSG_PERMISSIONS_CHANGED = 1; + + private final OnPermissionsChangedListener mListener; + private final Handler mHandler; + + + public OnPermissionsChangeListenerDelegate(OnPermissionsChangedListener listener, + Looper looper) { + mListener = listener; + mHandler = new Handler(looper, this); + } + + @Override + public void onPermissionsChanged(int uid) { + mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget(); + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_PERMISSIONS_CHANGED: { + final int uid = msg.arg1; + mListener.onPermissionsChanged(uid); + return true; + } + } + return false; + } + } } diff --git a/core/java/android/content/pm/IOnPermissionsChangeListener.aidl b/core/java/android/content/pm/IOnPermissionsChangeListener.aidl new file mode 100644 index 0000000..7791b50 --- /dev/null +++ b/core/java/android/content/pm/IOnPermissionsChangeListener.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015 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 android.content.pm; + +/** + * Listener for changes in the permissions for installed packages. + * {@hide} + */ +oneway interface IOnPermissionsChangeListener { + void onPermissionsChanged(int uid); +} diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 00b8c71..0c07bc3 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -31,6 +31,7 @@ import android.content.pm.IPackageDeleteObserver2; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; +import android.content.pm.IOnPermissionsChangeListener; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.InstrumentationInfo; import android.content.pm.KeySet; @@ -490,4 +491,7 @@ interface IPackageManager { KeySet getSigningKeySet(String packageName); boolean isPackageSignedByKeySet(String packageName, in KeySet ks); boolean isPackageSignedByKeySetExactly(String packageName, in KeySet ks); + + void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener); + void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index c3f2c43..bd50ca0 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -16,11 +16,13 @@ package android.content.pm; +import android.Manifest; import android.annotation.CheckResult; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.StringRes; @@ -78,6 +80,21 @@ public abstract class PackageManager { } /** + * Listener for changes in permissions granted to a UID. + * + * @hide + */ + @SystemApi + public interface OnPermissionsChangedListener { + + /** + * Called when the permissions for a UID change. + * @param uid The UID with a change. + */ + public void onPermissionsChanged(int uid); + } + + /** * {@link PackageInfo} flag: return information about * activities in the package in {@link PackageInfo#activities}. */ @@ -4295,6 +4312,27 @@ public abstract class PackageManager { public abstract boolean isSafeMode(); /** + * Adds a listener for permission changes for installed packages. + * + * @param listener The listener to add. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) + public abstract void addOnPermissionsChangeListener(OnPermissionsChangedListener listener); + + /** + * Remvoes a listener for permission changes for installed packages. + * + * @param listener The listener to remove. + * + * @hide + */ + @SystemApi + public abstract void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener); + + /** * Return the {@link KeySet} associated with the String alias for this * application. * diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index d2a9cdc..5849350 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -77,7 +77,6 @@ public class RemoteCallbackList<E extends IInterface> { public boolean register(E callback) { return register(callback, null); } - /** * Add a new callback to the list. This callback will remain in the list * until a corresponding call to {@link #unregister} or its hosting process diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 709de9e..0911d42 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1979,6 +1979,10 @@ <permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS" android:protectionLevel="signature" /> + <!-- @hide Allows an application to observe permission changes. --> + <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" + android:protectionLevel="signatureOrSystem" /> + <!-- Allows an application to use SurfaceFlinger's low level features. <p>Not for use by third-party applications. --> <permission android:name="android.permission.ACCESS_SURFACE_FLINGER" diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 7bdbec6..6c9fd3f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -92,6 +92,7 @@ import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.FeatureInfo; +import android.content.pm.IOnPermissionsChangeListener; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageDeleteObserver2; @@ -144,6 +145,7 @@ import android.os.Message; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.RemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SELinux; @@ -523,6 +525,8 @@ public class PackageManagerService extends IPackageManager.Stub { private AtomicInteger mNextMoveId = new AtomicInteger(); private final MoveCallbacks mMoveCallbacks; + private final OnPermissionChangeListeners mOnPermissionChangeListeners; + // Cache of users who need badging. SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray(); @@ -1731,6 +1735,9 @@ public class PackageManagerService extends IPackageManager.Stub { mPackageDexOptimizer = new PackageDexOptimizer(this); mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper()); + mOnPermissionChangeListeners = new OnPermissionChangeListeners( + FgThread.get().getLooper()); + getDefaultDisplayMetrics(context, mMetrics); SystemConfig systemConfig = SystemConfig.getInstance(); @@ -3195,10 +3202,11 @@ public class PackageManagerService extends IPackageManager.Stub { case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { gidsChanged = true; - } - break; + } break; } + mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid); + // Not critical if that is lost - app has to request again. mSettings.writeRuntimePermissionsForUserLPr(userId, false); } @@ -3255,6 +3263,8 @@ public class PackageManagerService extends IPackageManager.Stub { return; } + mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid); + // Critical, after this call app should never have the permission. mSettings.writeRuntimePermissionsForUserLPr(userId, true); } @@ -3397,6 +3407,24 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override + public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS, + "addOnPermissionsChangeListener"); + + synchronized (mPackages) { + mOnPermissionChangeListeners.addListenerLocked(listener); + } + } + + @Override + public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener) { + synchronized (mPackages) { + mOnPermissionChangeListeners.removeListenerLocked(listener); + } + } + + @Override public boolean isProtectedBroadcast(String actionName) { synchronized (mPackages) { return mProtectedBroadcasts.contains(actionName); @@ -15297,4 +15325,57 @@ public class PackageManagerService extends IPackageManager.Stub { } } } + + private final class OnPermissionChangeListeners extends Handler { + private static final int MSG_ON_PERMISSIONS_CHANGED = 1; + + private final RemoteCallbackList<IOnPermissionsChangeListener> mPermissionListeners = + new RemoteCallbackList<>(); + + public OnPermissionChangeListeners(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_ON_PERMISSIONS_CHANGED: { + final int uid = msg.arg1; + handleOnPermissionsChanged(uid); + } break; + } + } + + public void addListenerLocked(IOnPermissionsChangeListener listener) { + mPermissionListeners.register(listener); + + } + + public void removeListenerLocked(IOnPermissionsChangeListener listener) { + mPermissionListeners.unregister(listener); + } + + public void onPermissionsChanged(int uid) { + if (mPermissionListeners.getRegisteredCallbackCount() > 0) { + obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget(); + } + } + + private void handleOnPermissionsChanged(int uid) { + final int count = mPermissionListeners.beginBroadcast(); + try { + for (int i = 0; i < count; i++) { + IOnPermissionsChangeListener callback = mPermissionListeners + .getBroadcastItem(i); + try { + callback.onPermissionsChanged(uid); + } catch (RemoteException e) { + Log.e(TAG, "Permission listener is dead", e); + } + } + } finally { + mPermissionListeners.finishBroadcast(); + } + } + } } diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 3b7aa9f..ac92dc0 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -224,6 +224,18 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) { + throw new UnsupportedOperationException(); + } + + /** @hide */ + @Override + public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) { + throw new UnsupportedOperationException(); + } + @Override public int checkSignatures(String pkg1, String pkg2) { throw new UnsupportedOperationException(); |