1 /*
2  * Copyright (C) 2018 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.uri;
18 
19 import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
20 import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
21 
22 import android.os.Binder;
23 import android.os.IBinder;
24 import android.util.ArraySet;
25 import android.util.proto.ProtoOutputStream;
26 
27 import com.android.server.am.UriPermissionOwnerProto;
28 import com.google.android.collect.Sets;
29 
30 import java.io.PrintWriter;
31 import java.util.Iterator;
32 
33 public class UriPermissionOwner {
34     private final UriGrantsManagerInternal mService;
35     private final Object mOwner;
36 
37     private Binder externalToken;
38 
39     private ArraySet<UriPermission> mReadPerms;
40     private ArraySet<UriPermission> mWritePerms;
41 
42     class ExternalToken extends Binder {
getOwner()43         UriPermissionOwner getOwner() {
44             return UriPermissionOwner.this;
45         }
46     }
47 
UriPermissionOwner(UriGrantsManagerInternal service, Object owner)48     public UriPermissionOwner(UriGrantsManagerInternal service, Object owner) {
49         mService = service;
50         mOwner = owner;
51     }
52 
getExternalToken()53     public Binder getExternalToken() {
54         if (externalToken == null) {
55             externalToken = new ExternalToken();
56         }
57         return externalToken;
58     }
59 
fromExternalToken(IBinder token)60     static UriPermissionOwner fromExternalToken(IBinder token) {
61         if (token instanceof ExternalToken) {
62             return ((ExternalToken)token).getOwner();
63         }
64         return null;
65     }
66 
removeUriPermissions()67     public void removeUriPermissions() {
68         removeUriPermissions(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
69     }
70 
removeUriPermissions(int mode)71     void removeUriPermissions(int mode) {
72         removeUriPermission(null, mode);
73     }
74 
removeUriPermission(GrantUri grantUri, int mode)75     void removeUriPermission(GrantUri grantUri, int mode) {
76         if ((mode & FLAG_GRANT_READ_URI_PERMISSION) != 0 && mReadPerms != null) {
77             Iterator<UriPermission> it = mReadPerms.iterator();
78             while (it.hasNext()) {
79                 UriPermission perm = it.next();
80                 if (grantUri == null || grantUri.equals(perm.uri)) {
81                     perm.removeReadOwner(this);
82                     mService.removeUriPermissionIfNeeded(perm);
83                     it.remove();
84                 }
85             }
86             if (mReadPerms.isEmpty()) {
87                 mReadPerms = null;
88             }
89         }
90         if ((mode & FLAG_GRANT_WRITE_URI_PERMISSION) != 0
91                 && mWritePerms != null) {
92             Iterator<UriPermission> it = mWritePerms.iterator();
93             while (it.hasNext()) {
94                 UriPermission perm = it.next();
95                 if (grantUri == null || grantUri.equals(perm.uri)) {
96                     perm.removeWriteOwner(this);
97                     mService.removeUriPermissionIfNeeded(perm);
98                     it.remove();
99                 }
100             }
101             if (mWritePerms.isEmpty()) {
102                 mWritePerms = null;
103             }
104         }
105     }
106 
addReadPermission(UriPermission perm)107     public void addReadPermission(UriPermission perm) {
108         if (mReadPerms == null) {
109             mReadPerms = Sets.newArraySet();
110         }
111         mReadPerms.add(perm);
112     }
113 
addWritePermission(UriPermission perm)114     public void addWritePermission(UriPermission perm) {
115         if (mWritePerms == null) {
116             mWritePerms = Sets.newArraySet();
117         }
118         mWritePerms.add(perm);
119     }
120 
removeReadPermission(UriPermission perm)121     public void removeReadPermission(UriPermission perm) {
122         mReadPerms.remove(perm);
123         if (mReadPerms.isEmpty()) {
124             mReadPerms = null;
125         }
126     }
127 
removeWritePermission(UriPermission perm)128     public void removeWritePermission(UriPermission perm) {
129         mWritePerms.remove(perm);
130         if (mWritePerms.isEmpty()) {
131             mWritePerms = null;
132         }
133     }
134 
dump(PrintWriter pw, String prefix)135     public void dump(PrintWriter pw, String prefix) {
136         if (mReadPerms != null) {
137             pw.print(prefix); pw.print("readUriPermissions="); pw.println(mReadPerms);
138         }
139         if (mWritePerms != null) {
140             pw.print(prefix); pw.print("writeUriPermissions="); pw.println(mWritePerms);
141         }
142     }
143 
writeToProto(ProtoOutputStream proto, long fieldId)144     public void writeToProto(ProtoOutputStream proto, long fieldId) {
145         long token = proto.start(fieldId);
146         proto.write(UriPermissionOwnerProto.OWNER, mOwner.toString());
147         if (mReadPerms != null) {
148             synchronized (mReadPerms) {
149                 for (UriPermission p : mReadPerms) {
150                     p.uri.writeToProto(proto, UriPermissionOwnerProto.READ_PERMS);
151                 }
152             }
153         }
154         if (mWritePerms != null) {
155             synchronized (mWritePerms) {
156                 for (UriPermission p : mWritePerms) {
157                     p.uri.writeToProto(proto, UriPermissionOwnerProto.WRITE_PERMS);
158                 }
159             }
160         }
161         proto.end(token);
162     }
163 
164     @Override
toString()165     public String toString() {
166         return mOwner.toString();
167     }
168 }
169