Merge "Release drag-and-drop URI permissions on gc if not tied to an activity" into sc-dev

This commit is contained in:
Nikita Dubrovsky
2021-05-03 21:53:10 +00:00
committed by Android (Google) Code Review
6 changed files with 47 additions and 47 deletions

View File

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

View File

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

View File

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

View File

@@ -24,6 +24,6 @@ import android.os.IBinder;
*/
interface IDragAndDropPermissions {
void take(IBinder activityToken);
void takeTransient(IBinder transientToken);
void takeTransient();
void release();
}

View File

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

View File

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