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