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.os.UserHandle; 25 import android.util.ArraySet; 26 import android.util.proto.ProtoOutputStream; 27 28 import com.android.server.am.UriPermissionOwnerProto; 29 30 import com.google.android.collect.Sets; 31 32 import java.io.PrintWriter; 33 import java.util.ArrayList; 34 import java.util.Iterator; 35 import java.util.List; 36 37 public class UriPermissionOwner { 38 private final UriGrantsManagerInternal mService; 39 private final Object mOwner; 40 41 private Binder externalToken; 42 43 private ArraySet<UriPermission> mReadPerms; 44 private ArraySet<UriPermission> mWritePerms; 45 46 class ExternalToken extends Binder { getOwner()47 UriPermissionOwner getOwner() { 48 return UriPermissionOwner.this; 49 } 50 } 51 UriPermissionOwner(UriGrantsManagerInternal service, Object owner)52 public UriPermissionOwner(UriGrantsManagerInternal service, Object owner) { 53 mService = service; 54 mOwner = owner; 55 } 56 getExternalToken()57 public Binder getExternalToken() { 58 if (externalToken == null) { 59 externalToken = new ExternalToken(); 60 } 61 return externalToken; 62 } 63 fromExternalToken(IBinder token)64 static UriPermissionOwner fromExternalToken(IBinder token) { 65 if (token instanceof ExternalToken) { 66 return ((ExternalToken) token).getOwner(); 67 } 68 return null; 69 } 70 removeUriPermissions()71 public void removeUriPermissions() { 72 removeUriPermissions(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION); 73 } 74 removeUriPermissions(int mode)75 void removeUriPermissions(int mode) { 76 removeUriPermission(null, mode); 77 } 78 removeUriPermission(GrantUri grantUri, int mode)79 void removeUriPermission(GrantUri grantUri, int mode) { 80 removeUriPermission(grantUri, mode, null, UserHandle.USER_ALL); 81 } 82 removeUriPermission(GrantUri grantUri, int mode, String targetPgk, int targetUserId)83 void removeUriPermission(GrantUri grantUri, int mode, String targetPgk, int targetUserId) { 84 final List<UriPermission> permissionsToRemove = new ArrayList<>(); 85 86 synchronized (this) { 87 if ((mode & FLAG_GRANT_READ_URI_PERMISSION) != 0 && mReadPerms != null) { 88 final Iterator<UriPermission> it = mReadPerms.iterator(); 89 while (it.hasNext()) { 90 final UriPermission perm = it.next(); 91 if (grantUri != null && !grantUri.equals(perm.uri)) { 92 continue; 93 } 94 if (targetPgk != null && !targetPgk.equals(perm.targetPkg)) { 95 continue; 96 } 97 if (targetUserId != UserHandle.USER_ALL && targetUserId != perm.targetUserId) { 98 continue; 99 } 100 permissionsToRemove.add(perm); 101 perm.removeReadOwner(this); 102 it.remove(); 103 } 104 if (mReadPerms.isEmpty()) { 105 mReadPerms = null; 106 } 107 } 108 109 if ((mode & FLAG_GRANT_WRITE_URI_PERMISSION) != 0 && mWritePerms != null) { 110 final Iterator<UriPermission> it = mWritePerms.iterator(); 111 while (it.hasNext()) { 112 final UriPermission perm = it.next(); 113 if (grantUri != null && !grantUri.equals(perm.uri)) { 114 continue; 115 } 116 if (targetPgk != null && !targetPgk.equals(perm.targetPkg)) { 117 continue; 118 } 119 if (targetUserId != UserHandle.USER_ALL && targetUserId != perm.targetUserId) { 120 continue; 121 } 122 permissionsToRemove.add(perm); 123 perm.removeWriteOwner(this); 124 it.remove(); 125 } 126 if (mWritePerms.isEmpty()) { 127 mWritePerms = null; 128 } 129 } 130 } 131 132 final int permissionsToRemoveSize = permissionsToRemove.size(); 133 for (int i = 0; i < permissionsToRemoveSize; i++) { 134 mService.removeUriPermissionIfNeeded(permissionsToRemove.get(i)); 135 } 136 } 137 addReadPermission(UriPermission perm)138 public void addReadPermission(UriPermission perm) { 139 synchronized (this) { 140 if (mReadPerms == null) { 141 mReadPerms = Sets.newArraySet(); 142 } 143 mReadPerms.add(perm); 144 } 145 } 146 addWritePermission(UriPermission perm)147 public void addWritePermission(UriPermission perm) { 148 synchronized (this) { 149 if (mWritePerms == null) { 150 mWritePerms = Sets.newArraySet(); 151 } 152 mWritePerms.add(perm); 153 } 154 } 155 removeReadPermission(UriPermission perm)156 public void removeReadPermission(UriPermission perm) { 157 synchronized (this) { 158 if (mReadPerms != null) { 159 mReadPerms.remove(perm); 160 if (mReadPerms.isEmpty()) { 161 mReadPerms = null; 162 } 163 } 164 } 165 } 166 removeWritePermission(UriPermission perm)167 public void removeWritePermission(UriPermission perm) { 168 synchronized (this) { 169 if (mWritePerms != null) { 170 mWritePerms.remove(perm); 171 if (mWritePerms.isEmpty()) { 172 mWritePerms = null; 173 } 174 } 175 } 176 } 177 dump(PrintWriter pw, String prefix)178 public void dump(PrintWriter pw, String prefix) { 179 synchronized (this) { 180 if (mReadPerms != null) { 181 pw.print(prefix); 182 pw.print("readUriPermissions="); 183 pw.println(mReadPerms); 184 } 185 if (mWritePerms != null) { 186 pw.print(prefix); 187 pw.print("writeUriPermissions="); 188 pw.println(mWritePerms); 189 } 190 } 191 } 192 dumpDebug(ProtoOutputStream proto, long fieldId)193 public void dumpDebug(ProtoOutputStream proto, long fieldId) { 194 long token = proto.start(fieldId); 195 proto.write(UriPermissionOwnerProto.OWNER, mOwner.toString()); 196 synchronized (this) { 197 if (mReadPerms != null) { 198 for (UriPermission p : mReadPerms) { 199 p.uri.dumpDebug(proto, UriPermissionOwnerProto.READ_PERMS); 200 } 201 } 202 if (mWritePerms != null) { 203 for (UriPermission p : mWritePerms) { 204 p.uri.dumpDebug(proto, UriPermissionOwnerProto.WRITE_PERMS); 205 } 206 } 207 } 208 proto.end(token); 209 } 210 211 @Override toString()212 public String toString() { 213 return mOwner.toString(); 214 } 215 } 216