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