diff --git a/core/java/android/view/DragAndDropPermissions.java b/core/java/android/view/DragAndDropPermissions.java index d47604d6ec417..16204d852a3a1 100644 --- a/core/java/android/view/DragAndDropPermissions.java +++ b/core/java/android/view/DragAndDropPermissions.java @@ -16,12 +16,15 @@ package android.view; +import static java.lang.Integer.toHexString; + import android.app.Activity; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; +import android.util.Log; import com.android.internal.view.IDragAndDropPermissions; @@ -56,9 +59,28 @@ import com.android.internal.view.IDragAndDropPermissions; */ public final class DragAndDropPermissions implements Parcelable { - private final IDragAndDropPermissions mDragAndDropPermissions; + private static final String TAG = "DragAndDrop"; + private static final boolean DEBUG = false; - private IBinder mTransientToken; + /** + * Permissions for a drop can be granted in one of two ways: + *
    + *
  1. An app can explicitly request permissions using + * {@link Activity#requestDragAndDropPermissions(DragEvent)}. In this case permissions are + * revoked automatically when then activity is destroyed. See {@link #take(IBinder)}. + *
  2. The platform can request permissions on behalf of the app (e.g. in + * {@link android.widget.Editor}). In this case permissions are revoked automatically when + * the app process terminates. See {@link #takeTransient()}. + *
+ * + *

In order to implement the second case above, we create a static token object here. This + * ensures that the token stays alive for the lifetime of the app process, allowing us to + * revoke permissions when the app process terminates using {@link IBinder#linkToDeath} in + * {@code DragAndDropPermissionsHandler}. + */ + private static IBinder sAppToken; + + private final IDragAndDropPermissions mDragAndDropPermissions; /** * Create a new {@link DragAndDropPermissions} object to control the access permissions for @@ -81,30 +103,51 @@ public final class DragAndDropPermissions implements Parcelable { } /** - * Take the permissions and bind their lifetime to the activity. + * Take permissions, binding their lifetime to the activity. + * + *

Note: This API is exposed to apps via + * {@link Activity#requestDragAndDropPermissions(DragEvent)}. + * * @param activityToken Binder pointing to an Activity instance to bind the lifetime to. * @return True if permissions are successfully taken. + * * @hide */ public boolean take(IBinder activityToken) { try { + if (DEBUG) { + Log.d(TAG, this + ": calling take() with activity-bound token: " + + toHexString(activityToken.hashCode())); + } mDragAndDropPermissions.take(activityToken); } catch (RemoteException e) { + Log.w(TAG, this + ": take() failed with a RemoteException", e); return false; } return true; } /** - * Take the permissions. Must call {@link #release} explicitly. + * Take permissions transiently. Permissions will be revoked when the app process terminates. + * + *

Note: This API is not exposed to apps. + * * @return True if permissions are successfully taken. + * * @hide */ public boolean takeTransient() { try { - mTransientToken = new Binder(); - mDragAndDropPermissions.takeTransient(mTransientToken); + if (sAppToken == null) { + sAppToken = new Binder(); + } + if (DEBUG) { + Log.d(TAG, this + ": calling takeTransient() with process-bound token: " + + toHexString(sAppToken.hashCode())); + } + mDragAndDropPermissions.takeTransient(sAppToken); } catch (RemoteException e) { + Log.w(TAG, this + ": takeTransient() failed with a RemoteException", e); return false; } return true; @@ -116,8 +159,8 @@ public final class DragAndDropPermissions implements Parcelable { public void release() { try { mDragAndDropPermissions.release(); - mTransientToken = null; } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -142,11 +185,9 @@ public final class DragAndDropPermissions implements Parcelable { @Override public void writeToParcel(Parcel destination, int flags) { destination.writeStrongInterface(mDragAndDropPermissions); - destination.writeStrongBinder(mTransientToken); } private DragAndDropPermissions(Parcel in) { mDragAndDropPermissions = IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder()); - mTransientToken = in.readStrongBinder(); } } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 012352d0a0f53..bcbfe37c6904c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -2898,9 +2898,6 @@ public class Editor { } finally { mTextView.endBatchEdit(); mUndoInputFilter.freezeLastEdit(); - if (permissions != null) { - permissions.release(); - } } } diff --git a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java index 999c5859ba1d4..62e4a85476000 100644 --- a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java +++ b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java @@ -16,12 +16,15 @@ package com.android.server.wm; +import static java.lang.Integer.toHexString; + import android.app.UriGrantsManager; import android.content.ClipData; import android.net.Uri; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.util.Log; import com.android.internal.view.IDragAndDropPermissions; import com.android.server.LocalServices; @@ -32,6 +35,9 @@ import java.util.ArrayList; class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub implements IBinder.DeathRecipient { + private static final String TAG = "DragAndDrop"; + private static final boolean DEBUG = false; + private final WindowManagerGlobalLock mGlobalLock; private final int mSourceUid; private final String mTargetPackage; @@ -43,7 +49,7 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub private IBinder mActivityToken = null; private IBinder mPermissionOwnerToken = null; - private IBinder mTransientToken = null; + private IBinder mAppToken = null; DragAndDropPermissionsHandler(WindowManagerGlobalLock lock, ClipData clipData, int sourceUid, String targetPackage, int mode, int sourceUserId, int targetUserId) { @@ -62,6 +68,10 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub if (mActivityToken != null || mPermissionOwnerToken != null) { return; } + if (DEBUG) { + Log.d(TAG, this + ": taking permissions bound to activity: " + + toHexString(activityToken.hashCode())); + } mActivityToken = activityToken; // Will throw if Activity is not found. @@ -84,14 +94,18 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub } @Override - public void takeTransient(IBinder transientToken) throws RemoteException { + public void takeTransient(IBinder appToken) throws RemoteException { if (mActivityToken != null || mPermissionOwnerToken != null) { return; } + if (DEBUG) { + Log.d(TAG, this + ": taking permissions bound to app process: " + + toHexString(appToken.hashCode())); + } mPermissionOwnerToken = LocalServices.getService(UriGrantsManagerInternal.class) .newUriPermissionOwner("drop"); - mTransientToken = transientToken; - mTransientToken.linkToDeath(this, 0); + mAppToken = appToken; + mAppToken.linkToDeath(this, 0); doTake(mPermissionOwnerToken); } @@ -112,11 +126,17 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub } finally { mActivityToken = null; } + if (DEBUG) { + Log.d(TAG, this + ": releasing activity-bound permissions"); + } } else { permissionOwner = mPermissionOwnerToken; mPermissionOwnerToken = null; - mTransientToken.unlinkToDeath(this, 0); - mTransientToken = null; + mAppToken.unlinkToDeath(this, 0); + mAppToken = null; + if (DEBUG) { + Log.d(TAG, this + ": releasing process-bound permissions"); + } } UriGrantsManagerInternal ugm = LocalServices.getService(UriGrantsManagerInternal.class); @@ -139,6 +159,9 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub @Override public void binderDied() { + if (DEBUG) { + Log.d(TAG, this + ": app process died: " + toHexString(mAppToken.hashCode())); + } try { release(); } catch (RemoteException e) {