blob: 7da8c48dea35fc85700afad3544ffeaa27e60d96 [file] [log] [blame]
Amith Yamasani742a6712011-05-04 14:49:28 -07001/*
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;
Amith Yamasani742a6712011-05-04 14:49:28 -070020import android.os.Binder;
Marco Nelissende7408c2012-02-08 14:57:38 -080021import android.os.RemoteException;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070022import android.os.UserHandle;
Amith Yamasani742a6712011-05-04 14:49:28 -070023import android.util.Slog;
24import android.util.SparseArray;
Dianne Hackborncbfd23e2013-06-11 14:26:53 -070025import com.android.internal.os.TransferPipe;
Amith Yamasani742a6712011-05-04 14:49:28 -070026
Marco Nelissende7408c2012-02-08 14:57:38 -080027import java.io.FileDescriptor;
28import java.io.IOException;
Amith Yamasani742a6712011-05-04 14:49:28 -070029import java.io.PrintWriter;
Marco Nelissende7408c2012-02-08 14:57:38 -080030import java.util.ArrayList;
Amith Yamasani742a6712011-05-04 14:49:28 -070031import java.util.HashMap;
32import java.util.Iterator;
33import java.util.Map;
34
35/**
36 * Keeps track of content providers by authority (name) and class. It separates the mapping by
37 * user and ones that are not user-specific (system providers).
38 */
Dianne Hackbornbe4e6aa2013-06-07 13:25:29 -070039public final class ProviderMap {
Amith Yamasani742a6712011-05-04 14:49:28 -070040
41 private static final String TAG = "ProviderMap";
42
43 private static final boolean DBG = false;
44
Dianne Hackborn2d1b3782012-09-09 17:49:39 -070045 private final ActivityManagerService mAm;
46
Dianne Hackborn7d19e022012-08-07 19:12:33 -070047 private final HashMap<String, ContentProviderRecord> mSingletonByName
Amith Yamasani742a6712011-05-04 14:49:28 -070048 = new HashMap<String, ContentProviderRecord>();
Dianne Hackborn7d19e022012-08-07 19:12:33 -070049 private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass
Amith Yamasani742a6712011-05-04 14:49:28 -070050 = 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
Dianne Hackborn2d1b3782012-09-09 17:49:39 -070057 ProviderMap(ActivityManagerService am) {
58 mAm = am;
59 }
60
Amith Yamasani742a6712011-05-04 14:49:28 -070061 ContentProviderRecord getProviderByName(String name) {
62 return getProviderByName(name, -1);
63 }
64
65 ContentProviderRecord getProviderByName(String name, int userId) {
66 if (DBG) {
67 Slog.i(TAG, "getProviderByName: " + name + " , callingUid = " + Binder.getCallingUid());
68 }
69 // Try to find it in the global list
Dianne Hackborn7d19e022012-08-07 19:12:33 -070070 ContentProviderRecord record = mSingletonByName.get(name);
Amith Yamasani742a6712011-05-04 14:49:28 -070071 if (record != null) {
72 return record;
73 }
74
75 // Check the current user's list
76 return getProvidersByName(userId).get(name);
77 }
78
79 ContentProviderRecord getProviderByClass(ComponentName name) {
80 return getProviderByClass(name, -1);
81 }
82
83 ContentProviderRecord getProviderByClass(ComponentName name, int userId) {
84 if (DBG) {
85 Slog.i(TAG, "getProviderByClass: " + name + ", callingUid = " + Binder.getCallingUid());
86 }
87 // Try to find it in the global list
Dianne Hackborn7d19e022012-08-07 19:12:33 -070088 ContentProviderRecord record = mSingletonByClass.get(name);
Amith Yamasani742a6712011-05-04 14:49:28 -070089 if (record != null) {
90 return record;
91 }
92
93 // Check the current user's list
94 return getProvidersByClass(userId).get(name);
95 }
96
97 void putProviderByName(String name, ContentProviderRecord record) {
98 if (DBG) {
99 Slog.i(TAG, "putProviderByName: " + name + " , callingUid = " + Binder.getCallingUid()
100 + ", record uid = " + record.appInfo.uid);
101 }
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700102 if (record.singleton) {
103 mSingletonByName.put(name, record);
Amith Yamasani742a6712011-05-04 14:49:28 -0700104 } else {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700105 final int userId = UserHandle.getUserId(record.appInfo.uid);
Amith Yamasani742a6712011-05-04 14:49:28 -0700106 getProvidersByName(userId).put(name, record);
107 }
108 }
109
110 void putProviderByClass(ComponentName name, ContentProviderRecord record) {
111 if (DBG) {
112 Slog.i(TAG, "putProviderByClass: " + name + " , callingUid = " + Binder.getCallingUid()
113 + ", record uid = " + record.appInfo.uid);
114 }
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700115 if (record.singleton) {
116 mSingletonByClass.put(name, record);
Amith Yamasani742a6712011-05-04 14:49:28 -0700117 } else {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700118 final int userId = UserHandle.getUserId(record.appInfo.uid);
Amith Yamasani742a6712011-05-04 14:49:28 -0700119 getProvidersByClass(userId).put(name, record);
120 }
121 }
122
Dianne Hackborn41203752012-08-31 14:05:51 -0700123 void removeProviderByName(String name, int userId) {
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700124 if (mSingletonByName.containsKey(name)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700125 if (DBG)
126 Slog.i(TAG, "Removing from globalByName name=" + name);
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700127 mSingletonByName.remove(name);
Amith Yamasani742a6712011-05-04 14:49:28 -0700128 } else {
Dianne Hackborn41203752012-08-31 14:05:51 -0700129 if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
Amith Yamasani742a6712011-05-04 14:49:28 -0700130 if (DBG)
131 Slog.i(TAG,
Dianne Hackborn41203752012-08-31 14:05:51 -0700132 "Removing from providersByName name=" + name + " user=" + userId);
133 HashMap<String, ContentProviderRecord> map = getProvidersByName(userId);
Vairavan Srinivasan88090042012-08-15 23:37:45 -0700134 // map returned by getProvidersByName wouldn't be null
135 map.remove(name);
136 if (map.size() == 0) {
Dianne Hackborn41203752012-08-31 14:05:51 -0700137 mProvidersByNamePerUser.remove(userId);
Vairavan Srinivasan88090042012-08-15 23:37:45 -0700138 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700139 }
140 }
141
Dianne Hackborn41203752012-08-31 14:05:51 -0700142 void removeProviderByClass(ComponentName name, int userId) {
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700143 if (mSingletonByClass.containsKey(name)) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700144 if (DBG)
145 Slog.i(TAG, "Removing from globalByClass name=" + name);
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700146 mSingletonByClass.remove(name);
Amith Yamasani742a6712011-05-04 14:49:28 -0700147 } else {
Dianne Hackborn41203752012-08-31 14:05:51 -0700148 if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
Amith Yamasani742a6712011-05-04 14:49:28 -0700149 if (DBG)
150 Slog.i(TAG,
Dianne Hackborn41203752012-08-31 14:05:51 -0700151 "Removing from providersByClass name=" + name + " user=" + userId);
152 HashMap<ComponentName, ContentProviderRecord> map = getProvidersByClass(userId);
Vairavan Srinivasan88090042012-08-15 23:37:45 -0700153 // map returned by getProvidersByClass wouldn't be null
154 map.remove(name);
155 if (map.size() == 0) {
Dianne Hackborn41203752012-08-31 14:05:51 -0700156 mProvidersByClassPerUser.remove(userId);
Vairavan Srinivasan88090042012-08-15 23:37:45 -0700157 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700158 }
159 }
160
Dianne Hackborn41203752012-08-31 14:05:51 -0700161 private HashMap<String, ContentProviderRecord> getProvidersByName(int userId) {
162 if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
Amith Yamasani742a6712011-05-04 14:49:28 -0700163 final HashMap<String, ContentProviderRecord> map = mProvidersByNamePerUser.get(userId);
164 if (map == null) {
165 HashMap<String, ContentProviderRecord> newMap = new HashMap<String, ContentProviderRecord>();
166 mProvidersByNamePerUser.put(userId, newMap);
167 return newMap;
168 } else {
169 return map;
170 }
171 }
172
Dianne Hackborn41203752012-08-31 14:05:51 -0700173 HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int userId) {
174 if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
175 final HashMap<ComponentName, ContentProviderRecord> map
176 = mProvidersByClassPerUser.get(userId);
Amith Yamasani742a6712011-05-04 14:49:28 -0700177 if (map == null) {
Dianne Hackborn41203752012-08-31 14:05:51 -0700178 HashMap<ComponentName, ContentProviderRecord> newMap
179 = new HashMap<ComponentName, ContentProviderRecord>();
Amith Yamasani742a6712011-05-04 14:49:28 -0700180 mProvidersByClassPerUser.put(userId, newMap);
181 return newMap;
182 } else {
183 return map;
184 }
185 }
186
Dianne Hackborn5e03e2c2012-09-06 14:21:19 -0700187 private boolean collectForceStopProvidersLocked(String name, int appId,
188 boolean doit, boolean evenPersistent, int userId,
189 HashMap<ComponentName, ContentProviderRecord> providers,
190 ArrayList<ContentProviderRecord> result) {
191 boolean didSomething = false;
192 for (ContentProviderRecord provider : providers.values()) {
193 if ((name == null || provider.info.packageName.equals(name))
194 && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
195 if (!doit) {
196 return true;
197 }
198 didSomething = true;
199 result.add(provider);
200 }
201 }
202 return didSomething;
203 }
204
205 boolean collectForceStopProviders(String name, int appId,
206 boolean doit, boolean evenPersistent, int userId,
207 ArrayList<ContentProviderRecord> result) {
208 boolean didSomething = collectForceStopProvidersLocked(name, appId, doit,
209 evenPersistent, userId, mSingletonByClass, result);
210 if (!doit && didSomething) {
211 return true;
212 }
213 if (userId == UserHandle.USER_ALL) {
214 for (int i=0; i<mProvidersByClassPerUser.size(); i++) {
215 if (collectForceStopProvidersLocked(name, appId, doit, evenPersistent,
216 userId, mProvidersByClassPerUser.valueAt(i), result)) {
217 if (!doit) {
218 return true;
219 }
220 didSomething = true;
221 }
222 }
223 } else {
Dianne Hackborn2d1b3782012-09-09 17:49:39 -0700224 HashMap<ComponentName, ContentProviderRecord> items
225 = getProvidersByClass(userId);
226 if (items != null) {
227 didSomething |= collectForceStopProvidersLocked(name, appId, doit,
228 evenPersistent, userId, items, result);
229 }
Dianne Hackborn5e03e2c2012-09-06 14:21:19 -0700230 }
231 return didSomething;
232 }
233
Dianne Hackborn390517b2013-05-30 15:03:32 -0700234 private boolean dumpProvidersByClassLocked(PrintWriter pw, boolean dumpAll, String dumpPackage,
235 String header, boolean needSep, HashMap<ComponentName, ContentProviderRecord> map) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700236 Iterator<Map.Entry<ComponentName, ContentProviderRecord>> it = map.entrySet().iterator();
Dianne Hackborn390517b2013-05-30 15:03:32 -0700237 boolean written = false;
Amith Yamasani742a6712011-05-04 14:49:28 -0700238 while (it.hasNext()) {
239 Map.Entry<ComponentName, ContentProviderRecord> e = it.next();
240 ContentProviderRecord r = e.getValue();
Dianne Hackborn390517b2013-05-30 15:03:32 -0700241 if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
242 continue;
243 }
244 if (needSep) {
245 pw.println("");
246 needSep = false;
247 }
248 if (header != null) {
249 pw.println(header);
250 header = null;
251 }
252 written = true;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700253 pw.print(" * ");
254 pw.println(r);
255 r.dump(pw, " ", dumpAll);
Amith Yamasani742a6712011-05-04 14:49:28 -0700256 }
Dianne Hackborn390517b2013-05-30 15:03:32 -0700257 return written;
Amith Yamasani742a6712011-05-04 14:49:28 -0700258 }
259
Dianne Hackborn390517b2013-05-30 15:03:32 -0700260 private boolean dumpProvidersByNameLocked(PrintWriter pw, String dumpPackage,
261 String header, boolean needSep, HashMap<String, ContentProviderRecord> map) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700262 Iterator<Map.Entry<String, ContentProviderRecord>> it = map.entrySet().iterator();
Dianne Hackborn390517b2013-05-30 15:03:32 -0700263 boolean written = false;
Amith Yamasani742a6712011-05-04 14:49:28 -0700264 while (it.hasNext()) {
265 Map.Entry<String, ContentProviderRecord> e = it.next();
266 ContentProviderRecord r = e.getValue();
Dianne Hackborn390517b2013-05-30 15:03:32 -0700267 if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
268 continue;
269 }
270 if (needSep) {
271 pw.println("");
272 needSep = false;
273 }
274 if (header != null) {
275 pw.println(header);
276 header = null;
277 }
278 written = true;
Amith Yamasani742a6712011-05-04 14:49:28 -0700279 pw.print(" ");
280 pw.print(e.getKey());
281 pw.print(": ");
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700282 pw.println(r.toShortString());
Amith Yamasani742a6712011-05-04 14:49:28 -0700283 }
Dianne Hackborn390517b2013-05-30 15:03:32 -0700284 return written;
Amith Yamasani742a6712011-05-04 14:49:28 -0700285 }
286
Dianne Hackborn390517b2013-05-30 15:03:32 -0700287 boolean dumpProvidersLocked(PrintWriter pw, boolean dumpAll, String dumpPackage) {
288 boolean needSep = false;
289
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700290 if (mSingletonByClass.size() > 0) {
Dianne Hackborn7ad34e52013-06-05 18:41:45 -0700291 needSep |= dumpProvidersByClassLocked(pw, dumpAll, dumpPackage,
Dianne Hackborn390517b2013-05-30 15:03:32 -0700292 " Published single-user content providers (by class):", needSep,
293 mSingletonByClass);
Amith Yamasani742a6712011-05-04 14:49:28 -0700294 }
295
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700296 for (int i = 0; i < mProvidersByClassPerUser.size(); i++) {
297 HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(i);
Dianne Hackborn390517b2013-05-30 15:03:32 -0700298 needSep |= dumpProvidersByClassLocked(pw, dumpAll, dumpPackage,
299 " Published user " + mProvidersByClassPerUser.keyAt(i)
300 + " content providers (by class):", needSep, map);
Amith Yamasani742a6712011-05-04 14:49:28 -0700301 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700302
303 if (dumpAll) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700304 needSep |= dumpProvidersByNameLocked(pw, dumpPackage,
305 " Single-user authority to provider mappings:", needSep, mSingletonByName);
Amith Yamasani742a6712011-05-04 14:49:28 -0700306
307 for (int i = 0; i < mProvidersByNamePerUser.size(); i++) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700308 needSep |= dumpProvidersByNameLocked(pw, dumpPackage,
309 " User " + mProvidersByNamePerUser.keyAt(i)
310 + " authority to provider mappings:", needSep,
311 mProvidersByNamePerUser.valueAt(i));
Amith Yamasani742a6712011-05-04 14:49:28 -0700312 }
313 }
Dianne Hackborn390517b2013-05-30 15:03:32 -0700314 return needSep;
Amith Yamasani742a6712011-05-04 14:49:28 -0700315 }
Marco Nelissende7408c2012-02-08 14:57:38 -0800316
317 protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
318 int opti, boolean dumpAll) {
Dianne Hackborn2d1b3782012-09-09 17:49:39 -0700319 ArrayList<ContentProviderRecord> allProviders = new ArrayList<ContentProviderRecord>();
Marco Nelissende7408c2012-02-08 14:57:38 -0800320 ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
321
Dianne Hackborn2d1b3782012-09-09 17:49:39 -0700322 synchronized (mAm) {
323 allProviders.addAll(mSingletonByClass.values());
324 for (int i=0; i<mProvidersByClassPerUser.size(); i++) {
325 allProviders.addAll(mProvidersByClassPerUser.valueAt(i).values());
Marco Nelissende7408c2012-02-08 14:57:38 -0800326 }
327
Dianne Hackborn2d1b3782012-09-09 17:49:39 -0700328 if ("all".equals(name)) {
329 providers.addAll(allProviders);
330 } else {
331 ComponentName componentName = name != null
332 ? ComponentName.unflattenFromString(name) : null;
333 int objectId = 0;
334 if (componentName == null) {
335 // Not a '/' separated full component name; maybe an object ID?
336 try {
337 objectId = Integer.parseInt(name, 16);
338 name = null;
339 componentName = null;
340 } catch (RuntimeException e) {
341 }
342 }
343
344 for (int i=0; i<allProviders.size(); i++) {
345 ContentProviderRecord r1 = allProviders.get(i);
Marco Nelissende7408c2012-02-08 14:57:38 -0800346 if (componentName != null) {
347 if (r1.name.equals(componentName)) {
348 providers.add(r1);
349 }
350 } else if (name != null) {
351 if (r1.name.flattenToString().contains(name)) {
352 providers.add(r1);
353 }
354 } else if (System.identityHashCode(r1) == objectId) {
355 providers.add(r1);
356 }
357 }
358 }
359 }
360
361 if (providers.size() <= 0) {
362 return false;
363 }
364
365 boolean needSep = false;
366 for (int i=0; i<providers.size(); i++) {
367 if (needSep) {
368 pw.println();
369 }
370 needSep = true;
371 dumpProvider("", fd, pw, providers.get(i), args, dumpAll);
372 }
373 return true;
374 }
375
376 /**
377 * Invokes IApplicationThread.dumpProvider() on the thread of the specified provider if
378 * there is a thread associated with the provider.
379 */
380 private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw,
381 final ContentProviderRecord r, String[] args, boolean dumpAll) {
382 String innerPrefix = prefix + " ";
Dianne Hackborn2d1b3782012-09-09 17:49:39 -0700383 synchronized (mAm) {
Marco Nelissende7408c2012-02-08 14:57:38 -0800384 pw.print(prefix); pw.print("PROVIDER ");
385 pw.print(r);
386 pw.print(" pid=");
387 if (r.proc != null) pw.println(r.proc.pid);
388 else pw.println("(not running)");
389 if (dumpAll) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700390 r.dump(pw, innerPrefix, true);
Marco Nelissende7408c2012-02-08 14:57:38 -0800391 }
392 }
393 if (r.proc != null && r.proc.thread != null) {
394 pw.println(" Client:");
395 pw.flush();
396 try {
397 TransferPipe tp = new TransferPipe();
398 try {
399 r.proc.thread.dumpProvider(
400 tp.getWriteFd().getFileDescriptor(), r.provider.asBinder(), args);
401 tp.setBufferPrefix(" ");
402 // Short timeout, since blocking here can
403 // deadlock with the application.
404 tp.go(fd, 2000);
405 } finally {
406 tp.kill();
407 }
408 } catch (IOException ex) {
409 pw.println(" Failure while dumping the provider: " + ex);
410 } catch (RemoteException ex) {
411 pw.println(" Got a RemoteException while dumping the service");
412 }
413 }
414 }
Amith Yamasani742a6712011-05-04 14:49:28 -0700415}