blob: 5307696eb6c3443445b913a6a351078a0b0bf4f7 [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 Hackborn01e4cfc2010-06-24 15:07:24 -070039import android.util.AndroidRuntimeException;
40import android.util.Slog;
41
42import java.io.File;
43import java.io.IOException;
44import java.io.InputStream;
45import java.lang.ref.WeakReference;
46import java.net.URL;
47import java.util.Enumeration;
48import java.util.HashMap;
49import java.util.Iterator;
50
51final class IntentReceiverLeaked extends AndroidRuntimeException {
52 public IntentReceiverLeaked(String msg) {
53 super(msg);
54 }
55}
56
57final class ServiceConnectionLeaked extends AndroidRuntimeException {
58 public ServiceConnectionLeaked(String msg) {
59 super(msg);
60 }
61}
62
63/**
64 * Local state maintained about a currently loaded .apk.
65 * @hide
66 */
67final class LoadedApk {
68
69 private final ActivityThread mActivityThread;
70 private final ApplicationInfo mApplicationInfo;
71 final String mPackageName;
72 private final String mAppDir;
73 private final String mResDir;
74 private final String[] mSharedLibraries;
75 private final String mDataDir;
Kenny Root85387d72010-08-26 10:13:11 -070076 private final String mLibDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070077 private final File mDataDirFile;
78 private final ClassLoader mBaseClassLoader;
79 private final boolean mSecurityViolation;
80 private final boolean mIncludeCode;
81 Resources mResources;
82 private ClassLoader mClassLoader;
83 private Application mApplication;
84 CompatibilityInfo mCompatibilityInfo;
85
86 private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers
87 = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
88 private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
89 = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
90 private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
91 = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
92 private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
93 = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
94
95 int mClientCount = 0;
96
97 Application getApplication() {
98 return mApplication;
99 }
100
101 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400102 CompatibilityInfo compatInfo,
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700103 ActivityThread mainThread, ClassLoader baseLoader,
104 boolean securityViolation, boolean includeCode) {
105 mActivityThread = activityThread;
106 mApplicationInfo = aInfo;
107 mPackageName = aInfo.packageName;
108 mAppDir = aInfo.sourceDir;
109 mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir
110 : aInfo.publicSourceDir;
111 mSharedLibraries = aInfo.sharedLibraryFiles;
112 mDataDir = aInfo.dataDir;
113 mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
Kenny Root85387d72010-08-26 10:13:11 -0700114 mLibDir = aInfo.nativeLibraryDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700115 mBaseClassLoader = baseLoader;
116 mSecurityViolation = securityViolation;
117 mIncludeCode = includeCode;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400118 mCompatibilityInfo = compatInfo;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700119
120 if (mAppDir == null) {
121 if (ActivityThread.mSystemContext == null) {
122 ActivityThread.mSystemContext =
123 ContextImpl.createSystemContext(mainThread);
124 ActivityThread.mSystemContext.getResources().updateConfiguration(
125 mainThread.getConfiguration(),
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400126 mainThread.getDisplayMetricsLocked(false),
127 compatInfo);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700128 //Slog.i(TAG, "Created system resources "
129 // + mSystemContext.getResources() + ": "
130 // + mSystemContext.getResources().getConfiguration());
131 }
132 mClassLoader = ActivityThread.mSystemContext.getClassLoader();
133 mResources = ActivityThread.mSystemContext.getResources();
134 }
135 }
136
137 public LoadedApk(ActivityThread activityThread, String name,
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400138 Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700139 mActivityThread = activityThread;
140 mApplicationInfo = info != null ? info : new ApplicationInfo();
141 mApplicationInfo.packageName = name;
142 mPackageName = name;
143 mAppDir = null;
144 mResDir = null;
145 mSharedLibraries = null;
146 mDataDir = null;
147 mDataDirFile = null;
Kenny Root85387d72010-08-26 10:13:11 -0700148 mLibDir = null;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700149 mBaseClassLoader = null;
150 mSecurityViolation = false;
151 mIncludeCode = true;
152 mClassLoader = systemContext.getClassLoader();
153 mResources = systemContext.getResources();
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400154 mCompatibilityInfo = compatInfo;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700155 }
156
157 public String getPackageName() {
158 return mPackageName;
159 }
160
161 public ApplicationInfo getApplicationInfo() {
162 return mApplicationInfo;
163 }
164
165 public boolean isSecurityViolation() {
166 return mSecurityViolation;
167 }
168
169 /**
170 * Gets the array of shared libraries that are listed as
171 * used by the given package.
172 *
173 * @param packageName the name of the package (note: not its
174 * file name)
175 * @return null-ok; the array of shared libraries, each one
176 * a fully-qualified path
177 */
178 private static String[] getLibrariesFor(String packageName) {
179 ApplicationInfo ai = null;
180 try {
181 ai = ActivityThread.getPackageManager().getApplicationInfo(packageName,
182 PackageManager.GET_SHARED_LIBRARY_FILES);
183 } catch (RemoteException e) {
184 throw new AssertionError(e);
185 }
186
187 if (ai == null) {
188 return null;
189 }
190
191 return ai.sharedLibraryFiles;
192 }
193
194 /**
195 * Combines two arrays (of library names) such that they are
196 * concatenated in order but are devoid of duplicates. The
197 * result is a single string with the names of the libraries
198 * separated by colons, or <code>null</code> if both lists
199 * were <code>null</code> or empty.
200 *
201 * @param list1 null-ok; the first list
202 * @param list2 null-ok; the second list
203 * @return null-ok; the combination
204 */
205 private static String combineLibs(String[] list1, String[] list2) {
206 StringBuilder result = new StringBuilder(300);
207 boolean first = true;
208
209 if (list1 != null) {
210 for (String s : list1) {
211 if (first) {
212 first = false;
213 } else {
214 result.append(':');
215 }
216 result.append(s);
217 }
218 }
219
220 // Only need to check for duplicates if list1 was non-empty.
221 boolean dupCheck = !first;
222
223 if (list2 != null) {
224 for (String s : list2) {
225 if (dupCheck && ArrayUtils.contains(list1, s)) {
226 continue;
227 }
228
229 if (first) {
230 first = false;
231 } else {
232 result.append(':');
233 }
234 result.append(s);
235 }
236 }
237
238 return result.toString();
239 }
240
241 public ClassLoader getClassLoader() {
242 synchronized (this) {
243 if (mClassLoader != null) {
244 return mClassLoader;
245 }
246
247 if (mIncludeCode && !mPackageName.equals("android")) {
248 String zip = mAppDir;
249
250 /*
251 * The following is a bit of a hack to inject
252 * instrumentation into the system: If the app
253 * being started matches one of the instrumentation names,
254 * then we combine both the "instrumentation" and
255 * "instrumented" app into the path, along with the
256 * concatenation of both apps' shared library lists.
257 */
258
259 String instrumentationAppDir =
260 mActivityThread.mInstrumentationAppDir;
261 String instrumentationAppPackage =
262 mActivityThread.mInstrumentationAppPackage;
263 String instrumentedAppDir =
264 mActivityThread.mInstrumentedAppDir;
265 String[] instrumentationLibs = null;
266
267 if (mAppDir.equals(instrumentationAppDir)
268 || mAppDir.equals(instrumentedAppDir)) {
269 zip = instrumentationAppDir + ":" + instrumentedAppDir;
270 if (! instrumentedAppDir.equals(instrumentationAppDir)) {
271 instrumentationLibs =
272 getLibrariesFor(instrumentationAppPackage);
273 }
274 }
275
276 if ((mSharedLibraries != null) ||
277 (instrumentationLibs != null)) {
278 zip =
279 combineLibs(mSharedLibraries, instrumentationLibs)
280 + ':' + zip;
281 }
282
283 /*
284 * With all the combination done (if necessary, actually
285 * create the class loader.
286 */
287
Kenny Root85387d72010-08-26 10:13:11 -0700288 if (ActivityThread.localLOGV)
289 Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + mLibDir);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700290
Brad Fitzpatrick624d50f2010-11-09 14:25:12 -0800291 // Temporarily disable logging of disk reads on the Looper thread
292 // as this is early and necessary.
293 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
294
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700295 mClassLoader =
296 ApplicationLoaders.getDefault().getClassLoader(
Kenny Root85387d72010-08-26 10:13:11 -0700297 zip, mLibDir, mBaseClassLoader);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700298 initializeJavaContextClassLoader();
Brad Fitzpatrick624d50f2010-11-09 14:25:12 -0800299
300 StrictMode.setThreadPolicy(oldPolicy);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700301 } else {
302 if (mBaseClassLoader == null) {
303 mClassLoader = ClassLoader.getSystemClassLoader();
304 } else {
305 mClassLoader = mBaseClassLoader;
306 }
307 }
308 return mClassLoader;
309 }
310 }
311
312 /**
313 * Setup value for Thread.getContextClassLoader(). If the
314 * package will not run in in a VM with other packages, we set
315 * the Java context ClassLoader to the
316 * PackageInfo.getClassLoader value. However, if this VM can
317 * contain multiple packages, we intead set the Java context
318 * ClassLoader to a proxy that will warn about the use of Java
319 * context ClassLoaders and then fall through to use the
320 * system ClassLoader.
321 *
322 * <p> Note that this is similar to but not the same as the
323 * android.content.Context.getClassLoader(). While both
324 * context class loaders are typically set to the
325 * PathClassLoader used to load the package archive in the
326 * single application per VM case, a single Android process
327 * may contain several Contexts executing on one thread with
328 * their own logical ClassLoaders while the Java context
329 * ClassLoader is a thread local. This is why in the case when
330 * we have multiple packages per VM we do not set the Java
331 * context ClassLoader to an arbitrary but instead warn the
332 * user to set their own if we detect that they are using a
333 * Java library that expects it to be set.
334 */
335 private void initializeJavaContextClassLoader() {
336 IPackageManager pm = ActivityThread.getPackageManager();
337 android.content.pm.PackageInfo pi;
338 try {
339 pi = pm.getPackageInfo(mPackageName, 0);
340 } catch (RemoteException e) {
341 throw new AssertionError(e);
342 }
343 /*
344 * Two possible indications that this package could be
345 * sharing its virtual machine with other packages:
346 *
347 * 1.) the sharedUserId attribute is set in the manifest,
348 * indicating a request to share a VM with other
349 * packages with the same sharedUserId.
350 *
351 * 2.) the application element of the manifest has an
352 * attribute specifying a non-default process name,
353 * indicating the desire to run in another packages VM.
354 */
355 boolean sharedUserIdSet = (pi.sharedUserId != null);
356 boolean processNameNotDefault =
357 (pi.applicationInfo != null &&
358 !mPackageName.equals(pi.applicationInfo.processName));
359 boolean sharable = (sharedUserIdSet || processNameNotDefault);
360 ClassLoader contextClassLoader =
361 (sharable)
362 ? new WarningContextClassLoader()
363 : mClassLoader;
364 Thread.currentThread().setContextClassLoader(contextClassLoader);
365 }
366
367 private static class WarningContextClassLoader extends ClassLoader {
368
369 private static boolean warned = false;
370
371 private void warn(String methodName) {
372 if (warned) {
373 return;
374 }
375 warned = true;
376 Thread.currentThread().setContextClassLoader(getParent());
377 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " +
378 "The class loader returned by " +
379 "Thread.getContextClassLoader() may fail for processes " +
380 "that host multiple applications. You should explicitly " +
381 "specify a context class loader. For example: " +
382 "Thread.setContextClassLoader(getClass().getClassLoader());");
383 }
384
385 @Override public URL getResource(String resName) {
386 warn("getResource");
387 return getParent().getResource(resName);
388 }
389
390 @Override public Enumeration<URL> getResources(String resName) throws IOException {
391 warn("getResources");
392 return getParent().getResources(resName);
393 }
394
395 @Override public InputStream getResourceAsStream(String resName) {
396 warn("getResourceAsStream");
397 return getParent().getResourceAsStream(resName);
398 }
399
400 @Override public Class<?> loadClass(String className) throws ClassNotFoundException {
401 warn("loadClass");
402 return getParent().loadClass(className);
403 }
404
405 @Override public void setClassAssertionStatus(String cname, boolean enable) {
406 warn("setClassAssertionStatus");
407 getParent().setClassAssertionStatus(cname, enable);
408 }
409
410 @Override public void setPackageAssertionStatus(String pname, boolean enable) {
411 warn("setPackageAssertionStatus");
412 getParent().setPackageAssertionStatus(pname, enable);
413 }
414
415 @Override public void setDefaultAssertionStatus(boolean enable) {
416 warn("setDefaultAssertionStatus");
417 getParent().setDefaultAssertionStatus(enable);
418 }
419
420 @Override public void clearAssertionStatus() {
421 warn("clearAssertionStatus");
422 getParent().clearAssertionStatus();
423 }
424 }
425
426 public String getAppDir() {
427 return mAppDir;
428 }
429
430 public String getResDir() {
431 return mResDir;
432 }
433
434 public String getDataDir() {
435 return mDataDir;
436 }
437
438 public File getDataDirFile() {
439 return mDataDirFile;
440 }
441
442 public AssetManager getAssets(ActivityThread mainThread) {
443 return getResources(mainThread).getAssets();
444 }
445
446 public Resources getResources(ActivityThread mainThread) {
447 if (mResources == null) {
448 mResources = mainThread.getTopLevelResources(mResDir, this);
449 }
450 return mResources;
451 }
452
453 public Application makeApplication(boolean forceDefaultAppClass,
454 Instrumentation instrumentation) {
455 if (mApplication != null) {
456 return mApplication;
457 }
458
459 Application app = null;
460
461 String appClass = mApplicationInfo.className;
462 if (forceDefaultAppClass || (appClass == null)) {
463 appClass = "android.app.Application";
464 }
465
466 try {
467 java.lang.ClassLoader cl = getClassLoader();
468 ContextImpl appContext = new ContextImpl();
469 appContext.init(this, null, mActivityThread);
470 app = mActivityThread.mInstrumentation.newApplication(
471 cl, appClass, appContext);
472 appContext.setOuterContext(app);
473 } catch (Exception e) {
474 if (!mActivityThread.mInstrumentation.onException(app, e)) {
475 throw new RuntimeException(
476 "Unable to instantiate application " + appClass
477 + ": " + e.toString(), e);
478 }
479 }
480 mActivityThread.mAllApplications.add(app);
481 mApplication = app;
482
483 if (instrumentation != null) {
484 try {
485 instrumentation.callApplicationOnCreate(app);
486 } catch (Exception e) {
487 if (!instrumentation.onException(app, e)) {
488 throw new RuntimeException(
489 "Unable to create application " + app.getClass().getName()
490 + ": " + e.toString(), e);
491 }
492 }
493 }
494
495 return app;
496 }
497
498 public void removeContextRegistrations(Context context,
499 String who, String what) {
500 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
501 mReceivers.remove(context);
502 if (rmap != null) {
503 Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator();
504 while (it.hasNext()) {
505 LoadedApk.ReceiverDispatcher rd = it.next();
506 IntentReceiverLeaked leak = new IntentReceiverLeaked(
507 what + " " + who + " has leaked IntentReceiver "
508 + rd.getIntentReceiver() + " that was " +
509 "originally registered here. Are you missing a " +
510 "call to unregisterReceiver()?");
511 leak.setStackTrace(rd.getLocation().getStackTrace());
512 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
513 try {
514 ActivityManagerNative.getDefault().unregisterReceiver(
515 rd.getIIntentReceiver());
516 } catch (RemoteException e) {
517 // system crashed, nothing we can do
518 }
519 }
520 }
521 mUnregisteredReceivers.remove(context);
522 //Slog.i(TAG, "Receiver registrations: " + mReceivers);
523 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
524 mServices.remove(context);
525 if (smap != null) {
526 Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator();
527 while (it.hasNext()) {
528 LoadedApk.ServiceDispatcher sd = it.next();
529 ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
530 what + " " + who + " has leaked ServiceConnection "
531 + sd.getServiceConnection() + " that was originally bound here");
532 leak.setStackTrace(sd.getLocation().getStackTrace());
533 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
534 try {
535 ActivityManagerNative.getDefault().unbindService(
536 sd.getIServiceConnection());
537 } catch (RemoteException e) {
538 // system crashed, nothing we can do
539 }
540 sd.doForget();
541 }
542 }
543 mUnboundServices.remove(context);
544 //Slog.i(TAG, "Service registrations: " + mServices);
545 }
546
547 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
548 Context context, Handler handler,
549 Instrumentation instrumentation, boolean registered) {
550 synchronized (mReceivers) {
551 LoadedApk.ReceiverDispatcher rd = null;
552 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
553 if (registered) {
554 map = mReceivers.get(context);
555 if (map != null) {
556 rd = map.get(r);
557 }
558 }
559 if (rd == null) {
560 rd = new ReceiverDispatcher(r, context, handler,
561 instrumentation, registered);
562 if (registered) {
563 if (map == null) {
564 map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
565 mReceivers.put(context, map);
566 }
567 map.put(r, rd);
568 }
569 } else {
570 rd.validate(context, handler);
571 }
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800572 rd.mForgotten = false;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700573 return rd.getIIntentReceiver();
574 }
575 }
576
577 public IIntentReceiver forgetReceiverDispatcher(Context context,
578 BroadcastReceiver r) {
579 synchronized (mReceivers) {
580 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
581 LoadedApk.ReceiverDispatcher rd = null;
582 if (map != null) {
583 rd = map.get(r);
584 if (rd != null) {
585 map.remove(r);
586 if (map.size() == 0) {
587 mReceivers.remove(context);
588 }
589 if (r.getDebugUnregister()) {
590 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
591 = mUnregisteredReceivers.get(context);
592 if (holder == null) {
593 holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
594 mUnregisteredReceivers.put(context, holder);
595 }
596 RuntimeException ex = new IllegalArgumentException(
597 "Originally unregistered here:");
598 ex.fillInStackTrace();
599 rd.setUnregisterLocation(ex);
600 holder.put(r, rd);
601 }
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800602 rd.mForgotten = true;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700603 return rd.getIIntentReceiver();
604 }
605 }
606 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
607 = mUnregisteredReceivers.get(context);
608 if (holder != null) {
609 rd = holder.get(r);
610 if (rd != null) {
611 RuntimeException ex = rd.getUnregisterLocation();
612 throw new IllegalArgumentException(
613 "Unregistering Receiver " + r
614 + " that was already unregistered", ex);
615 }
616 }
617 if (context == null) {
618 throw new IllegalStateException("Unbinding Receiver " + r
619 + " from Context that is no longer in use: " + context);
620 } else {
621 throw new IllegalArgumentException("Receiver not registered: " + r);
622 }
623
624 }
625 }
626
627 static final class ReceiverDispatcher {
628
629 final static class InnerReceiver extends IIntentReceiver.Stub {
630 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
631 final LoadedApk.ReceiverDispatcher mStrongRef;
632
633 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
634 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
635 mStrongRef = strong ? rd : null;
636 }
637 public void performReceive(Intent intent, int resultCode,
638 String data, Bundle extras, boolean ordered, boolean sticky) {
639 LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
640 if (ActivityThread.DEBUG_BROADCAST) {
641 int seq = intent.getIntExtra("seq", -1);
642 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
643 + " to " + (rd != null ? rd.mReceiver : null));
644 }
645 if (rd != null) {
646 rd.performReceive(intent, resultCode, data, extras,
647 ordered, sticky);
648 } else {
649 // The activity manager dispatched a broadcast to a registered
650 // receiver in this process, but before it could be delivered the
651 // receiver was unregistered. Acknowledge the broadcast on its
652 // behalf so that the system's broadcast sequence can continue.
653 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
654 "Finishing broadcast to unregistered receiver");
655 IActivityManager mgr = ActivityManagerNative.getDefault();
656 try {
657 mgr.finishReceiver(this, resultCode, data, extras, false);
658 } catch (RemoteException e) {
659 Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
660 }
661 }
662 }
663 }
664
665 final IIntentReceiver.Stub mIIntentReceiver;
666 final BroadcastReceiver mReceiver;
667 final Context mContext;
668 final Handler mActivityThread;
669 final Instrumentation mInstrumentation;
670 final boolean mRegistered;
671 final IntentReceiverLeaked mLocation;
672 RuntimeException mUnregisterLocation;
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800673 boolean mForgotten;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700674
Dianne Hackborne829fef2010-10-26 17:44:01 -0700675 final class Args extends BroadcastReceiver.PendingResult implements Runnable {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700676 private Intent mCurIntent;
Dianne Hackborne829fef2010-10-26 17:44:01 -0700677 private final boolean mOrdered;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700678
Dianne Hackborne829fef2010-10-26 17:44:01 -0700679 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
680 boolean ordered, boolean sticky) {
681 super(resultCode, resultData, resultExtras,
682 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
683 ordered, sticky, mIIntentReceiver.asBinder());
684 mCurIntent = intent;
685 mOrdered = ordered;
686 }
687
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700688 public void run() {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700689 final BroadcastReceiver receiver = mReceiver;
690 final boolean ordered = mOrdered;
691
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700692 if (ActivityThread.DEBUG_BROADCAST) {
693 int seq = mCurIntent.getIntExtra("seq", -1);
694 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
695 + " seq=" + seq + " to " + mReceiver);
696 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
Dianne Hackborne829fef2010-10-26 17:44:01 -0700697 + " mOrderedHint=" + ordered);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700698 }
699
Dianne Hackborne829fef2010-10-26 17:44:01 -0700700 final IActivityManager mgr = ActivityManagerNative.getDefault();
701 final Intent intent = mCurIntent;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700702 mCurIntent = null;
703
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800704 if (receiver == null || mForgotten) {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700705 if (mRegistered && ordered) {
706 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
707 "Finishing null broadcast to " + mReceiver);
708 sendFinished(mgr);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700709 }
710 return;
711 }
712
713 try {
714 ClassLoader cl = mReceiver.getClass().getClassLoader();
715 intent.setExtrasClassLoader(cl);
Dianne Hackborne829fef2010-10-26 17:44:01 -0700716 setExtrasClassLoader(cl);
717 receiver.setPendingResult(this);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700718 receiver.onReceive(mContext, intent);
719 } catch (Exception e) {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700720 if (mRegistered && ordered) {
721 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
722 "Finishing failed broadcast to " + mReceiver);
723 sendFinished(mgr);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700724 }
725 if (mInstrumentation == null ||
726 !mInstrumentation.onException(mReceiver, e)) {
727 throw new RuntimeException(
728 "Error receiving broadcast " + intent
729 + " in " + mReceiver, e);
730 }
731 }
Dianne Hackborne829fef2010-10-26 17:44:01 -0700732
733 if (receiver.getPendingResult() != null) {
734 finish();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700735 }
736 }
737 }
738
739 ReceiverDispatcher(BroadcastReceiver receiver, Context context,
740 Handler activityThread, Instrumentation instrumentation,
741 boolean registered) {
742 if (activityThread == null) {
743 throw new NullPointerException("Handler must not be null");
744 }
745
746 mIIntentReceiver = new InnerReceiver(this, !registered);
747 mReceiver = receiver;
748 mContext = context;
749 mActivityThread = activityThread;
750 mInstrumentation = instrumentation;
751 mRegistered = registered;
752 mLocation = new IntentReceiverLeaked(null);
753 mLocation.fillInStackTrace();
754 }
755
756 void validate(Context context, Handler activityThread) {
757 if (mContext != context) {
758 throw new IllegalStateException(
759 "Receiver " + mReceiver +
760 " registered with differing Context (was " +
761 mContext + " now " + context + ")");
762 }
763 if (mActivityThread != activityThread) {
764 throw new IllegalStateException(
765 "Receiver " + mReceiver +
766 " registered with differing handler (was " +
767 mActivityThread + " now " + activityThread + ")");
768 }
769 }
770
771 IntentReceiverLeaked getLocation() {
772 return mLocation;
773 }
774
775 BroadcastReceiver getIntentReceiver() {
776 return mReceiver;
777 }
778
779 IIntentReceiver getIIntentReceiver() {
780 return mIIntentReceiver;
781 }
782
783 void setUnregisterLocation(RuntimeException ex) {
784 mUnregisterLocation = ex;
785 }
786
787 RuntimeException getUnregisterLocation() {
788 return mUnregisterLocation;
789 }
790
791 public void performReceive(Intent intent, int resultCode,
792 String data, Bundle extras, boolean ordered, boolean sticky) {
793 if (ActivityThread.DEBUG_BROADCAST) {
794 int seq = intent.getIntExtra("seq", -1);
795 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
796 + " to " + mReceiver);
797 }
Dianne Hackborne829fef2010-10-26 17:44:01 -0700798 Args args = new Args(intent, resultCode, data, extras, ordered, sticky);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700799 if (!mActivityThread.post(args)) {
800 if (mRegistered && ordered) {
801 IActivityManager mgr = ActivityManagerNative.getDefault();
Dianne Hackborne829fef2010-10-26 17:44:01 -0700802 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
803 "Finishing sync broadcast to " + mReceiver);
804 args.sendFinished(mgr);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700805 }
806 }
807 }
808
809 }
810
811 public final IServiceConnection getServiceDispatcher(ServiceConnection c,
812 Context context, Handler handler, int flags) {
813 synchronized (mServices) {
814 LoadedApk.ServiceDispatcher sd = null;
815 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
816 if (map != null) {
817 sd = map.get(c);
818 }
819 if (sd == null) {
820 sd = new ServiceDispatcher(c, context, handler, flags);
821 if (map == null) {
822 map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
823 mServices.put(context, map);
824 }
825 map.put(c, sd);
826 } else {
827 sd.validate(context, handler);
828 }
829 return sd.getIServiceConnection();
830 }
831 }
832
833 public final IServiceConnection forgetServiceDispatcher(Context context,
834 ServiceConnection c) {
835 synchronized (mServices) {
836 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
837 = mServices.get(context);
838 LoadedApk.ServiceDispatcher sd = null;
839 if (map != null) {
840 sd = map.get(c);
841 if (sd != null) {
842 map.remove(c);
843 sd.doForget();
844 if (map.size() == 0) {
845 mServices.remove(context);
846 }
847 if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
848 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
849 = mUnboundServices.get(context);
850 if (holder == null) {
851 holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
852 mUnboundServices.put(context, holder);
853 }
854 RuntimeException ex = new IllegalArgumentException(
855 "Originally unbound here:");
856 ex.fillInStackTrace();
857 sd.setUnbindLocation(ex);
858 holder.put(c, sd);
859 }
860 return sd.getIServiceConnection();
861 }
862 }
863 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
864 = mUnboundServices.get(context);
865 if (holder != null) {
866 sd = holder.get(c);
867 if (sd != null) {
868 RuntimeException ex = sd.getUnbindLocation();
869 throw new IllegalArgumentException(
870 "Unbinding Service " + c
871 + " that was already unbound", ex);
872 }
873 }
874 if (context == null) {
875 throw new IllegalStateException("Unbinding Service " + c
876 + " from Context that is no longer in use: " + context);
877 } else {
878 throw new IllegalArgumentException("Service not registered: " + c);
879 }
880 }
881 }
882
883 static final class ServiceDispatcher {
884 private final ServiceDispatcher.InnerConnection mIServiceConnection;
885 private final ServiceConnection mConnection;
886 private final Context mContext;
887 private final Handler mActivityThread;
888 private final ServiceConnectionLeaked mLocation;
889 private final int mFlags;
890
891 private RuntimeException mUnbindLocation;
892
893 private boolean mDied;
894
895 private static class ConnectionInfo {
896 IBinder binder;
897 IBinder.DeathRecipient deathMonitor;
898 }
899
900 private static class InnerConnection extends IServiceConnection.Stub {
901 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
902
903 InnerConnection(LoadedApk.ServiceDispatcher sd) {
904 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
905 }
906
907 public void connected(ComponentName name, IBinder service) throws RemoteException {
908 LoadedApk.ServiceDispatcher sd = mDispatcher.get();
909 if (sd != null) {
910 sd.connected(name, service);
911 }
912 }
913 }
914
915 private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
916 = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
917
918 ServiceDispatcher(ServiceConnection conn,
919 Context context, Handler activityThread, int flags) {
920 mIServiceConnection = new InnerConnection(this);
921 mConnection = conn;
922 mContext = context;
923 mActivityThread = activityThread;
924 mLocation = new ServiceConnectionLeaked(null);
925 mLocation.fillInStackTrace();
926 mFlags = flags;
927 }
928
929 void validate(Context context, Handler activityThread) {
930 if (mContext != context) {
931 throw new RuntimeException(
932 "ServiceConnection " + mConnection +
933 " registered with differing Context (was " +
934 mContext + " now " + context + ")");
935 }
936 if (mActivityThread != activityThread) {
937 throw new RuntimeException(
938 "ServiceConnection " + mConnection +
939 " registered with differing handler (was " +
940 mActivityThread + " now " + activityThread + ")");
941 }
942 }
943
944 void doForget() {
945 synchronized(this) {
946 Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator();
947 while (it.hasNext()) {
948 ServiceDispatcher.ConnectionInfo ci = it.next();
949 ci.binder.unlinkToDeath(ci.deathMonitor, 0);
950 }
951 mActiveConnections.clear();
952 }
953 }
954
955 ServiceConnectionLeaked getLocation() {
956 return mLocation;
957 }
958
959 ServiceConnection getServiceConnection() {
960 return mConnection;
961 }
962
963 IServiceConnection getIServiceConnection() {
964 return mIServiceConnection;
965 }
966
967 int getFlags() {
968 return mFlags;
969 }
970
971 void setUnbindLocation(RuntimeException ex) {
972 mUnbindLocation = ex;
973 }
974
975 RuntimeException getUnbindLocation() {
976 return mUnbindLocation;
977 }
978
979 public void connected(ComponentName name, IBinder service) {
980 if (mActivityThread != null) {
981 mActivityThread.post(new RunConnection(name, service, 0));
982 } else {
983 doConnected(name, service);
984 }
985 }
986
987 public void death(ComponentName name, IBinder service) {
988 ServiceDispatcher.ConnectionInfo old;
989
990 synchronized (this) {
991 mDied = true;
992 old = mActiveConnections.remove(name);
993 if (old == null || old.binder != service) {
994 // Death for someone different than who we last
995 // reported... just ignore it.
996 return;
997 }
998 old.binder.unlinkToDeath(old.deathMonitor, 0);
999 }
1000
1001 if (mActivityThread != null) {
1002 mActivityThread.post(new RunConnection(name, service, 1));
1003 } else {
1004 doDeath(name, service);
1005 }
1006 }
1007
1008 public void doConnected(ComponentName name, IBinder service) {
1009 ServiceDispatcher.ConnectionInfo old;
1010 ServiceDispatcher.ConnectionInfo info;
1011
1012 synchronized (this) {
1013 old = mActiveConnections.get(name);
1014 if (old != null && old.binder == service) {
1015 // Huh, already have this one. Oh well!
1016 return;
1017 }
1018
1019 if (service != null) {
1020 // A new service is being connected... set it all up.
1021 mDied = false;
1022 info = new ConnectionInfo();
1023 info.binder = service;
1024 info.deathMonitor = new DeathMonitor(name, service);
1025 try {
1026 service.linkToDeath(info.deathMonitor, 0);
1027 mActiveConnections.put(name, info);
1028 } catch (RemoteException e) {
1029 // This service was dead before we got it... just
1030 // don't do anything with it.
1031 mActiveConnections.remove(name);
1032 return;
1033 }
1034
1035 } else {
1036 // The named service is being disconnected... clean up.
1037 mActiveConnections.remove(name);
1038 }
1039
1040 if (old != null) {
1041 old.binder.unlinkToDeath(old.deathMonitor, 0);
1042 }
1043 }
1044
1045 // If there was an old service, it is not disconnected.
1046 if (old != null) {
1047 mConnection.onServiceDisconnected(name);
1048 }
1049 // If there is a new service, it is now connected.
1050 if (service != null) {
1051 mConnection.onServiceConnected(name, service);
1052 }
1053 }
1054
1055 public void doDeath(ComponentName name, IBinder service) {
1056 mConnection.onServiceDisconnected(name);
1057 }
1058
1059 private final class RunConnection implements Runnable {
1060 RunConnection(ComponentName name, IBinder service, int command) {
1061 mName = name;
1062 mService = service;
1063 mCommand = command;
1064 }
1065
1066 public void run() {
1067 if (mCommand == 0) {
1068 doConnected(mName, mService);
1069 } else if (mCommand == 1) {
1070 doDeath(mName, mService);
1071 }
1072 }
1073
1074 final ComponentName mName;
1075 final IBinder mService;
1076 final int mCommand;
1077 }
1078
1079 private final class DeathMonitor implements IBinder.DeathRecipient
1080 {
1081 DeathMonitor(ComponentName name, IBinder service) {
1082 mName = name;
1083 mService = service;
1084 }
1085
1086 public void binderDied() {
1087 death(mName, mService);
1088 }
1089
1090 final ComponentName mName;
1091 final IBinder mService;
1092 }
1093 }
1094}