ProviderMap.java revision 540e123b14ef71f0bfda325e11773c1c510fb8ba
1/* 2 * Copyright (C) 2011 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 17package com.android.server.am; 18 19import android.content.ComponentName; 20import android.os.Binder; 21import android.os.RemoteException; 22import android.os.UserHandle; 23import android.util.Slog; 24import android.util.SparseArray; 25import com.android.internal.os.TransferPipe; 26 27import java.io.FileDescriptor; 28import java.io.IOException; 29import java.io.PrintWriter; 30import java.util.ArrayList; 31import java.util.HashMap; 32import java.util.Iterator; 33import java.util.Map; 34import java.util.Set; 35 36/** 37 * Keeps track of content providers by authority (name) and class. It separates the mapping by 38 * user and ones that are not user-specific (system providers). 39 */ 40public final class ProviderMap { 41 42 private static final String TAG = "ProviderMap"; 43 44 private static final boolean DBG = false; 45 46 private final ActivityManagerService mAm; 47 48 private final HashMap<String, ContentProviderRecord> mSingletonByName 49 = new HashMap<String, ContentProviderRecord>(); 50 private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass 51 = new HashMap<ComponentName, ContentProviderRecord>(); 52 53 private final SparseArray<HashMap<String, ContentProviderRecord>> mProvidersByNamePerUser 54 = new SparseArray<HashMap<String, ContentProviderRecord>>(); 55 private final SparseArray<HashMap<ComponentName, ContentProviderRecord>> mProvidersByClassPerUser 56 = new SparseArray<HashMap<ComponentName, ContentProviderRecord>>(); 57 58 ProviderMap(ActivityManagerService am) { 59 mAm = am; 60 } 61 62 ContentProviderRecord getProviderByName(String name) { 63 return getProviderByName(name, -1); 64 } 65 66 ContentProviderRecord getProviderByName(String name, int userId) { 67 if (DBG) { 68 Slog.i(TAG, "getProviderByName: " + name + " , callingUid = " + Binder.getCallingUid()); 69 } 70 // Try to find it in the global list 71 ContentProviderRecord record = mSingletonByName.get(name); 72 if (record != null) { 73 return record; 74 } 75 76 // Check the current user's list 77 return getProvidersByName(userId).get(name); 78 } 79 80 ContentProviderRecord getProviderByClass(ComponentName name) { 81 return getProviderByClass(name, -1); 82 } 83 84 ContentProviderRecord getProviderByClass(ComponentName name, int userId) { 85 if (DBG) { 86 Slog.i(TAG, "getProviderByClass: " + name + ", callingUid = " + Binder.getCallingUid()); 87 } 88 // Try to find it in the global list 89 ContentProviderRecord record = mSingletonByClass.get(name); 90 if (record != null) { 91 return record; 92 } 93 94 // Check the current user's list 95 return getProvidersByClass(userId).get(name); 96 } 97 98 void putProviderByName(String name, ContentProviderRecord record) { 99 if (DBG) { 100 Slog.i(TAG, "putProviderByName: " + name + " , callingUid = " + Binder.getCallingUid() 101 + ", record uid = " + record.appInfo.uid); 102 } 103 if (record.singleton) { 104 mSingletonByName.put(name, record); 105 } else { 106 final int userId = UserHandle.getUserId(record.appInfo.uid); 107 getProvidersByName(userId).put(name, record); 108 } 109 } 110 111 void putProviderByClass(ComponentName name, ContentProviderRecord record) { 112 if (DBG) { 113 Slog.i(TAG, "putProviderByClass: " + name + " , callingUid = " + Binder.getCallingUid() 114 + ", record uid = " + record.appInfo.uid); 115 } 116 if (record.singleton) { 117 mSingletonByClass.put(name, record); 118 } else { 119 final int userId = UserHandle.getUserId(record.appInfo.uid); 120 getProvidersByClass(userId).put(name, record); 121 } 122 } 123 124 void removeProviderByName(String name, int userId) { 125 if (mSingletonByName.containsKey(name)) { 126 if (DBG) 127 Slog.i(TAG, "Removing from globalByName name=" + name); 128 mSingletonByName.remove(name); 129 } else { 130 if (userId < 0) throw new IllegalArgumentException("Bad user " + userId); 131 if (DBG) 132 Slog.i(TAG, 133 "Removing from providersByName name=" + name + " user=" + userId); 134 HashMap<String, ContentProviderRecord> map = getProvidersByName(userId); 135 // map returned by getProvidersByName wouldn't be null 136 map.remove(name); 137 if (map.size() == 0) { 138 mProvidersByNamePerUser.remove(userId); 139 } 140 } 141 } 142 143 void removeProviderByClass(ComponentName name, int userId) { 144 if (mSingletonByClass.containsKey(name)) { 145 if (DBG) 146 Slog.i(TAG, "Removing from globalByClass name=" + name); 147 mSingletonByClass.remove(name); 148 } else { 149 if (userId < 0) throw new IllegalArgumentException("Bad user " + userId); 150 if (DBG) 151 Slog.i(TAG, 152 "Removing from providersByClass name=" + name + " user=" + userId); 153 HashMap<ComponentName, ContentProviderRecord> map = getProvidersByClass(userId); 154 // map returned by getProvidersByClass wouldn't be null 155 map.remove(name); 156 if (map.size() == 0) { 157 mProvidersByClassPerUser.remove(userId); 158 } 159 } 160 } 161 162 private HashMap<String, ContentProviderRecord> getProvidersByName(int userId) { 163 if (userId < 0) throw new IllegalArgumentException("Bad user " + userId); 164 final HashMap<String, ContentProviderRecord> map = mProvidersByNamePerUser.get(userId); 165 if (map == null) { 166 HashMap<String, ContentProviderRecord> newMap = new HashMap<String, ContentProviderRecord>(); 167 mProvidersByNamePerUser.put(userId, newMap); 168 return newMap; 169 } else { 170 return map; 171 } 172 } 173 174 HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int userId) { 175 if (userId < 0) throw new IllegalArgumentException("Bad user " + userId); 176 final HashMap<ComponentName, ContentProviderRecord> map 177 = mProvidersByClassPerUser.get(userId); 178 if (map == null) { 179 HashMap<ComponentName, ContentProviderRecord> newMap 180 = new HashMap<ComponentName, ContentProviderRecord>(); 181 mProvidersByClassPerUser.put(userId, newMap); 182 return newMap; 183 } else { 184 return map; 185 } 186 } 187 188 private boolean collectPackageProvidersLocked(String packageName, 189 Set<String> filterByClasses, boolean doit, boolean evenPersistent, 190 HashMap<ComponentName, ContentProviderRecord> providers, 191 ArrayList<ContentProviderRecord> result) { 192 boolean didSomething = false; 193 for (ContentProviderRecord provider : providers.values()) { 194 final boolean sameComponent = packageName == null 195 || (provider.info.packageName.equals(packageName) 196 && (filterByClasses == null 197 || filterByClasses.contains(provider.name.getClassName()))); 198 if (sameComponent 199 && (provider.proc == null || evenPersistent || !provider.proc.persistent)) { 200 if (!doit) { 201 return true; 202 } 203 didSomething = true; 204 result.add(provider); 205 } 206 } 207 return didSomething; 208 } 209 210 boolean collectPackageProvidersLocked(String packageName, Set<String> filterByClasses, 211 boolean doit, boolean evenPersistent, int userId, 212 ArrayList<ContentProviderRecord> result) { 213 boolean didSomething = collectPackageProvidersLocked(packageName, filterByClasses, 214 doit, evenPersistent, mSingletonByClass, result); 215 if (!doit && didSomething) { 216 return true; 217 } 218 if (userId == UserHandle.USER_ALL) { 219 for (int i = 0; i < mProvidersByClassPerUser.size(); i++) { 220 if (collectPackageProvidersLocked(packageName, filterByClasses, 221 doit, evenPersistent, mProvidersByClassPerUser.valueAt(i), result)) { 222 if (!doit) { 223 return true; 224 } 225 didSomething = true; 226 } 227 } 228 } else { 229 HashMap<ComponentName, ContentProviderRecord> items 230 = getProvidersByClass(userId); 231 if (items != null) { 232 didSomething |= collectPackageProvidersLocked(packageName, filterByClasses, 233 doit, evenPersistent, items, result); 234 } 235 } 236 return didSomething; 237 } 238 239 private boolean dumpProvidersByClassLocked(PrintWriter pw, boolean dumpAll, String dumpPackage, 240 String header, boolean needSep, HashMap<ComponentName, ContentProviderRecord> map) { 241 Iterator<Map.Entry<ComponentName, ContentProviderRecord>> it = map.entrySet().iterator(); 242 boolean written = false; 243 while (it.hasNext()) { 244 Map.Entry<ComponentName, ContentProviderRecord> e = it.next(); 245 ContentProviderRecord r = e.getValue(); 246 if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) { 247 continue; 248 } 249 if (needSep) { 250 pw.println(""); 251 needSep = false; 252 } 253 if (header != null) { 254 pw.println(header); 255 header = null; 256 } 257 written = true; 258 pw.print(" * "); 259 pw.println(r); 260 r.dump(pw, " ", dumpAll); 261 } 262 return written; 263 } 264 265 private boolean dumpProvidersByNameLocked(PrintWriter pw, String dumpPackage, 266 String header, boolean needSep, HashMap<String, ContentProviderRecord> map) { 267 Iterator<Map.Entry<String, ContentProviderRecord>> it = map.entrySet().iterator(); 268 boolean written = false; 269 while (it.hasNext()) { 270 Map.Entry<String, ContentProviderRecord> e = it.next(); 271 ContentProviderRecord r = e.getValue(); 272 if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) { 273 continue; 274 } 275 if (needSep) { 276 pw.println(""); 277 needSep = false; 278 } 279 if (header != null) { 280 pw.println(header); 281 header = null; 282 } 283 written = true; 284 pw.print(" "); 285 pw.print(e.getKey()); 286 pw.print(": "); 287 pw.println(r.toShortString()); 288 } 289 return written; 290 } 291 292 boolean dumpProvidersLocked(PrintWriter pw, boolean dumpAll, String dumpPackage) { 293 boolean needSep = false; 294 295 if (mSingletonByClass.size() > 0) { 296 needSep |= dumpProvidersByClassLocked(pw, dumpAll, dumpPackage, 297 " Published single-user content providers (by class):", needSep, 298 mSingletonByClass); 299 } 300 301 for (int i = 0; i < mProvidersByClassPerUser.size(); i++) { 302 HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(i); 303 needSep |= dumpProvidersByClassLocked(pw, dumpAll, dumpPackage, 304 " Published user " + mProvidersByClassPerUser.keyAt(i) 305 + " content providers (by class):", needSep, map); 306 } 307 308 if (dumpAll) { 309 needSep |= dumpProvidersByNameLocked(pw, dumpPackage, 310 " Single-user authority to provider mappings:", needSep, mSingletonByName); 311 312 for (int i = 0; i < mProvidersByNamePerUser.size(); i++) { 313 needSep |= dumpProvidersByNameLocked(pw, dumpPackage, 314 " User " + mProvidersByNamePerUser.keyAt(i) 315 + " authority to provider mappings:", needSep, 316 mProvidersByNamePerUser.valueAt(i)); 317 } 318 } 319 return needSep; 320 } 321 322 protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args, 323 int opti, boolean dumpAll) { 324 ArrayList<ContentProviderRecord> allProviders = new ArrayList<ContentProviderRecord>(); 325 ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>(); 326 327 synchronized (mAm) { 328 allProviders.addAll(mSingletonByClass.values()); 329 for (int i=0; i<mProvidersByClassPerUser.size(); i++) { 330 allProviders.addAll(mProvidersByClassPerUser.valueAt(i).values()); 331 } 332 333 if ("all".equals(name)) { 334 providers.addAll(allProviders); 335 } else { 336 ComponentName componentName = name != null 337 ? ComponentName.unflattenFromString(name) : null; 338 int objectId = 0; 339 if (componentName == null) { 340 // Not a '/' separated full component name; maybe an object ID? 341 try { 342 objectId = Integer.parseInt(name, 16); 343 name = null; 344 componentName = null; 345 } catch (RuntimeException e) { 346 } 347 } 348 349 for (int i=0; i<allProviders.size(); i++) { 350 ContentProviderRecord r1 = allProviders.get(i); 351 if (componentName != null) { 352 if (r1.name.equals(componentName)) { 353 providers.add(r1); 354 } 355 } else if (name != null) { 356 if (r1.name.flattenToString().contains(name)) { 357 providers.add(r1); 358 } 359 } else if (System.identityHashCode(r1) == objectId) { 360 providers.add(r1); 361 } 362 } 363 } 364 } 365 366 if (providers.size() <= 0) { 367 return false; 368 } 369 370 boolean needSep = false; 371 for (int i=0; i<providers.size(); i++) { 372 if (needSep) { 373 pw.println(); 374 } 375 needSep = true; 376 dumpProvider("", fd, pw, providers.get(i), args, dumpAll); 377 } 378 return true; 379 } 380 381 /** 382 * Invokes IApplicationThread.dumpProvider() on the thread of the specified provider if 383 * there is a thread associated with the provider. 384 */ 385 private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw, 386 final ContentProviderRecord r, String[] args, boolean dumpAll) { 387 String innerPrefix = prefix + " "; 388 synchronized (mAm) { 389 pw.print(prefix); pw.print("PROVIDER "); 390 pw.print(r); 391 pw.print(" pid="); 392 if (r.proc != null) pw.println(r.proc.pid); 393 else pw.println("(not running)"); 394 if (dumpAll) { 395 r.dump(pw, innerPrefix, true); 396 } 397 } 398 if (r.proc != null && r.proc.thread != null) { 399 pw.println(" Client:"); 400 pw.flush(); 401 try { 402 TransferPipe tp = new TransferPipe(); 403 try { 404 r.proc.thread.dumpProvider( 405 tp.getWriteFd().getFileDescriptor(), r.provider.asBinder(), args); 406 tp.setBufferPrefix(" "); 407 // Short timeout, since blocking here can 408 // deadlock with the application. 409 tp.go(fd, 2000); 410 } finally { 411 tp.kill(); 412 } 413 } catch (IOException ex) { 414 pw.println(" Failure while dumping the provider: " + ex); 415 } catch (RemoteException ex) { 416 pw.println(" Got a RemoteException while dumping the service"); 417 } 418 } 419 } 420} 421