1/*
2** Copyright 2016, 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;
18
19import android.annotation.NonNull;
20import android.annotation.UserIdInt;
21import android.app.ActivityManagerNative;
22import android.content.Intent;
23import android.net.Uri;
24import android.os.Binder;
25import android.os.IBinder;
26import android.os.RemoteException;
27
28import com.android.internal.annotations.GuardedBy;
29import com.android.internal.inputmethod.IInputContentUriToken;
30
31final class InputContentUriTokenHandler extends IInputContentUriToken.Stub {
32
33    @NonNull
34    private final Uri mUri;
35    private final int mSourceUid;
36    @NonNull
37    private final String mTargetPackage;
38    @UserIdInt
39    private final int mSourceUserId;
40    @UserIdInt
41    private final int mTargetUserId;
42
43    private final Object mLock = new Object();
44
45    @GuardedBy("mLock")
46    private IBinder mPermissionOwnerToken = null;
47
48    InputContentUriTokenHandler(@NonNull Uri contentUri, int sourceUid,
49            @NonNull String targetPackage, @UserIdInt int sourceUserId,
50            @UserIdInt int targetUserId) {
51        mUri = contentUri;
52        mSourceUid = sourceUid;
53        mTargetPackage = targetPackage;
54        mSourceUserId = sourceUserId;
55        mTargetUserId = targetUserId;
56    }
57
58    @Override
59    public void take() {
60        synchronized (mLock) {
61            if (mPermissionOwnerToken != null) {
62                // Permission is already granted.
63                return;
64            }
65
66            try {
67                mPermissionOwnerToken = ActivityManagerNative.getDefault()
68                        .newUriPermissionOwner("InputContentUriTokenHandler");
69            } catch (RemoteException e) {
70                e.rethrowFromSystemServer();
71            }
72
73            doTakeLocked(mPermissionOwnerToken);
74        }
75    }
76
77    private void doTakeLocked(@NonNull IBinder permissionOwner) {
78        long origId = Binder.clearCallingIdentity();
79        try {
80            try {
81                ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
82                        permissionOwner, mSourceUid, mTargetPackage, mUri,
83                        Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId, mTargetUserId);
84            } catch (RemoteException e) {
85                e.rethrowFromSystemServer();
86            }
87        } finally {
88            Binder.restoreCallingIdentity(origId);
89        }
90    }
91
92    @Override
93    public void release() {
94        synchronized (mLock) {
95            if (mPermissionOwnerToken == null) {
96                return;
97            }
98            try {
99                ActivityManagerNative.getDefault().revokeUriPermissionFromOwner(
100                        mPermissionOwnerToken, mUri,
101                        Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId);
102            } catch (RemoteException e) {
103                e.rethrowFromSystemServer();
104            } finally {
105                mPermissionOwnerToken = null;
106            }
107        }
108    }
109
110    /**
111     * {@inheritDoc}
112     */
113    @Override
114    protected void finalize() throws Throwable {
115        try {
116            release();
117        } finally {
118            super.finalize();
119        }
120    }
121}
122