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