DragAndDropPermissionsHandler.java revision 377c32845bffaf68d5751d8cdf6fd60b8b3f5dc3
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.ActivityManagerNative;
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
44    DragAndDropPermissionsHandler(ClipData clipData, int sourceUid, String targetPackage, int mode,
45                                  int sourceUserId, int targetUserId) {
46        mSourceUid = sourceUid;
47        mTargetPackage = targetPackage;
48        mMode = mode;
49        mSourceUserId = sourceUserId;
50        mTargetUserId = targetUserId;
51
52        clipData.collectUris(mUris);
53    }
54
55    @Override
56    public void take(IBinder activityToken) throws RemoteException {
57        if (mActivityToken != null || mPermissionOwnerToken != null) {
58            return;
59        }
60        mActivityToken = activityToken;
61
62        // Will throw if Activity is not found.
63        IBinder permissionOwner = ActivityManagerNative.getDefault().
64                getUriPermissionOwnerForActivity(mActivityToken);
65
66        doTake(permissionOwner);
67    }
68
69    private void doTake(IBinder permissionOwner) throws RemoteException {
70        long origId = Binder.clearCallingIdentity();
71        try {
72            for (int i = 0; i < mUris.size(); i++) {
73                ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
74                        permissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode,
75                        mSourceUserId, mTargetUserId);
76            }
77        } finally {
78            Binder.restoreCallingIdentity(origId);
79        }
80    }
81
82    @Override
83    public void takeTransient(IBinder permissionOwnerToken) throws RemoteException {
84        if (mActivityToken != null || mPermissionOwnerToken != null) {
85            return;
86        }
87        mPermissionOwnerToken = permissionOwnerToken;
88        mPermissionOwnerToken.linkToDeath(this, 0);
89
90        doTake(mPermissionOwnerToken);
91    }
92
93    @Override
94    public void release() throws RemoteException {
95        if (mActivityToken == null && mPermissionOwnerToken == null) {
96            return;
97        }
98
99        IBinder permissionOwner = null;
100        if (mActivityToken != null) {
101            try {
102                permissionOwner = ActivityManagerNative.getDefault().
103                        getUriPermissionOwnerForActivity(mActivityToken);
104            } catch (Exception e) {
105                // Activity is destroyed, permissions already revoked.
106                return;
107            } finally {
108                mActivityToken = null;
109            }
110        } else {
111            permissionOwner = mPermissionOwnerToken;
112            mPermissionOwnerToken.unlinkToDeath(this, 0);
113            mPermissionOwnerToken = null;
114        }
115
116        for (int i = 0; i < mUris.size(); ++i) {
117            ActivityManagerNative.getDefault().revokeUriPermissionFromOwner(
118                    permissionOwner, mUris.get(i), mMode, mSourceUserId);
119        }
120    }
121
122    @Override
123    public void binderDied() {
124        try {
125            release();
126        } catch (RemoteException e) {
127            // Cannot happen, local call.
128        }
129    }
130}
131