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