Home | History | Annotate | Download | only in wm
      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 
     17 package com.android.server.wm;
     18 
     19 import android.app.ActivityManager;
     20 import android.content.ClipData;
     21 import android.net.Uri;
     22 import android.os.Binder;
     23 import android.os.IBinder;
     24 import android.os.RemoteException;
     25 
     26 import com.android.internal.view.IDragAndDropPermissions;
     27 
     28 import java.util.ArrayList;
     29 
     30 class 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