Merge "Release drag-and-drop URI permissions on gc if not tied to an activity" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
f3c059b9f0
@@ -19,7 +19,6 @@ 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;
|
||||
@@ -62,24 +61,6 @@ public final class DragAndDropPermissions implements Parcelable {
|
||||
private static final String TAG = "DragAndDrop";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Permissions for a drop can be granted in one of two ways:
|
||||
* <ol>
|
||||
* <li>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)}.
|
||||
* <li>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()}.
|
||||
* </ol>
|
||||
*
|
||||
* <p>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;
|
||||
|
||||
/**
|
||||
@@ -128,7 +109,9 @@ public final class DragAndDropPermissions implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Take permissions transiently. Permissions will be revoked when the app process terminates.
|
||||
* Take permissions transiently. Permissions will be tied to this object's lifecycle; if not
|
||||
* released explicitly, they will be released automatically when there are no more references
|
||||
* to this object and it's garbage collected.
|
||||
*
|
||||
* <p>Note: This API is not exposed to apps.
|
||||
*
|
||||
@@ -138,14 +121,10 @@ public final class DragAndDropPermissions implements Parcelable {
|
||||
*/
|
||||
public boolean takeTransient() {
|
||||
try {
|
||||
if (sAppToken == null) {
|
||||
sAppToken = new Binder();
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, this + ": calling takeTransient() with process-bound token: "
|
||||
+ toHexString(sAppToken.hashCode()));
|
||||
Log.d(TAG, this + ": calling takeTransient()");
|
||||
}
|
||||
mDragAndDropPermissions.takeTransient(sAppToken);
|
||||
mDragAndDropPermissions.takeTransient();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, this + ": takeTransient() failed with a RemoteException", e);
|
||||
return false;
|
||||
|
||||
@@ -74,7 +74,7 @@ public interface OnReceiveContentListener {
|
||||
* preserve the common behavior for inserting text. See the class javadoc for a sample
|
||||
* implementation.
|
||||
*
|
||||
* <p>Handling different content
|
||||
* <h3>Handling different content</h3>
|
||||
* <ul>
|
||||
* <li>Text. If the {@link ContentInfo#getSource() source} is
|
||||
* {@link ContentInfo#SOURCE_AUTOFILL autofill}, the view's content should be fully
|
||||
@@ -86,6 +86,25 @@ public interface OnReceiveContentListener {
|
||||
* completely separate view).
|
||||
* </ul>
|
||||
*
|
||||
* <h3>URI permissions</h3>
|
||||
* <p>{@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION Read permissions} are
|
||||
* granted automatically by the platform for any
|
||||
* {@link android.content.ContentResolver#SCHEME_CONTENT content URIs} in the payload passed
|
||||
* to this listener. Permissions are transient and will be released automatically by the
|
||||
* platform.
|
||||
* <ul>
|
||||
* <li>If the {@link ContentInfo#getSource() source} is the
|
||||
* {@link ContentInfo#SOURCE_CLIPBOARD clipboard}, permissions are released whenever the
|
||||
* next copy action is performed by the user.
|
||||
* <li>If the source is {@link ContentInfo#SOURCE_AUTOFILL autofill}, permissions are tied
|
||||
* to the target {@link android.app.Activity} lifecycle (released when the activity
|
||||
* finishes).
|
||||
* <li>For other sources, permissions are tied to the passed-in {@code payload} object
|
||||
* (released automatically when there are no more references to it). To ensure that
|
||||
* permissions are not released prematurely, implementations of this listener should pass
|
||||
* along the {@code payload} object if processing is done on a background thread.
|
||||
* </ul>
|
||||
*
|
||||
* @param view The view where the content insertion was requested.
|
||||
* @param payload The content to insert and related metadata.
|
||||
*
|
||||
|
||||
@@ -199,7 +199,12 @@ public final class InputContentInfo implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests a temporary read-only access permission for content URI associated with this object.
|
||||
* Requests a temporary {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION read-only}
|
||||
* access permission for the content URI associated with this object.
|
||||
*
|
||||
* <p>The lifecycle of the permission granted here is tied to this object instance. If the
|
||||
* permission is not released explicitly via {@link #releasePermission()}, it will be
|
||||
* released automatically when there are no more references to this object.</p>
|
||||
*
|
||||
* <p>Does nothing if the temporary permission is already granted.</p>
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,6 @@ import android.os.IBinder;
|
||||
*/
|
||||
interface IDragAndDropPermissions {
|
||||
void take(IBinder activityToken);
|
||||
void takeTransient(IBinder transientToken);
|
||||
void takeTransient();
|
||||
void release();
|
||||
}
|
||||
|
||||
@@ -104,7 +104,8 @@ final class InputContentUriTokenHandler extends IInputContentUriToken.Stub {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* If permissions are not released explicitly via {@link #release()}, release automatically
|
||||
* whenever there are no more references to this object.
|
||||
*/
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
|
||||
@@ -32,8 +32,7 @@ import com.android.server.uri.UriGrantsManagerInternal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub
|
||||
implements IBinder.DeathRecipient {
|
||||
class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub {
|
||||
|
||||
private static final String TAG = "DragAndDrop";
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -49,7 +48,6 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub
|
||||
|
||||
private IBinder mActivityToken = null;
|
||||
private IBinder mPermissionOwnerToken = null;
|
||||
private IBinder mAppToken = null;
|
||||
|
||||
DragAndDropPermissionsHandler(WindowManagerGlobalLock lock, ClipData clipData, int sourceUid,
|
||||
String targetPackage, int mode, int sourceUserId, int targetUserId) {
|
||||
@@ -94,18 +92,15 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeTransient(IBinder appToken) throws RemoteException {
|
||||
public void takeTransient() throws RemoteException {
|
||||
if (mActivityToken != null || mPermissionOwnerToken != null) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, this + ": taking permissions bound to app process: "
|
||||
+ toHexString(appToken.hashCode()));
|
||||
Log.d(TAG, this + ": taking transient permissions");
|
||||
}
|
||||
mPermissionOwnerToken = LocalServices.getService(UriGrantsManagerInternal.class)
|
||||
.newUriPermissionOwner("drop");
|
||||
mAppToken = appToken;
|
||||
mAppToken.linkToDeath(this, 0);
|
||||
|
||||
doTake(mPermissionOwnerToken);
|
||||
}
|
||||
@@ -132,10 +127,8 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub
|
||||
} else {
|
||||
permissionOwner = mPermissionOwnerToken;
|
||||
mPermissionOwnerToken = null;
|
||||
mAppToken.unlinkToDeath(this, 0);
|
||||
mAppToken = null;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, this + ": releasing process-bound permissions");
|
||||
Log.d(TAG, this + ": releasing transient permissions");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,15 +150,18 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If permissions are not tied to an activity, release whenever there are no more references
|
||||
* to this object (if not already released).
|
||||
*/
|
||||
@Override
|
||||
public void binderDied() {
|
||||
protected void finalize() throws Throwable {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, this + ": app process died: " + toHexString(mAppToken.hashCode()));
|
||||
Log.d(TAG, this + ": running finalizer");
|
||||
}
|
||||
try {
|
||||
release();
|
||||
} catch (RemoteException e) {
|
||||
// Cannot happen, local call.
|
||||
if (mActivityToken != null || mPermissionOwnerToken == null) {
|
||||
return;
|
||||
}
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user