blob: 222449085702e5d09eca54796ef1fbfc7bca1566 [file] [log] [blame]
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001/*
2 * Copyright (C) 2010 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 android.app;
18
19import com.android.internal.util.ArrayUtils;
20
21import android.content.BroadcastReceiver;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.IIntentReceiver;
25import android.content.Intent;
26import android.content.ServiceConnection;
27import android.content.pm.ApplicationInfo;
28import android.content.pm.IPackageManager;
29import android.content.pm.PackageManager;
30import android.content.res.AssetManager;
31import android.content.res.CompatibilityInfo;
32import android.content.res.Resources;
33import android.os.Bundle;
34import android.os.Handler;
35import android.os.IBinder;
36import android.os.Process;
37import android.os.RemoteException;
Brad Fitzpatrick624d50f2010-11-09 14:25:12 -080038import android.os.StrictMode;
Dianne Hackborn1ded0b12012-04-26 14:14:50 -070039import android.os.Trace;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070040import android.os.UserHandle;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070041import android.util.AndroidRuntimeException;
42import android.util.Slog;
Dianne Hackborn5fd21692011-06-07 14:09:47 -070043import android.view.CompatibilityInfoHolder;
Jeff Browna492c3a2012-08-23 19:48:44 -070044import android.view.Display;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070045
46import java.io.File;
47import java.io.IOException;
48import java.io.InputStream;
49import java.lang.ref.WeakReference;
50import java.net.URL;
51import java.util.Enumeration;
52import java.util.HashMap;
53import java.util.Iterator;
54
55final class IntentReceiverLeaked extends AndroidRuntimeException {
56 public IntentReceiverLeaked(String msg) {
57 super(msg);
58 }
59}
60
61final class ServiceConnectionLeaked extends AndroidRuntimeException {
62 public ServiceConnectionLeaked(String msg) {
63 super(msg);
64 }
65}
66
67/**
68 * Local state maintained about a currently loaded .apk.
69 * @hide
70 */
Dianne Hackborn5fd21692011-06-07 14:09:47 -070071public final class LoadedApk {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070072
Amith Yamasani742a6712011-05-04 14:49:28 -070073 private static final String TAG = "LoadedApk";
74
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070075 private final ActivityThread mActivityThread;
76 private final ApplicationInfo mApplicationInfo;
77 final String mPackageName;
78 private final String mAppDir;
79 private final String mResDir;
80 private final String[] mSharedLibraries;
81 private final String mDataDir;
Kenny Root85387d72010-08-26 10:13:11 -070082 private final String mLibDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070083 private final File mDataDirFile;
84 private final ClassLoader mBaseClassLoader;
85 private final boolean mSecurityViolation;
86 private final boolean mIncludeCode;
Dianne Hackborn5fd21692011-06-07 14:09:47 -070087 public final CompatibilityInfoHolder mCompatibilityInfo = new CompatibilityInfoHolder();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070088 Resources mResources;
89 private ClassLoader mClassLoader;
90 private Application mApplication;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070091
92 private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers
93 = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
94 private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
95 = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
96 private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
97 = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
98 private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
99 = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
100
101 int mClientCount = 0;
102
103 Application getApplication() {
104 return mApplication;
105 }
106
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700107 /**
108 * Create information about a new .apk
109 *
110 * NOTE: This constructor is called with ActivityThread's lock held,
111 * so MUST NOT call back out to the activity manager.
112 */
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700113 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400114 CompatibilityInfo compatInfo,
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700115 ActivityThread mainThread, ClassLoader baseLoader,
116 boolean securityViolation, boolean includeCode) {
117 mActivityThread = activityThread;
118 mApplicationInfo = aInfo;
119 mPackageName = aInfo.packageName;
120 mAppDir = aInfo.sourceDir;
Amith Yamasani742a6712011-05-04 14:49:28 -0700121 final int myUid = Process.myUid();
122 mResDir = aInfo.uid == myUid ? aInfo.sourceDir
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700123 : aInfo.publicSourceDir;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700124 if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
125 aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
Amith Yamasani742a6712011-05-04 14:49:28 -0700126 mPackageName);
127 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700128 mSharedLibraries = aInfo.sharedLibraryFiles;
129 mDataDir = aInfo.dataDir;
130 mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
Kenny Root85387d72010-08-26 10:13:11 -0700131 mLibDir = aInfo.nativeLibraryDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700132 mBaseClassLoader = baseLoader;
133 mSecurityViolation = securityViolation;
134 mIncludeCode = includeCode;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700135 mCompatibilityInfo.set(compatInfo);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700136
137 if (mAppDir == null) {
138 if (ActivityThread.mSystemContext == null) {
139 ActivityThread.mSystemContext =
140 ContextImpl.createSystemContext(mainThread);
141 ActivityThread.mSystemContext.getResources().updateConfiguration(
142 mainThread.getConfiguration(),
Jeff Browna492c3a2012-08-23 19:48:44 -0700143 mainThread.getDisplayMetricsLocked(
144 Display.DEFAULT_DISPLAY, compatInfo),
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400145 compatInfo);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700146 //Slog.i(TAG, "Created system resources "
147 // + mSystemContext.getResources() + ": "
148 // + mSystemContext.getResources().getConfiguration());
149 }
150 mClassLoader = ActivityThread.mSystemContext.getClassLoader();
151 mResources = ActivityThread.mSystemContext.getResources();
152 }
153 }
154
155 public LoadedApk(ActivityThread activityThread, String name,
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400156 Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700157 mActivityThread = activityThread;
158 mApplicationInfo = info != null ? info : new ApplicationInfo();
159 mApplicationInfo.packageName = name;
160 mPackageName = name;
161 mAppDir = null;
162 mResDir = null;
163 mSharedLibraries = null;
164 mDataDir = null;
165 mDataDirFile = null;
Kenny Root85387d72010-08-26 10:13:11 -0700166 mLibDir = null;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700167 mBaseClassLoader = null;
168 mSecurityViolation = false;
169 mIncludeCode = true;
170 mClassLoader = systemContext.getClassLoader();
171 mResources = systemContext.getResources();
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700172 mCompatibilityInfo.set(compatInfo);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700173 }
174
175 public String getPackageName() {
176 return mPackageName;
177 }
178
179 public ApplicationInfo getApplicationInfo() {
180 return mApplicationInfo;
181 }
182
183 public boolean isSecurityViolation() {
184 return mSecurityViolation;
185 }
186
187 /**
188 * Gets the array of shared libraries that are listed as
189 * used by the given package.
190 *
191 * @param packageName the name of the package (note: not its
192 * file name)
193 * @return null-ok; the array of shared libraries, each one
194 * a fully-qualified path
195 */
196 private static String[] getLibrariesFor(String packageName) {
197 ApplicationInfo ai = null;
198 try {
199 ai = ActivityThread.getPackageManager().getApplicationInfo(packageName,
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700200 PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId());
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700201 } catch (RemoteException e) {
202 throw new AssertionError(e);
203 }
204
205 if (ai == null) {
206 return null;
207 }
208
209 return ai.sharedLibraryFiles;
210 }
211
212 /**
213 * Combines two arrays (of library names) such that they are
214 * concatenated in order but are devoid of duplicates. The
215 * result is a single string with the names of the libraries
216 * separated by colons, or <code>null</code> if both lists
217 * were <code>null</code> or empty.
218 *
219 * @param list1 null-ok; the first list
220 * @param list2 null-ok; the second list
221 * @return null-ok; the combination
222 */
223 private static String combineLibs(String[] list1, String[] list2) {
224 StringBuilder result = new StringBuilder(300);
225 boolean first = true;
226
227 if (list1 != null) {
228 for (String s : list1) {
229 if (first) {
230 first = false;
231 } else {
232 result.append(':');
233 }
234 result.append(s);
235 }
236 }
237
238 // Only need to check for duplicates if list1 was non-empty.
239 boolean dupCheck = !first;
240
241 if (list2 != null) {
242 for (String s : list2) {
243 if (dupCheck && ArrayUtils.contains(list1, s)) {
244 continue;
245 }
246
247 if (first) {
248 first = false;
249 } else {
250 result.append(':');
251 }
252 result.append(s);
253 }
254 }
255
256 return result.toString();
257 }
258
259 public ClassLoader getClassLoader() {
260 synchronized (this) {
261 if (mClassLoader != null) {
262 return mClassLoader;
263 }
264
265 if (mIncludeCode && !mPackageName.equals("android")) {
266 String zip = mAppDir;
Brian Carlstromd893a892012-04-01 21:30:26 -0700267 String libraryPath = mLibDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700268
269 /*
270 * The following is a bit of a hack to inject
271 * instrumentation into the system: If the app
272 * being started matches one of the instrumentation names,
273 * then we combine both the "instrumentation" and
274 * "instrumented" app into the path, along with the
275 * concatenation of both apps' shared library lists.
276 */
277
278 String instrumentationAppDir =
279 mActivityThread.mInstrumentationAppDir;
Brian Carlstromd893a892012-04-01 21:30:26 -0700280 String instrumentationAppLibraryDir =
281 mActivityThread.mInstrumentationAppLibraryDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700282 String instrumentationAppPackage =
283 mActivityThread.mInstrumentationAppPackage;
284 String instrumentedAppDir =
285 mActivityThread.mInstrumentedAppDir;
Brian Carlstromd893a892012-04-01 21:30:26 -0700286 String instrumentedAppLibraryDir =
287 mActivityThread.mInstrumentedAppLibraryDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700288 String[] instrumentationLibs = null;
289
290 if (mAppDir.equals(instrumentationAppDir)
291 || mAppDir.equals(instrumentedAppDir)) {
292 zip = instrumentationAppDir + ":" + instrumentedAppDir;
Brian Carlstromd893a892012-04-01 21:30:26 -0700293 libraryPath = instrumentationAppLibraryDir + ":" + instrumentedAppLibraryDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700294 if (! instrumentedAppDir.equals(instrumentationAppDir)) {
295 instrumentationLibs =
296 getLibrariesFor(instrumentationAppPackage);
297 }
298 }
299
300 if ((mSharedLibraries != null) ||
301 (instrumentationLibs != null)) {
302 zip =
303 combineLibs(mSharedLibraries, instrumentationLibs)
304 + ':' + zip;
305 }
306
307 /*
308 * With all the combination done (if necessary, actually
309 * create the class loader.
310 */
311
Kenny Root85387d72010-08-26 10:13:11 -0700312 if (ActivityThread.localLOGV)
Brian Carlstromd893a892012-04-01 21:30:26 -0700313 Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + libraryPath);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700314
Brad Fitzpatrick624d50f2010-11-09 14:25:12 -0800315 // Temporarily disable logging of disk reads on the Looper thread
316 // as this is early and necessary.
317 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
318
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700319 mClassLoader =
320 ApplicationLoaders.getDefault().getClassLoader(
Brian Carlstromd893a892012-04-01 21:30:26 -0700321 zip, libraryPath, mBaseClassLoader);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700322 initializeJavaContextClassLoader();
Brad Fitzpatrick624d50f2010-11-09 14:25:12 -0800323
324 StrictMode.setThreadPolicy(oldPolicy);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700325 } else {
326 if (mBaseClassLoader == null) {
327 mClassLoader = ClassLoader.getSystemClassLoader();
328 } else {
329 mClassLoader = mBaseClassLoader;
330 }
331 }
332 return mClassLoader;
333 }
334 }
335
336 /**
337 * Setup value for Thread.getContextClassLoader(). If the
338 * package will not run in in a VM with other packages, we set
339 * the Java context ClassLoader to the
340 * PackageInfo.getClassLoader value. However, if this VM can
341 * contain multiple packages, we intead set the Java context
342 * ClassLoader to a proxy that will warn about the use of Java
343 * context ClassLoaders and then fall through to use the
344 * system ClassLoader.
345 *
346 * <p> Note that this is similar to but not the same as the
347 * android.content.Context.getClassLoader(). While both
348 * context class loaders are typically set to the
349 * PathClassLoader used to load the package archive in the
350 * single application per VM case, a single Android process
351 * may contain several Contexts executing on one thread with
352 * their own logical ClassLoaders while the Java context
353 * ClassLoader is a thread local. This is why in the case when
354 * we have multiple packages per VM we do not set the Java
355 * context ClassLoader to an arbitrary but instead warn the
356 * user to set their own if we detect that they are using a
357 * Java library that expects it to be set.
358 */
359 private void initializeJavaContextClassLoader() {
360 IPackageManager pm = ActivityThread.getPackageManager();
361 android.content.pm.PackageInfo pi;
362 try {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700363 pi = pm.getPackageInfo(mPackageName, 0, UserHandle.myUserId());
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700364 } catch (RemoteException e) {
Dianne Hackborn208d9372013-02-25 13:17:54 -0800365 throw new IllegalStateException("Unable to get package info for "
366 + mPackageName + "; is system dying?", e);
367 }
368 if (pi == null) {
369 throw new IllegalStateException("Unable to get package info for "
370 + mPackageName + "; is package not installed?");
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700371 }
372 /*
373 * Two possible indications that this package could be
374 * sharing its virtual machine with other packages:
375 *
376 * 1.) the sharedUserId attribute is set in the manifest,
377 * indicating a request to share a VM with other
378 * packages with the same sharedUserId.
379 *
380 * 2.) the application element of the manifest has an
381 * attribute specifying a non-default process name,
382 * indicating the desire to run in another packages VM.
383 */
384 boolean sharedUserIdSet = (pi.sharedUserId != null);
385 boolean processNameNotDefault =
386 (pi.applicationInfo != null &&
387 !mPackageName.equals(pi.applicationInfo.processName));
388 boolean sharable = (sharedUserIdSet || processNameNotDefault);
389 ClassLoader contextClassLoader =
390 (sharable)
391 ? new WarningContextClassLoader()
392 : mClassLoader;
393 Thread.currentThread().setContextClassLoader(contextClassLoader);
394 }
395
396 private static class WarningContextClassLoader extends ClassLoader {
397
398 private static boolean warned = false;
399
400 private void warn(String methodName) {
401 if (warned) {
402 return;
403 }
404 warned = true;
405 Thread.currentThread().setContextClassLoader(getParent());
406 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " +
407 "The class loader returned by " +
408 "Thread.getContextClassLoader() may fail for processes " +
409 "that host multiple applications. You should explicitly " +
410 "specify a context class loader. For example: " +
411 "Thread.setContextClassLoader(getClass().getClassLoader());");
412 }
413
414 @Override public URL getResource(String resName) {
415 warn("getResource");
416 return getParent().getResource(resName);
417 }
418
419 @Override public Enumeration<URL> getResources(String resName) throws IOException {
420 warn("getResources");
421 return getParent().getResources(resName);
422 }
423
424 @Override public InputStream getResourceAsStream(String resName) {
425 warn("getResourceAsStream");
426 return getParent().getResourceAsStream(resName);
427 }
428
429 @Override public Class<?> loadClass(String className) throws ClassNotFoundException {
430 warn("loadClass");
431 return getParent().loadClass(className);
432 }
433
434 @Override public void setClassAssertionStatus(String cname, boolean enable) {
435 warn("setClassAssertionStatus");
436 getParent().setClassAssertionStatus(cname, enable);
437 }
438
439 @Override public void setPackageAssertionStatus(String pname, boolean enable) {
440 warn("setPackageAssertionStatus");
441 getParent().setPackageAssertionStatus(pname, enable);
442 }
443
444 @Override public void setDefaultAssertionStatus(boolean enable) {
445 warn("setDefaultAssertionStatus");
446 getParent().setDefaultAssertionStatus(enable);
447 }
448
449 @Override public void clearAssertionStatus() {
450 warn("clearAssertionStatus");
451 getParent().clearAssertionStatus();
452 }
453 }
454
455 public String getAppDir() {
456 return mAppDir;
457 }
458
Brian Carlstromd893a892012-04-01 21:30:26 -0700459 public String getLibDir() {
460 return mLibDir;
461 }
462
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700463 public String getResDir() {
464 return mResDir;
465 }
466
467 public String getDataDir() {
468 return mDataDir;
469 }
470
471 public File getDataDirFile() {
472 return mDataDirFile;
473 }
474
475 public AssetManager getAssets(ActivityThread mainThread) {
476 return getResources(mainThread).getAssets();
477 }
478
479 public Resources getResources(ActivityThread mainThread) {
480 if (mResources == null) {
Jeff Browna492c3a2012-08-23 19:48:44 -0700481 mResources = mainThread.getTopLevelResources(mResDir,
482 Display.DEFAULT_DISPLAY, null, this);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700483 }
484 return mResources;
485 }
486
487 public Application makeApplication(boolean forceDefaultAppClass,
488 Instrumentation instrumentation) {
489 if (mApplication != null) {
490 return mApplication;
491 }
492
493 Application app = null;
494
495 String appClass = mApplicationInfo.className;
496 if (forceDefaultAppClass || (appClass == null)) {
497 appClass = "android.app.Application";
498 }
499
500 try {
501 java.lang.ClassLoader cl = getClassLoader();
502 ContextImpl appContext = new ContextImpl();
503 appContext.init(this, null, mActivityThread);
504 app = mActivityThread.mInstrumentation.newApplication(
505 cl, appClass, appContext);
506 appContext.setOuterContext(app);
507 } catch (Exception e) {
508 if (!mActivityThread.mInstrumentation.onException(app, e)) {
509 throw new RuntimeException(
510 "Unable to instantiate application " + appClass
511 + ": " + e.toString(), e);
512 }
513 }
514 mActivityThread.mAllApplications.add(app);
515 mApplication = app;
516
517 if (instrumentation != null) {
518 try {
519 instrumentation.callApplicationOnCreate(app);
520 } catch (Exception e) {
521 if (!instrumentation.onException(app, e)) {
522 throw new RuntimeException(
523 "Unable to create application " + app.getClass().getName()
524 + ": " + e.toString(), e);
525 }
526 }
527 }
528
529 return app;
530 }
531
532 public void removeContextRegistrations(Context context,
533 String who, String what) {
Jeff Sharkeyd7026f12012-03-01 20:50:32 -0800534 final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700535 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
536 mReceivers.remove(context);
537 if (rmap != null) {
538 Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator();
539 while (it.hasNext()) {
540 LoadedApk.ReceiverDispatcher rd = it.next();
541 IntentReceiverLeaked leak = new IntentReceiverLeaked(
542 what + " " + who + " has leaked IntentReceiver "
543 + rd.getIntentReceiver() + " that was " +
544 "originally registered here. Are you missing a " +
545 "call to unregisterReceiver()?");
546 leak.setStackTrace(rd.getLocation().getStackTrace());
547 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
Jeff Sharkeyd7026f12012-03-01 20:50:32 -0800548 if (reportRegistrationLeaks) {
549 StrictMode.onIntentReceiverLeaked(leak);
550 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700551 try {
552 ActivityManagerNative.getDefault().unregisterReceiver(
553 rd.getIIntentReceiver());
554 } catch (RemoteException e) {
555 // system crashed, nothing we can do
556 }
557 }
558 }
559 mUnregisteredReceivers.remove(context);
560 //Slog.i(TAG, "Receiver registrations: " + mReceivers);
561 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
562 mServices.remove(context);
563 if (smap != null) {
564 Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator();
565 while (it.hasNext()) {
566 LoadedApk.ServiceDispatcher sd = it.next();
567 ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
568 what + " " + who + " has leaked ServiceConnection "
569 + sd.getServiceConnection() + " that was originally bound here");
570 leak.setStackTrace(sd.getLocation().getStackTrace());
571 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
Jeff Sharkeyd7026f12012-03-01 20:50:32 -0800572 if (reportRegistrationLeaks) {
573 StrictMode.onServiceConnectionLeaked(leak);
574 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700575 try {
576 ActivityManagerNative.getDefault().unbindService(
577 sd.getIServiceConnection());
578 } catch (RemoteException e) {
579 // system crashed, nothing we can do
580 }
581 sd.doForget();
582 }
583 }
584 mUnboundServices.remove(context);
585 //Slog.i(TAG, "Service registrations: " + mServices);
586 }
587
588 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
589 Context context, Handler handler,
590 Instrumentation instrumentation, boolean registered) {
591 synchronized (mReceivers) {
592 LoadedApk.ReceiverDispatcher rd = null;
593 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
594 if (registered) {
595 map = mReceivers.get(context);
596 if (map != null) {
597 rd = map.get(r);
598 }
599 }
600 if (rd == null) {
601 rd = new ReceiverDispatcher(r, context, handler,
602 instrumentation, registered);
603 if (registered) {
604 if (map == null) {
605 map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
606 mReceivers.put(context, map);
607 }
608 map.put(r, rd);
609 }
610 } else {
611 rd.validate(context, handler);
612 }
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800613 rd.mForgotten = false;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700614 return rd.getIIntentReceiver();
615 }
616 }
617
618 public IIntentReceiver forgetReceiverDispatcher(Context context,
619 BroadcastReceiver r) {
620 synchronized (mReceivers) {
621 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
622 LoadedApk.ReceiverDispatcher rd = null;
623 if (map != null) {
624 rd = map.get(r);
625 if (rd != null) {
626 map.remove(r);
627 if (map.size() == 0) {
628 mReceivers.remove(context);
629 }
630 if (r.getDebugUnregister()) {
631 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
632 = mUnregisteredReceivers.get(context);
633 if (holder == null) {
634 holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
635 mUnregisteredReceivers.put(context, holder);
636 }
637 RuntimeException ex = new IllegalArgumentException(
638 "Originally unregistered here:");
639 ex.fillInStackTrace();
640 rd.setUnregisterLocation(ex);
641 holder.put(r, rd);
642 }
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800643 rd.mForgotten = true;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700644 return rd.getIIntentReceiver();
645 }
646 }
647 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
648 = mUnregisteredReceivers.get(context);
649 if (holder != null) {
650 rd = holder.get(r);
651 if (rd != null) {
652 RuntimeException ex = rd.getUnregisterLocation();
653 throw new IllegalArgumentException(
654 "Unregistering Receiver " + r
655 + " that was already unregistered", ex);
656 }
657 }
658 if (context == null) {
659 throw new IllegalStateException("Unbinding Receiver " + r
660 + " from Context that is no longer in use: " + context);
661 } else {
662 throw new IllegalArgumentException("Receiver not registered: " + r);
663 }
664
665 }
666 }
667
668 static final class ReceiverDispatcher {
669
670 final static class InnerReceiver extends IIntentReceiver.Stub {
671 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
672 final LoadedApk.ReceiverDispatcher mStrongRef;
673
674 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
675 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
676 mStrongRef = strong ? rd : null;
677 }
Dianne Hackborn20e80982012-08-31 19:00:44 -0700678 public void performReceive(Intent intent, int resultCode, String data,
679 Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700680 LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
681 if (ActivityThread.DEBUG_BROADCAST) {
682 int seq = intent.getIntExtra("seq", -1);
683 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
684 + " to " + (rd != null ? rd.mReceiver : null));
685 }
686 if (rd != null) {
687 rd.performReceive(intent, resultCode, data, extras,
Dianne Hackborn20e80982012-08-31 19:00:44 -0700688 ordered, sticky, sendingUser);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700689 } else {
690 // The activity manager dispatched a broadcast to a registered
691 // receiver in this process, but before it could be delivered the
692 // receiver was unregistered. Acknowledge the broadcast on its
693 // behalf so that the system's broadcast sequence can continue.
694 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
695 "Finishing broadcast to unregistered receiver");
696 IActivityManager mgr = ActivityManagerNative.getDefault();
697 try {
Dianne Hackborn9ecebbf2011-09-28 23:19:47 -0400698 if (extras != null) {
699 extras.setAllowFds(false);
700 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700701 mgr.finishReceiver(this, resultCode, data, extras, false);
702 } catch (RemoteException e) {
703 Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
704 }
705 }
706 }
707 }
708
709 final IIntentReceiver.Stub mIIntentReceiver;
710 final BroadcastReceiver mReceiver;
711 final Context mContext;
712 final Handler mActivityThread;
713 final Instrumentation mInstrumentation;
714 final boolean mRegistered;
715 final IntentReceiverLeaked mLocation;
716 RuntimeException mUnregisterLocation;
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800717 boolean mForgotten;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700718
Dianne Hackborne829fef2010-10-26 17:44:01 -0700719 final class Args extends BroadcastReceiver.PendingResult implements Runnable {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700720 private Intent mCurIntent;
Dianne Hackborne829fef2010-10-26 17:44:01 -0700721 private final boolean mOrdered;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700722
Dianne Hackborne829fef2010-10-26 17:44:01 -0700723 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
Dianne Hackborn20e80982012-08-31 19:00:44 -0700724 boolean ordered, boolean sticky, int sendingUser) {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700725 super(resultCode, resultData, resultExtras,
726 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
Dianne Hackborn20e80982012-08-31 19:00:44 -0700727 ordered, sticky, mIIntentReceiver.asBinder(), sendingUser);
Dianne Hackborne829fef2010-10-26 17:44:01 -0700728 mCurIntent = intent;
729 mOrdered = ordered;
730 }
731
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700732 public void run() {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700733 final BroadcastReceiver receiver = mReceiver;
734 final boolean ordered = mOrdered;
735
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700736 if (ActivityThread.DEBUG_BROADCAST) {
737 int seq = mCurIntent.getIntExtra("seq", -1);
738 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
739 + " seq=" + seq + " to " + mReceiver);
740 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
Dianne Hackborne829fef2010-10-26 17:44:01 -0700741 + " mOrderedHint=" + ordered);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700742 }
743
Dianne Hackborne829fef2010-10-26 17:44:01 -0700744 final IActivityManager mgr = ActivityManagerNative.getDefault();
745 final Intent intent = mCurIntent;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700746 mCurIntent = null;
747
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800748 if (receiver == null || mForgotten) {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700749 if (mRegistered && ordered) {
750 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
751 "Finishing null broadcast to " + mReceiver);
752 sendFinished(mgr);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700753 }
754 return;
755 }
756
Dianne Hackborn1ded0b12012-04-26 14:14:50 -0700757 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700758 try {
759 ClassLoader cl = mReceiver.getClass().getClassLoader();
760 intent.setExtrasClassLoader(cl);
Dianne Hackborne829fef2010-10-26 17:44:01 -0700761 setExtrasClassLoader(cl);
762 receiver.setPendingResult(this);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700763 receiver.onReceive(mContext, intent);
764 } catch (Exception e) {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700765 if (mRegistered && ordered) {
766 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
767 "Finishing failed broadcast to " + mReceiver);
768 sendFinished(mgr);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700769 }
770 if (mInstrumentation == null ||
771 !mInstrumentation.onException(mReceiver, e)) {
Dianne Hackborn1ded0b12012-04-26 14:14:50 -0700772 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700773 throw new RuntimeException(
774 "Error receiving broadcast " + intent
775 + " in " + mReceiver, e);
776 }
777 }
Dianne Hackborne829fef2010-10-26 17:44:01 -0700778
779 if (receiver.getPendingResult() != null) {
780 finish();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700781 }
Dianne Hackborn1ded0b12012-04-26 14:14:50 -0700782 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700783 }
784 }
785
786 ReceiverDispatcher(BroadcastReceiver receiver, Context context,
787 Handler activityThread, Instrumentation instrumentation,
788 boolean registered) {
789 if (activityThread == null) {
790 throw new NullPointerException("Handler must not be null");
791 }
792
793 mIIntentReceiver = new InnerReceiver(this, !registered);
794 mReceiver = receiver;
795 mContext = context;
796 mActivityThread = activityThread;
797 mInstrumentation = instrumentation;
798 mRegistered = registered;
799 mLocation = new IntentReceiverLeaked(null);
800 mLocation.fillInStackTrace();
801 }
802
803 void validate(Context context, Handler activityThread) {
804 if (mContext != context) {
805 throw new IllegalStateException(
806 "Receiver " + mReceiver +
807 " registered with differing Context (was " +
808 mContext + " now " + context + ")");
809 }
810 if (mActivityThread != activityThread) {
811 throw new IllegalStateException(
812 "Receiver " + mReceiver +
813 " registered with differing handler (was " +
814 mActivityThread + " now " + activityThread + ")");
815 }
816 }
817
818 IntentReceiverLeaked getLocation() {
819 return mLocation;
820 }
821
822 BroadcastReceiver getIntentReceiver() {
823 return mReceiver;
824 }
825
826 IIntentReceiver getIIntentReceiver() {
827 return mIIntentReceiver;
828 }
829
830 void setUnregisterLocation(RuntimeException ex) {
831 mUnregisterLocation = ex;
832 }
833
834 RuntimeException getUnregisterLocation() {
835 return mUnregisterLocation;
836 }
837
Dianne Hackborn20e80982012-08-31 19:00:44 -0700838 public void performReceive(Intent intent, int resultCode, String data,
839 Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700840 if (ActivityThread.DEBUG_BROADCAST) {
841 int seq = intent.getIntExtra("seq", -1);
842 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
843 + " to " + mReceiver);
844 }
Dianne Hackborn20e80982012-08-31 19:00:44 -0700845 Args args = new Args(intent, resultCode, data, extras, ordered,
846 sticky, sendingUser);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700847 if (!mActivityThread.post(args)) {
848 if (mRegistered && ordered) {
849 IActivityManager mgr = ActivityManagerNative.getDefault();
Dianne Hackborne829fef2010-10-26 17:44:01 -0700850 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
851 "Finishing sync broadcast to " + mReceiver);
852 args.sendFinished(mgr);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700853 }
854 }
855 }
856
857 }
858
859 public final IServiceConnection getServiceDispatcher(ServiceConnection c,
860 Context context, Handler handler, int flags) {
861 synchronized (mServices) {
862 LoadedApk.ServiceDispatcher sd = null;
863 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
864 if (map != null) {
865 sd = map.get(c);
866 }
867 if (sd == null) {
868 sd = new ServiceDispatcher(c, context, handler, flags);
869 if (map == null) {
870 map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
871 mServices.put(context, map);
872 }
873 map.put(c, sd);
874 } else {
875 sd.validate(context, handler);
876 }
877 return sd.getIServiceConnection();
878 }
879 }
880
881 public final IServiceConnection forgetServiceDispatcher(Context context,
882 ServiceConnection c) {
883 synchronized (mServices) {
884 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
885 = mServices.get(context);
886 LoadedApk.ServiceDispatcher sd = null;
887 if (map != null) {
888 sd = map.get(c);
889 if (sd != null) {
890 map.remove(c);
891 sd.doForget();
892 if (map.size() == 0) {
893 mServices.remove(context);
894 }
895 if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
896 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
897 = mUnboundServices.get(context);
898 if (holder == null) {
899 holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
900 mUnboundServices.put(context, holder);
901 }
902 RuntimeException ex = new IllegalArgumentException(
903 "Originally unbound here:");
904 ex.fillInStackTrace();
905 sd.setUnbindLocation(ex);
906 holder.put(c, sd);
907 }
908 return sd.getIServiceConnection();
909 }
910 }
911 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
912 = mUnboundServices.get(context);
913 if (holder != null) {
914 sd = holder.get(c);
915 if (sd != null) {
916 RuntimeException ex = sd.getUnbindLocation();
917 throw new IllegalArgumentException(
918 "Unbinding Service " + c
919 + " that was already unbound", ex);
920 }
921 }
922 if (context == null) {
923 throw new IllegalStateException("Unbinding Service " + c
924 + " from Context that is no longer in use: " + context);
925 } else {
926 throw new IllegalArgumentException("Service not registered: " + c);
927 }
928 }
929 }
930
931 static final class ServiceDispatcher {
932 private final ServiceDispatcher.InnerConnection mIServiceConnection;
933 private final ServiceConnection mConnection;
934 private final Context mContext;
935 private final Handler mActivityThread;
936 private final ServiceConnectionLeaked mLocation;
937 private final int mFlags;
938
939 private RuntimeException mUnbindLocation;
940
941 private boolean mDied;
Dianne Hackborn5a6ef732011-11-11 12:31:52 -0800942 private boolean mForgotten;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700943
944 private static class ConnectionInfo {
945 IBinder binder;
946 IBinder.DeathRecipient deathMonitor;
947 }
948
949 private static class InnerConnection extends IServiceConnection.Stub {
950 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
951
952 InnerConnection(LoadedApk.ServiceDispatcher sd) {
953 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
954 }
955
956 public void connected(ComponentName name, IBinder service) throws RemoteException {
957 LoadedApk.ServiceDispatcher sd = mDispatcher.get();
958 if (sd != null) {
959 sd.connected(name, service);
960 }
961 }
962 }
963
964 private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
965 = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
966
967 ServiceDispatcher(ServiceConnection conn,
968 Context context, Handler activityThread, int flags) {
969 mIServiceConnection = new InnerConnection(this);
970 mConnection = conn;
971 mContext = context;
972 mActivityThread = activityThread;
973 mLocation = new ServiceConnectionLeaked(null);
974 mLocation.fillInStackTrace();
975 mFlags = flags;
976 }
977
978 void validate(Context context, Handler activityThread) {
979 if (mContext != context) {
980 throw new RuntimeException(
981 "ServiceConnection " + mConnection +
982 " registered with differing Context (was " +
983 mContext + " now " + context + ")");
984 }
985 if (mActivityThread != activityThread) {
986 throw new RuntimeException(
987 "ServiceConnection " + mConnection +
988 " registered with differing handler (was " +
989 mActivityThread + " now " + activityThread + ")");
990 }
991 }
992
993 void doForget() {
994 synchronized(this) {
995 Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator();
996 while (it.hasNext()) {
997 ServiceDispatcher.ConnectionInfo ci = it.next();
998 ci.binder.unlinkToDeath(ci.deathMonitor, 0);
999 }
1000 mActiveConnections.clear();
Dianne Hackborn5a6ef732011-11-11 12:31:52 -08001001 mForgotten = true;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001002 }
1003 }
1004
1005 ServiceConnectionLeaked getLocation() {
1006 return mLocation;
1007 }
1008
1009 ServiceConnection getServiceConnection() {
1010 return mConnection;
1011 }
1012
1013 IServiceConnection getIServiceConnection() {
1014 return mIServiceConnection;
1015 }
1016
1017 int getFlags() {
1018 return mFlags;
1019 }
1020
1021 void setUnbindLocation(RuntimeException ex) {
1022 mUnbindLocation = ex;
1023 }
1024
1025 RuntimeException getUnbindLocation() {
1026 return mUnbindLocation;
1027 }
1028
1029 public void connected(ComponentName name, IBinder service) {
1030 if (mActivityThread != null) {
1031 mActivityThread.post(new RunConnection(name, service, 0));
1032 } else {
1033 doConnected(name, service);
1034 }
1035 }
1036
1037 public void death(ComponentName name, IBinder service) {
1038 ServiceDispatcher.ConnectionInfo old;
1039
1040 synchronized (this) {
1041 mDied = true;
1042 old = mActiveConnections.remove(name);
1043 if (old == null || old.binder != service) {
1044 // Death for someone different than who we last
1045 // reported... just ignore it.
1046 return;
1047 }
1048 old.binder.unlinkToDeath(old.deathMonitor, 0);
1049 }
1050
1051 if (mActivityThread != null) {
1052 mActivityThread.post(new RunConnection(name, service, 1));
1053 } else {
1054 doDeath(name, service);
1055 }
1056 }
1057
1058 public void doConnected(ComponentName name, IBinder service) {
1059 ServiceDispatcher.ConnectionInfo old;
1060 ServiceDispatcher.ConnectionInfo info;
1061
1062 synchronized (this) {
Dianne Hackborn5a6ef732011-11-11 12:31:52 -08001063 if (mForgotten) {
1064 // We unbound before receiving the connection; ignore
1065 // any connection received.
1066 return;
1067 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001068 old = mActiveConnections.get(name);
1069 if (old != null && old.binder == service) {
1070 // Huh, already have this one. Oh well!
1071 return;
1072 }
1073
1074 if (service != null) {
1075 // A new service is being connected... set it all up.
1076 mDied = false;
1077 info = new ConnectionInfo();
1078 info.binder = service;
1079 info.deathMonitor = new DeathMonitor(name, service);
1080 try {
1081 service.linkToDeath(info.deathMonitor, 0);
1082 mActiveConnections.put(name, info);
1083 } catch (RemoteException e) {
1084 // This service was dead before we got it... just
1085 // don't do anything with it.
1086 mActiveConnections.remove(name);
1087 return;
1088 }
1089
1090 } else {
1091 // The named service is being disconnected... clean up.
1092 mActiveConnections.remove(name);
1093 }
1094
1095 if (old != null) {
1096 old.binder.unlinkToDeath(old.deathMonitor, 0);
1097 }
1098 }
1099
1100 // If there was an old service, it is not disconnected.
1101 if (old != null) {
1102 mConnection.onServiceDisconnected(name);
1103 }
1104 // If there is a new service, it is now connected.
1105 if (service != null) {
1106 mConnection.onServiceConnected(name, service);
1107 }
1108 }
1109
1110 public void doDeath(ComponentName name, IBinder service) {
1111 mConnection.onServiceDisconnected(name);
1112 }
1113
1114 private final class RunConnection implements Runnable {
1115 RunConnection(ComponentName name, IBinder service, int command) {
1116 mName = name;
1117 mService = service;
1118 mCommand = command;
1119 }
1120
1121 public void run() {
1122 if (mCommand == 0) {
1123 doConnected(mName, mService);
1124 } else if (mCommand == 1) {
1125 doDeath(mName, mService);
1126 }
1127 }
1128
1129 final ComponentName mName;
1130 final IBinder mService;
1131 final int mCommand;
1132 }
1133
1134 private final class DeathMonitor implements IBinder.DeathRecipient
1135 {
1136 DeathMonitor(ComponentName name, IBinder service) {
1137 mName = name;
1138 mService = service;
1139 }
1140
1141 public void binderDied() {
1142 death(mName, mService);
1143 }
1144
1145 final ComponentName mName;
1146 final IBinder mService;
1147 }
1148 }
1149}