1 /*
2  * Copyright (C) 2017 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.job;
18 
19 import android.app.UriGrantsManager;
20 import android.content.ClipData;
21 import android.content.ContentProvider;
22 import android.content.Intent;
23 import android.net.Uri;
24 import android.os.IBinder;
25 import android.os.RemoteException;
26 import android.os.UserHandle;
27 import android.util.Slog;
28 import android.util.proto.ProtoOutputStream;
29 import com.android.server.LocalServices;
30 import com.android.server.uri.UriGrantsManagerInternal;
31 
32 import java.io.PrintWriter;
33 import java.util.ArrayList;
34 
35 public final class GrantedUriPermissions {
36     private final int mGrantFlags;
37     private final int mSourceUserId;
38     private final String mTag;
39     private final IBinder mPermissionOwner;
40     private final ArrayList<Uri> mUris = new ArrayList<>();
41 
GrantedUriPermissions(int grantFlags, int uid, String tag)42     private GrantedUriPermissions(int grantFlags, int uid, String tag)
43             throws RemoteException {
44         mGrantFlags = grantFlags;
45         mSourceUserId = UserHandle.getUserId(uid);
46         mTag = tag;
47         mPermissionOwner = LocalServices
48                 .getService(UriGrantsManagerInternal.class).newUriPermissionOwner("job: " + tag);
49     }
50 
revoke()51     public void revoke() {
52         for (int i = mUris.size()-1; i >= 0; i--) {
53             LocalServices.getService(UriGrantsManagerInternal.class).revokeUriPermissionFromOwner(
54                     mPermissionOwner, mUris.get(i), mGrantFlags, mSourceUserId);
55         }
56         mUris.clear();
57     }
58 
checkGrantFlags(int grantFlags)59     public static boolean checkGrantFlags(int grantFlags) {
60         return (grantFlags & (Intent.FLAG_GRANT_WRITE_URI_PERMISSION
61                 |Intent.FLAG_GRANT_READ_URI_PERMISSION)) != 0;
62     }
63 
createFromIntent(Intent intent, int sourceUid, String targetPackage, int targetUserId, String tag)64     public static GrantedUriPermissions createFromIntent(Intent intent,
65             int sourceUid, String targetPackage, int targetUserId, String tag) {
66         int grantFlags = intent.getFlags();
67         if (!checkGrantFlags(grantFlags)) {
68             return null;
69         }
70 
71         GrantedUriPermissions perms = null;
72 
73         Uri data = intent.getData();
74         if (data != null) {
75             perms = grantUri(data, sourceUid, targetPackage, targetUserId, grantFlags, tag,
76                     perms);
77         }
78 
79         ClipData clip = intent.getClipData();
80         if (clip != null) {
81             perms = grantClip(clip, sourceUid, targetPackage, targetUserId, grantFlags, tag,
82                     perms);
83         }
84 
85         return perms;
86     }
87 
createFromClip(ClipData clip, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag)88     public static GrantedUriPermissions createFromClip(ClipData clip,
89             int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag) {
90         if (!checkGrantFlags(grantFlags)) {
91             return null;
92         }
93         GrantedUriPermissions perms = null;
94         if (clip != null) {
95             perms = grantClip(clip, sourceUid, targetPackage, targetUserId, grantFlags,
96                     tag, perms);
97         }
98         return perms;
99     }
100 
grantClip(ClipData clip, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, GrantedUriPermissions curPerms)101     private static GrantedUriPermissions grantClip(ClipData clip,
102             int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag,
103             GrantedUriPermissions curPerms) {
104         final int N = clip.getItemCount();
105         for (int i = 0; i < N; i++) {
106             curPerms = grantItem(clip.getItemAt(i), sourceUid, targetPackage, targetUserId,
107                     grantFlags, tag, curPerms);
108         }
109         return curPerms;
110     }
111 
grantUri(Uri uri, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, GrantedUriPermissions curPerms)112     private static GrantedUriPermissions grantUri(Uri uri,
113             int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag,
114             GrantedUriPermissions curPerms) {
115         try {
116             int sourceUserId = ContentProvider.getUserIdFromUri(uri,
117                     UserHandle.getUserId(sourceUid));
118             uri = ContentProvider.getUriWithoutUserId(uri);
119             if (curPerms == null) {
120                 curPerms = new GrantedUriPermissions(grantFlags, sourceUid, tag);
121             }
122             UriGrantsManager.getService().grantUriPermissionFromOwner(curPerms.mPermissionOwner,
123                     sourceUid, targetPackage, uri, grantFlags, sourceUserId, targetUserId);
124             curPerms.mUris.add(uri);
125         } catch (RemoteException e) {
126             Slog.e("JobScheduler", "AM dead");
127         }
128         return curPerms;
129     }
130 
grantItem(ClipData.Item item, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, GrantedUriPermissions curPerms)131     private static GrantedUriPermissions grantItem(ClipData.Item item,
132             int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag,
133             GrantedUriPermissions curPerms) {
134         if (item.getUri() != null) {
135             curPerms = grantUri(item.getUri(), sourceUid, targetPackage, targetUserId,
136                     grantFlags, tag, curPerms);
137         }
138         Intent intent = item.getIntent();
139         if (intent != null && intent.getData() != null) {
140             curPerms = grantUri(intent.getData(), sourceUid, targetPackage, targetUserId,
141                     grantFlags, tag, curPerms);
142         }
143         return curPerms;
144     }
145 
146     // Dumpsys infrastructure
dump(PrintWriter pw, String prefix)147     public void dump(PrintWriter pw, String prefix) {
148         pw.print(prefix); pw.print("mGrantFlags=0x"); pw.print(Integer.toHexString(mGrantFlags));
149         pw.print(" mSourceUserId="); pw.println(mSourceUserId);
150         pw.print(prefix); pw.print("mTag="); pw.println(mTag);
151         pw.print(prefix); pw.print("mPermissionOwner="); pw.println(mPermissionOwner);
152         for (int i = 0; i < mUris.size(); i++) {
153             pw.print(prefix); pw.print("#"); pw.print(i); pw.print(": ");
154             pw.println(mUris.get(i));
155         }
156     }
157 
dump(ProtoOutputStream proto, long fieldId)158     public void dump(ProtoOutputStream proto, long fieldId) {
159         final long token = proto.start(fieldId);
160 
161         proto.write(GrantedUriPermissionsDumpProto.FLAGS, mGrantFlags);
162         proto.write(GrantedUriPermissionsDumpProto.SOURCE_USER_ID, mSourceUserId);
163         proto.write(GrantedUriPermissionsDumpProto.TAG, mTag);
164         proto.write(GrantedUriPermissionsDumpProto.PERMISSION_OWNER, mPermissionOwner.toString());
165         for (int i = 0; i < mUris.size(); i++) {
166             Uri u = mUris.get(i);
167             if (u != null) {
168                 proto.write(GrantedUriPermissionsDumpProto.URIS, u.toString());
169             }
170         }
171 
172         proto.end(token);
173     }
174 }
175