* commit '0525c07f30f08008883cf2845afa3bf81f888c55': Add system API to watch for permission changes
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -77,6 +79,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}.
|
||||
@@ -4294,6 +4311,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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -3396,6 +3406,24 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
|
||||
}
|
||||
|
||||
@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) {
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user