1/* 2** Copyright 2015, The Android Open Source Project 3** 4** Licensed under the Apache License, Version 2.0 (the "License"); 5** you may not use this file except in compliance with the License. 6** You may obtain a copy of the License at 7** 8** http://www.apache.org/licenses/LICENSE-2.0 9** 10** Unless required by applicable law or agreed to in writing, software 11** distributed under the License is distributed on an "AS IS" BASIS, 12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13** See the License for the specific language governing permissions and 14** limitations under the License. 15*/ 16 17package com.android.server.wm; 18 19import android.app.ActivityManager; 20import android.content.ClipData; 21import android.net.Uri; 22import android.os.Binder; 23import android.os.IBinder; 24import android.os.RemoteException; 25 26import com.android.internal.view.IDragAndDropPermissions; 27 28import java.util.ArrayList; 29 30class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub 31 implements IBinder.DeathRecipient { 32 33 private final int mSourceUid; 34 private final String mTargetPackage; 35 private final int mMode; 36 private final int mSourceUserId; 37 private final int mTargetUserId; 38 39 private final ArrayList<Uri> mUris = new ArrayList<Uri>(); 40 41 private IBinder mActivityToken = null; 42 private IBinder mPermissionOwnerToken = null; 43 private IBinder mTransientToken = null; 44 45 DragAndDropPermissionsHandler(ClipData clipData, int sourceUid, String targetPackage, int mode, 46 int sourceUserId, int targetUserId) { 47 mSourceUid = sourceUid; 48 mTargetPackage = targetPackage; 49 mMode = mode; 50 mSourceUserId = sourceUserId; 51 mTargetUserId = targetUserId; 52 53 clipData.collectUris(mUris); 54 } 55 56 @Override 57 public void take(IBinder activityToken) throws RemoteException { 58 if (mActivityToken != null || mPermissionOwnerToken != null) { 59 return; 60 } 61 mActivityToken = activityToken; 62 63 // Will throw if Activity is not found. 64 IBinder permissionOwner = ActivityManager.getService(). 65 getUriPermissionOwnerForActivity(mActivityToken); 66 67 doTake(permissionOwner); 68 } 69 70 private void doTake(IBinder permissionOwner) throws RemoteException { 71 long origId = Binder.clearCallingIdentity(); 72 try { 73 for (int i = 0; i < mUris.size(); i++) { 74 ActivityManager.getService().grantUriPermissionFromOwner( 75 permissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode, 76 mSourceUserId, mTargetUserId); 77 } 78 } finally { 79 Binder.restoreCallingIdentity(origId); 80 } 81 } 82 83 @Override 84 public void takeTransient(IBinder transientToken) throws RemoteException { 85 if (mActivityToken != null || mPermissionOwnerToken != null) { 86 return; 87 } 88 mPermissionOwnerToken = ActivityManager.getService().newUriPermissionOwner("drop"); 89 mTransientToken = transientToken; 90 mTransientToken.linkToDeath(this, 0); 91 92 doTake(mPermissionOwnerToken); 93 } 94 95 @Override 96 public void release() throws RemoteException { 97 if (mActivityToken == null && mPermissionOwnerToken == null) { 98 return; 99 } 100 101 IBinder permissionOwner = null; 102 if (mActivityToken != null) { 103 try { 104 permissionOwner = ActivityManager.getService(). 105 getUriPermissionOwnerForActivity(mActivityToken); 106 } catch (Exception e) { 107 // Activity is destroyed, permissions already revoked. 108 return; 109 } finally { 110 mActivityToken = null; 111 } 112 } else { 113 permissionOwner = mPermissionOwnerToken; 114 mPermissionOwnerToken = null; 115 mTransientToken.unlinkToDeath(this, 0); 116 mTransientToken = null; 117 } 118 119 for (int i = 0; i < mUris.size(); ++i) { 120 ActivityManager.getService().revokeUriPermissionFromOwner( 121 permissionOwner, mUris.get(i), mMode, mSourceUserId); 122 } 123 } 124 125 @Override 126 public void binderDied() { 127 try { 128 release(); 129 } catch (RemoteException e) { 130 // Cannot happen, local call. 131 } 132 } 133} 134