blob: 87670d23573ec4e1fa2472153b890842414a64b9 [file] [log] [blame]
/*
** Copyright 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 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;
import com.android.server.uri.UriGrantsManagerInternal;
import java.util.ArrayList;
class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub {
private static final String TAG = "DragAndDrop";
private static final boolean DEBUG = false;
private final WindowManagerGlobalLock mGlobalLock;
private final int mSourceUid;
private final String mTargetPackage;
private final int mMode;
private final int mSourceUserId;
private final int mTargetUserId;
private final ArrayList<Uri> mUris = new ArrayList<Uri>();
private IBinder mActivityToken = null;
private IBinder mPermissionOwnerToken = null;
DragAndDropPermissionsHandler(WindowManagerGlobalLock lock, ClipData clipData, int sourceUid,
String targetPackage, int mode, int sourceUserId, int targetUserId) {
mGlobalLock = lock;
mSourceUid = sourceUid;
mTargetPackage = targetPackage;
mMode = mode;
mSourceUserId = sourceUserId;
mTargetUserId = targetUserId;
clipData.collectUris(mUris);
}
@Override
public void take(IBinder activityToken) throws RemoteException {
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.
IBinder permissionOwner = getUriPermissionOwnerForActivity(mActivityToken);
doTake(permissionOwner);
}
private void doTake(IBinder permissionOwner) throws RemoteException {
final long origId = Binder.clearCallingIdentity();
try {
for (int i = 0; i < mUris.size(); i++) {
UriGrantsManager.getService().grantUriPermissionFromOwner(
permissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode,
mSourceUserId, mTargetUserId);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
@Override
public void takeTransient() throws RemoteException {
if (mActivityToken != null || mPermissionOwnerToken != null) {
return;
}
if (DEBUG) {
Log.d(TAG, this + ": taking transient permissions");
}
mPermissionOwnerToken = LocalServices.getService(UriGrantsManagerInternal.class)
.newUriPermissionOwner("drop");
doTake(mPermissionOwnerToken);
}
@Override
public void release() throws RemoteException {
if (mActivityToken == null && mPermissionOwnerToken == null) {
return;
}
IBinder permissionOwner = null;
if (mActivityToken != null) {
try {
permissionOwner = getUriPermissionOwnerForActivity(mActivityToken);
} catch (Exception e) {
// Activity is destroyed, permissions already revoked.
return;
} finally {
mActivityToken = null;
}
if (DEBUG) {
Log.d(TAG, this + ": releasing activity-bound permissions");
}
} else {
permissionOwner = mPermissionOwnerToken;
mPermissionOwnerToken = null;
if (DEBUG) {
Log.d(TAG, this + ": releasing transient permissions");
}
}
UriGrantsManagerInternal ugm = LocalServices.getService(UriGrantsManagerInternal.class);
for (int i = 0; i < mUris.size(); ++i) {
ugm.revokeUriPermissionFromOwner(permissionOwner, mUris.get(i), mMode, mSourceUserId);
}
}
private IBinder getUriPermissionOwnerForActivity(IBinder activityToken) {
ActivityTaskManagerService.enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
synchronized (mGlobalLock) {
ActivityRecord r = ActivityRecord.isInRootTaskLocked(activityToken);
if (r == null) {
throw new IllegalArgumentException("Activity does not exist; token="
+ activityToken);
}
return r.getUriPermissionsLocked().getExternalToken();
}
}
/**
* If permissions are not tied to an activity, release whenever there are no more references
* to this object (if not already released).
*/
@Override
protected void finalize() throws Throwable {
if (DEBUG) {
Log.d(TAG, this + ": running finalizer");
}
if (mActivityToken != null || mPermissionOwnerToken == null) {
return;
}
release();
}
}