am 0525c07f: am 75a0ee08: Merge "Add system API to watch for permission changes" into mnc-dev

* commit '0525c07f30f08008883cf2845afa3bf81f888c55':
  Add system API to watch for permission changes
This commit is contained in:
Svetoslav
2015-06-11 12:53:42 +00:00
committed by Android Git Automerger
10 changed files with 244 additions and 3 deletions

View File

@@ -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 \

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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.

View File

@@ -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

View File

@@ -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"

View File

@@ -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();
}
}
}
}

View File

@@ -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();