blob: 4239a5d8d0b7607c4b5e7fc7adf291b4d706d5fd [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
Dianne Hackbornadd005c2013-07-17 18:43:12 -070019import android.util.ArrayMap;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070020import com.android.internal.util.ArrayUtils;
21
22import android.content.BroadcastReceiver;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.IIntentReceiver;
26import android.content.Intent;
27import android.content.ServiceConnection;
28import android.content.pm.ApplicationInfo;
29import android.content.pm.IPackageManager;
30import android.content.pm.PackageManager;
31import android.content.res.AssetManager;
32import android.content.res.CompatibilityInfo;
33import android.content.res.Resources;
34import android.os.Bundle;
35import android.os.Handler;
36import android.os.IBinder;
37import android.os.Process;
38import android.os.RemoteException;
Brad Fitzpatrick624d50f2010-11-09 14:25:12 -080039import android.os.StrictMode;
Dianne Hackborn1ded0b12012-04-26 14:14:50 -070040import android.os.Trace;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070041import android.os.UserHandle;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070042import android.util.AndroidRuntimeException;
43import android.util.Slog;
Craig Mautner48d0d182013-06-11 07:53:06 -070044import android.view.DisplayAdjustments;
Jeff Browna492c3a2012-08-23 19:48:44 -070045import android.view.Display;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070046
47import java.io.File;
48import java.io.IOException;
49import java.io.InputStream;
50import java.lang.ref.WeakReference;
51import java.net.URL;
52import java.util.Enumeration;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070053
54final class IntentReceiverLeaked extends AndroidRuntimeException {
55 public IntentReceiverLeaked(String msg) {
56 super(msg);
57 }
58}
59
60final class ServiceConnectionLeaked extends AndroidRuntimeException {
61 public ServiceConnectionLeaked(String msg) {
62 super(msg);
63 }
64}
65
66/**
67 * Local state maintained about a currently loaded .apk.
68 * @hide
69 */
Dianne Hackborn5fd21692011-06-07 14:09:47 -070070public final class LoadedApk {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070071
Amith Yamasani742a6712011-05-04 14:49:28 -070072 private static final String TAG = "LoadedApk";
73
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070074 private final ActivityThread mActivityThread;
75 private final ApplicationInfo mApplicationInfo;
76 final String mPackageName;
77 private final String mAppDir;
78 private final String mResDir;
79 private final String[] mSharedLibraries;
80 private final String mDataDir;
Kenny Root85387d72010-08-26 10:13:11 -070081 private final String mLibDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070082 private final File mDataDirFile;
83 private final ClassLoader mBaseClassLoader;
84 private final boolean mSecurityViolation;
85 private final boolean mIncludeCode;
Craig Mautner48d0d182013-06-11 07:53:06 -070086 private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070087 Resources mResources;
88 private ClassLoader mClassLoader;
89 private Application mApplication;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070090
Dianne Hackbornadd005c2013-07-17 18:43:12 -070091 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
92 = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
93 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
94 = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
95 private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
96 = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
97 private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
98 = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070099
100 int mClientCount = 0;
101
102 Application getApplication() {
103 return mApplication;
104 }
105
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700106 /**
107 * Create information about a new .apk
108 *
109 * NOTE: This constructor is called with ActivityThread's lock held,
110 * so MUST NOT call back out to the activity manager.
111 */
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700112 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400113 CompatibilityInfo compatInfo,
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700114 ActivityThread mainThread, ClassLoader baseLoader,
115 boolean securityViolation, boolean includeCode) {
116 mActivityThread = activityThread;
117 mApplicationInfo = aInfo;
118 mPackageName = aInfo.packageName;
119 mAppDir = aInfo.sourceDir;
Amith Yamasani742a6712011-05-04 14:49:28 -0700120 final int myUid = Process.myUid();
121 mResDir = aInfo.uid == myUid ? aInfo.sourceDir
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700122 : aInfo.publicSourceDir;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700123 if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
124 aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
Amith Yamasani742a6712011-05-04 14:49:28 -0700125 mPackageName);
126 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700127 mSharedLibraries = aInfo.sharedLibraryFiles;
128 mDataDir = aInfo.dataDir;
129 mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
Kenny Root85387d72010-08-26 10:13:11 -0700130 mLibDir = aInfo.nativeLibraryDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700131 mBaseClassLoader = baseLoader;
132 mSecurityViolation = securityViolation;
133 mIncludeCode = includeCode;
Craig Mautner48d0d182013-06-11 07:53:06 -0700134 mDisplayAdjustments.setCompatibilityInfo(compatInfo);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700135
136 if (mAppDir == null) {
137 if (ActivityThread.mSystemContext == null) {
138 ActivityThread.mSystemContext =
139 ContextImpl.createSystemContext(mainThread);
Craig Mautner88c05892013-06-28 09:47:45 -0700140 ResourcesManager resourcesManager = ResourcesManager.getInstance();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700141 ActivityThread.mSystemContext.getResources().updateConfiguration(
Craig Mautner88c05892013-06-28 09:47:45 -0700142 resourcesManager.getConfiguration(),
143 resourcesManager.getDisplayMetricsLocked(
144 Display.DEFAULT_DISPLAY, mDisplayAdjustments), compatInfo);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700145 //Slog.i(TAG, "Created system resources "
146 // + mSystemContext.getResources() + ": "
147 // + mSystemContext.getResources().getConfiguration());
148 }
149 mClassLoader = ActivityThread.mSystemContext.getClassLoader();
150 mResources = ActivityThread.mSystemContext.getResources();
151 }
152 }
153
154 public LoadedApk(ActivityThread activityThread, String name,
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400155 Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700156 mActivityThread = activityThread;
157 mApplicationInfo = info != null ? info : new ApplicationInfo();
158 mApplicationInfo.packageName = name;
159 mPackageName = name;
160 mAppDir = null;
161 mResDir = null;
162 mSharedLibraries = null;
163 mDataDir = null;
164 mDataDirFile = null;
Kenny Root85387d72010-08-26 10:13:11 -0700165 mLibDir = null;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700166 mBaseClassLoader = null;
167 mSecurityViolation = false;
168 mIncludeCode = true;
169 mClassLoader = systemContext.getClassLoader();
170 mResources = systemContext.getResources();
Craig Mautner48d0d182013-06-11 07:53:06 -0700171 mDisplayAdjustments.setCompatibilityInfo(compatInfo);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700172 }
173
174 public String getPackageName() {
175 return mPackageName;
176 }
177
178 public ApplicationInfo getApplicationInfo() {
179 return mApplicationInfo;
180 }
181
182 public boolean isSecurityViolation() {
183 return mSecurityViolation;
184 }
185
Craig Mautner48d0d182013-06-11 07:53:06 -0700186 public CompatibilityInfo getCompatibilityInfo() {
187 return mDisplayAdjustments.getCompatibilityInfo();
188 }
189
190 public void setCompatibilityInfo(CompatibilityInfo compatInfo) {
191 mDisplayAdjustments.setCompatibilityInfo(compatInfo);
192 }
193
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700194 /**
195 * Gets the array of shared libraries that are listed as
196 * used by the given package.
197 *
198 * @param packageName the name of the package (note: not its
199 * file name)
200 * @return null-ok; the array of shared libraries, each one
201 * a fully-qualified path
202 */
203 private static String[] getLibrariesFor(String packageName) {
204 ApplicationInfo ai = null;
205 try {
206 ai = ActivityThread.getPackageManager().getApplicationInfo(packageName,
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700207 PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId());
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700208 } catch (RemoteException e) {
209 throw new AssertionError(e);
210 }
211
212 if (ai == null) {
213 return null;
214 }
215
216 return ai.sharedLibraryFiles;
217 }
218
219 /**
220 * Combines two arrays (of library names) such that they are
221 * concatenated in order but are devoid of duplicates. The
222 * result is a single string with the names of the libraries
223 * separated by colons, or <code>null</code> if both lists
224 * were <code>null</code> or empty.
225 *
226 * @param list1 null-ok; the first list
227 * @param list2 null-ok; the second list
228 * @return null-ok; the combination
229 */
230 private static String combineLibs(String[] list1, String[] list2) {
231 StringBuilder result = new StringBuilder(300);
232 boolean first = true;
233
234 if (list1 != null) {
235 for (String s : list1) {
236 if (first) {
237 first = false;
238 } else {
239 result.append(':');
240 }
241 result.append(s);
242 }
243 }
244
245 // Only need to check for duplicates if list1 was non-empty.
246 boolean dupCheck = !first;
247
248 if (list2 != null) {
249 for (String s : list2) {
250 if (dupCheck && ArrayUtils.contains(list1, s)) {
251 continue;
252 }
253
254 if (first) {
255 first = false;
256 } else {
257 result.append(':');
258 }
259 result.append(s);
260 }
261 }
262
263 return result.toString();
264 }
265
266 public ClassLoader getClassLoader() {
267 synchronized (this) {
268 if (mClassLoader != null) {
269 return mClassLoader;
270 }
271
272 if (mIncludeCode && !mPackageName.equals("android")) {
273 String zip = mAppDir;
Brian Carlstromd893a892012-04-01 21:30:26 -0700274 String libraryPath = mLibDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700275
276 /*
277 * The following is a bit of a hack to inject
278 * instrumentation into the system: If the app
279 * being started matches one of the instrumentation names,
280 * then we combine both the "instrumentation" and
281 * "instrumented" app into the path, along with the
282 * concatenation of both apps' shared library lists.
283 */
284
285 String instrumentationAppDir =
286 mActivityThread.mInstrumentationAppDir;
Brian Carlstromd893a892012-04-01 21:30:26 -0700287 String instrumentationAppLibraryDir =
288 mActivityThread.mInstrumentationAppLibraryDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700289 String instrumentationAppPackage =
290 mActivityThread.mInstrumentationAppPackage;
291 String instrumentedAppDir =
292 mActivityThread.mInstrumentedAppDir;
Brian Carlstromd893a892012-04-01 21:30:26 -0700293 String instrumentedAppLibraryDir =
294 mActivityThread.mInstrumentedAppLibraryDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700295 String[] instrumentationLibs = null;
296
297 if (mAppDir.equals(instrumentationAppDir)
298 || mAppDir.equals(instrumentedAppDir)) {
299 zip = instrumentationAppDir + ":" + instrumentedAppDir;
Brian Carlstromd893a892012-04-01 21:30:26 -0700300 libraryPath = instrumentationAppLibraryDir + ":" + instrumentedAppLibraryDir;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700301 if (! instrumentedAppDir.equals(instrumentationAppDir)) {
302 instrumentationLibs =
303 getLibrariesFor(instrumentationAppPackage);
304 }
305 }
306
307 if ((mSharedLibraries != null) ||
308 (instrumentationLibs != null)) {
309 zip =
310 combineLibs(mSharedLibraries, instrumentationLibs)
311 + ':' + zip;
312 }
313
314 /*
315 * With all the combination done (if necessary, actually
316 * create the class loader.
317 */
318
Kenny Root85387d72010-08-26 10:13:11 -0700319 if (ActivityThread.localLOGV)
Brian Carlstromd893a892012-04-01 21:30:26 -0700320 Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + libraryPath);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700321
Brad Fitzpatrick624d50f2010-11-09 14:25:12 -0800322 // Temporarily disable logging of disk reads on the Looper thread
323 // as this is early and necessary.
324 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
325
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700326 mClassLoader =
327 ApplicationLoaders.getDefault().getClassLoader(
Brian Carlstromd893a892012-04-01 21:30:26 -0700328 zip, libraryPath, mBaseClassLoader);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700329 initializeJavaContextClassLoader();
Brad Fitzpatrick624d50f2010-11-09 14:25:12 -0800330
331 StrictMode.setThreadPolicy(oldPolicy);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700332 } else {
333 if (mBaseClassLoader == null) {
334 mClassLoader = ClassLoader.getSystemClassLoader();
335 } else {
336 mClassLoader = mBaseClassLoader;
337 }
338 }
339 return mClassLoader;
340 }
341 }
342
343 /**
344 * Setup value for Thread.getContextClassLoader(). If the
345 * package will not run in in a VM with other packages, we set
346 * the Java context ClassLoader to the
347 * PackageInfo.getClassLoader value. However, if this VM can
348 * contain multiple packages, we intead set the Java context
349 * ClassLoader to a proxy that will warn about the use of Java
350 * context ClassLoaders and then fall through to use the
351 * system ClassLoader.
352 *
353 * <p> Note that this is similar to but not the same as the
354 * android.content.Context.getClassLoader(). While both
355 * context class loaders are typically set to the
356 * PathClassLoader used to load the package archive in the
357 * single application per VM case, a single Android process
358 * may contain several Contexts executing on one thread with
359 * their own logical ClassLoaders while the Java context
360 * ClassLoader is a thread local. This is why in the case when
361 * we have multiple packages per VM we do not set the Java
362 * context ClassLoader to an arbitrary but instead warn the
363 * user to set their own if we detect that they are using a
364 * Java library that expects it to be set.
365 */
366 private void initializeJavaContextClassLoader() {
367 IPackageManager pm = ActivityThread.getPackageManager();
368 android.content.pm.PackageInfo pi;
369 try {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700370 pi = pm.getPackageInfo(mPackageName, 0, UserHandle.myUserId());
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700371 } catch (RemoteException e) {
Dianne Hackborn208d9372013-02-25 13:17:54 -0800372 throw new IllegalStateException("Unable to get package info for "
373 + mPackageName + "; is system dying?", e);
374 }
375 if (pi == null) {
376 throw new IllegalStateException("Unable to get package info for "
377 + mPackageName + "; is package not installed?");
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700378 }
379 /*
380 * Two possible indications that this package could be
381 * sharing its virtual machine with other packages:
382 *
383 * 1.) the sharedUserId attribute is set in the manifest,
384 * indicating a request to share a VM with other
385 * packages with the same sharedUserId.
386 *
387 * 2.) the application element of the manifest has an
388 * attribute specifying a non-default process name,
389 * indicating the desire to run in another packages VM.
390 */
391 boolean sharedUserIdSet = (pi.sharedUserId != null);
392 boolean processNameNotDefault =
393 (pi.applicationInfo != null &&
394 !mPackageName.equals(pi.applicationInfo.processName));
395 boolean sharable = (sharedUserIdSet || processNameNotDefault);
396 ClassLoader contextClassLoader =
397 (sharable)
398 ? new WarningContextClassLoader()
399 : mClassLoader;
400 Thread.currentThread().setContextClassLoader(contextClassLoader);
401 }
402
403 private static class WarningContextClassLoader extends ClassLoader {
404
405 private static boolean warned = false;
406
407 private void warn(String methodName) {
408 if (warned) {
409 return;
410 }
411 warned = true;
412 Thread.currentThread().setContextClassLoader(getParent());
413 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " +
414 "The class loader returned by " +
415 "Thread.getContextClassLoader() may fail for processes " +
416 "that host multiple applications. You should explicitly " +
417 "specify a context class loader. For example: " +
418 "Thread.setContextClassLoader(getClass().getClassLoader());");
419 }
420
421 @Override public URL getResource(String resName) {
422 warn("getResource");
423 return getParent().getResource(resName);
424 }
425
426 @Override public Enumeration<URL> getResources(String resName) throws IOException {
427 warn("getResources");
428 return getParent().getResources(resName);
429 }
430
431 @Override public InputStream getResourceAsStream(String resName) {
432 warn("getResourceAsStream");
433 return getParent().getResourceAsStream(resName);
434 }
435
436 @Override public Class<?> loadClass(String className) throws ClassNotFoundException {
437 warn("loadClass");
438 return getParent().loadClass(className);
439 }
440
441 @Override public void setClassAssertionStatus(String cname, boolean enable) {
442 warn("setClassAssertionStatus");
443 getParent().setClassAssertionStatus(cname, enable);
444 }
445
446 @Override public void setPackageAssertionStatus(String pname, boolean enable) {
447 warn("setPackageAssertionStatus");
448 getParent().setPackageAssertionStatus(pname, enable);
449 }
450
451 @Override public void setDefaultAssertionStatus(boolean enable) {
452 warn("setDefaultAssertionStatus");
453 getParent().setDefaultAssertionStatus(enable);
454 }
455
456 @Override public void clearAssertionStatus() {
457 warn("clearAssertionStatus");
458 getParent().clearAssertionStatus();
459 }
460 }
461
462 public String getAppDir() {
463 return mAppDir;
464 }
465
Brian Carlstromd893a892012-04-01 21:30:26 -0700466 public String getLibDir() {
467 return mLibDir;
468 }
469
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700470 public String getResDir() {
471 return mResDir;
472 }
473
474 public String getDataDir() {
475 return mDataDir;
476 }
477
478 public File getDataDirFile() {
479 return mDataDirFile;
480 }
481
482 public AssetManager getAssets(ActivityThread mainThread) {
483 return getResources(mainThread).getAssets();
484 }
485
486 public Resources getResources(ActivityThread mainThread) {
487 if (mResources == null) {
Jeff Browna492c3a2012-08-23 19:48:44 -0700488 mResources = mainThread.getTopLevelResources(mResDir,
489 Display.DEFAULT_DISPLAY, null, this);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700490 }
491 return mResources;
492 }
493
494 public Application makeApplication(boolean forceDefaultAppClass,
495 Instrumentation instrumentation) {
496 if (mApplication != null) {
497 return mApplication;
498 }
499
500 Application app = null;
501
502 String appClass = mApplicationInfo.className;
503 if (forceDefaultAppClass || (appClass == null)) {
504 appClass = "android.app.Application";
505 }
506
507 try {
508 java.lang.ClassLoader cl = getClassLoader();
509 ContextImpl appContext = new ContextImpl();
510 appContext.init(this, null, mActivityThread);
511 app = mActivityThread.mInstrumentation.newApplication(
512 cl, appClass, appContext);
513 appContext.setOuterContext(app);
514 } catch (Exception e) {
515 if (!mActivityThread.mInstrumentation.onException(app, e)) {
516 throw new RuntimeException(
517 "Unable to instantiate application " + appClass
518 + ": " + e.toString(), e);
519 }
520 }
521 mActivityThread.mAllApplications.add(app);
522 mApplication = app;
523
524 if (instrumentation != null) {
525 try {
526 instrumentation.callApplicationOnCreate(app);
527 } catch (Exception e) {
528 if (!instrumentation.onException(app, e)) {
529 throw new RuntimeException(
530 "Unable to create application " + app.getClass().getName()
531 + ": " + e.toString(), e);
532 }
533 }
534 }
535
536 return app;
537 }
538
539 public void removeContextRegistrations(Context context,
540 String who, String what) {
Jeff Sharkeyd7026f12012-03-01 20:50:32 -0800541 final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700542 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
543 mReceivers.remove(context);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700544 if (rmap != null) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700545 for (int i=0; i<rmap.size(); i++) {
546 LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700547 IntentReceiverLeaked leak = new IntentReceiverLeaked(
548 what + " " + who + " has leaked IntentReceiver "
549 + rd.getIntentReceiver() + " that was " +
550 "originally registered here. Are you missing a " +
551 "call to unregisterReceiver()?");
552 leak.setStackTrace(rd.getLocation().getStackTrace());
553 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
Jeff Sharkeyd7026f12012-03-01 20:50:32 -0800554 if (reportRegistrationLeaks) {
555 StrictMode.onIntentReceiverLeaked(leak);
556 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700557 try {
558 ActivityManagerNative.getDefault().unregisterReceiver(
559 rd.getIIntentReceiver());
560 } catch (RemoteException e) {
561 // system crashed, nothing we can do
562 }
563 }
564 }
565 mUnregisteredReceivers.remove(context);
566 //Slog.i(TAG, "Receiver registrations: " + mReceivers);
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700567 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700568 mServices.remove(context);
569 if (smap != null) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700570 for (int i=0; i<smap.size(); i++) {
571 LoadedApk.ServiceDispatcher sd = smap.valueAt(i);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700572 ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
573 what + " " + who + " has leaked ServiceConnection "
574 + sd.getServiceConnection() + " that was originally bound here");
575 leak.setStackTrace(sd.getLocation().getStackTrace());
576 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
Jeff Sharkeyd7026f12012-03-01 20:50:32 -0800577 if (reportRegistrationLeaks) {
578 StrictMode.onServiceConnectionLeaked(leak);
579 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700580 try {
581 ActivityManagerNative.getDefault().unbindService(
582 sd.getIServiceConnection());
583 } catch (RemoteException e) {
584 // system crashed, nothing we can do
585 }
586 sd.doForget();
587 }
588 }
589 mUnboundServices.remove(context);
590 //Slog.i(TAG, "Service registrations: " + mServices);
591 }
592
593 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
594 Context context, Handler handler,
595 Instrumentation instrumentation, boolean registered) {
596 synchronized (mReceivers) {
597 LoadedApk.ReceiverDispatcher rd = null;
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700598 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700599 if (registered) {
600 map = mReceivers.get(context);
601 if (map != null) {
602 rd = map.get(r);
603 }
604 }
605 if (rd == null) {
606 rd = new ReceiverDispatcher(r, context, handler,
607 instrumentation, registered);
608 if (registered) {
609 if (map == null) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700610 map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700611 mReceivers.put(context, map);
612 }
613 map.put(r, rd);
614 }
615 } else {
616 rd.validate(context, handler);
617 }
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800618 rd.mForgotten = false;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700619 return rd.getIIntentReceiver();
620 }
621 }
622
623 public IIntentReceiver forgetReceiverDispatcher(Context context,
624 BroadcastReceiver r) {
625 synchronized (mReceivers) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700626 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700627 LoadedApk.ReceiverDispatcher rd = null;
628 if (map != null) {
629 rd = map.get(r);
630 if (rd != null) {
631 map.remove(r);
632 if (map.size() == 0) {
633 mReceivers.remove(context);
634 }
635 if (r.getDebugUnregister()) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700636 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700637 = mUnregisteredReceivers.get(context);
638 if (holder == null) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700639 holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700640 mUnregisteredReceivers.put(context, holder);
641 }
642 RuntimeException ex = new IllegalArgumentException(
643 "Originally unregistered here:");
644 ex.fillInStackTrace();
645 rd.setUnregisterLocation(ex);
646 holder.put(r, rd);
647 }
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800648 rd.mForgotten = true;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700649 return rd.getIIntentReceiver();
650 }
651 }
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700652 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700653 = mUnregisteredReceivers.get(context);
654 if (holder != null) {
655 rd = holder.get(r);
656 if (rd != null) {
657 RuntimeException ex = rd.getUnregisterLocation();
658 throw new IllegalArgumentException(
659 "Unregistering Receiver " + r
660 + " that was already unregistered", ex);
661 }
662 }
663 if (context == null) {
664 throw new IllegalStateException("Unbinding Receiver " + r
665 + " from Context that is no longer in use: " + context);
666 } else {
667 throw new IllegalArgumentException("Receiver not registered: " + r);
668 }
669
670 }
671 }
672
673 static final class ReceiverDispatcher {
674
675 final static class InnerReceiver extends IIntentReceiver.Stub {
676 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
677 final LoadedApk.ReceiverDispatcher mStrongRef;
678
679 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
680 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
681 mStrongRef = strong ? rd : null;
682 }
Dianne Hackborn20e80982012-08-31 19:00:44 -0700683 public void performReceive(Intent intent, int resultCode, String data,
684 Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700685 LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
686 if (ActivityThread.DEBUG_BROADCAST) {
687 int seq = intent.getIntExtra("seq", -1);
688 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
689 + " to " + (rd != null ? rd.mReceiver : null));
690 }
691 if (rd != null) {
692 rd.performReceive(intent, resultCode, data, extras,
Dianne Hackborn20e80982012-08-31 19:00:44 -0700693 ordered, sticky, sendingUser);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700694 } else {
695 // The activity manager dispatched a broadcast to a registered
696 // receiver in this process, but before it could be delivered the
697 // receiver was unregistered. Acknowledge the broadcast on its
698 // behalf so that the system's broadcast sequence can continue.
699 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
700 "Finishing broadcast to unregistered receiver");
701 IActivityManager mgr = ActivityManagerNative.getDefault();
702 try {
Dianne Hackborn9ecebbf2011-09-28 23:19:47 -0400703 if (extras != null) {
704 extras.setAllowFds(false);
705 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700706 mgr.finishReceiver(this, resultCode, data, extras, false);
707 } catch (RemoteException e) {
708 Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
709 }
710 }
711 }
712 }
713
714 final IIntentReceiver.Stub mIIntentReceiver;
715 final BroadcastReceiver mReceiver;
716 final Context mContext;
717 final Handler mActivityThread;
718 final Instrumentation mInstrumentation;
719 final boolean mRegistered;
720 final IntentReceiverLeaked mLocation;
721 RuntimeException mUnregisterLocation;
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800722 boolean mForgotten;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700723
Dianne Hackborne829fef2010-10-26 17:44:01 -0700724 final class Args extends BroadcastReceiver.PendingResult implements Runnable {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700725 private Intent mCurIntent;
Dianne Hackborne829fef2010-10-26 17:44:01 -0700726 private final boolean mOrdered;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700727
Dianne Hackborne829fef2010-10-26 17:44:01 -0700728 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
Dianne Hackborn20e80982012-08-31 19:00:44 -0700729 boolean ordered, boolean sticky, int sendingUser) {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700730 super(resultCode, resultData, resultExtras,
731 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
Dianne Hackborn20e80982012-08-31 19:00:44 -0700732 ordered, sticky, mIIntentReceiver.asBinder(), sendingUser);
Dianne Hackborne829fef2010-10-26 17:44:01 -0700733 mCurIntent = intent;
734 mOrdered = ordered;
735 }
736
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700737 public void run() {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700738 final BroadcastReceiver receiver = mReceiver;
739 final boolean ordered = mOrdered;
740
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700741 if (ActivityThread.DEBUG_BROADCAST) {
742 int seq = mCurIntent.getIntExtra("seq", -1);
743 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
744 + " seq=" + seq + " to " + mReceiver);
745 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
Dianne Hackborne829fef2010-10-26 17:44:01 -0700746 + " mOrderedHint=" + ordered);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700747 }
748
Dianne Hackborne829fef2010-10-26 17:44:01 -0700749 final IActivityManager mgr = ActivityManagerNative.getDefault();
750 final Intent intent = mCurIntent;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700751 mCurIntent = null;
752
Dianne Hackbornc2d9c8e2011-01-24 21:59:21 -0800753 if (receiver == null || mForgotten) {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700754 if (mRegistered && ordered) {
755 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
756 "Finishing null broadcast to " + mReceiver);
757 sendFinished(mgr);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700758 }
759 return;
760 }
761
Dianne Hackborn1ded0b12012-04-26 14:14:50 -0700762 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700763 try {
764 ClassLoader cl = mReceiver.getClass().getClassLoader();
765 intent.setExtrasClassLoader(cl);
Dianne Hackborne829fef2010-10-26 17:44:01 -0700766 setExtrasClassLoader(cl);
767 receiver.setPendingResult(this);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700768 receiver.onReceive(mContext, intent);
769 } catch (Exception e) {
Dianne Hackborne829fef2010-10-26 17:44:01 -0700770 if (mRegistered && ordered) {
771 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
772 "Finishing failed broadcast to " + mReceiver);
773 sendFinished(mgr);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700774 }
775 if (mInstrumentation == null ||
776 !mInstrumentation.onException(mReceiver, e)) {
Dianne Hackborn1ded0b12012-04-26 14:14:50 -0700777 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700778 throw new RuntimeException(
779 "Error receiving broadcast " + intent
780 + " in " + mReceiver, e);
781 }
782 }
Dianne Hackborne829fef2010-10-26 17:44:01 -0700783
784 if (receiver.getPendingResult() != null) {
785 finish();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700786 }
Dianne Hackborn1ded0b12012-04-26 14:14:50 -0700787 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700788 }
789 }
790
791 ReceiverDispatcher(BroadcastReceiver receiver, Context context,
792 Handler activityThread, Instrumentation instrumentation,
793 boolean registered) {
794 if (activityThread == null) {
795 throw new NullPointerException("Handler must not be null");
796 }
797
798 mIIntentReceiver = new InnerReceiver(this, !registered);
799 mReceiver = receiver;
800 mContext = context;
801 mActivityThread = activityThread;
802 mInstrumentation = instrumentation;
803 mRegistered = registered;
804 mLocation = new IntentReceiverLeaked(null);
805 mLocation.fillInStackTrace();
806 }
807
808 void validate(Context context, Handler activityThread) {
809 if (mContext != context) {
810 throw new IllegalStateException(
811 "Receiver " + mReceiver +
812 " registered with differing Context (was " +
813 mContext + " now " + context + ")");
814 }
815 if (mActivityThread != activityThread) {
816 throw new IllegalStateException(
817 "Receiver " + mReceiver +
818 " registered with differing handler (was " +
819 mActivityThread + " now " + activityThread + ")");
820 }
821 }
822
823 IntentReceiverLeaked getLocation() {
824 return mLocation;
825 }
826
827 BroadcastReceiver getIntentReceiver() {
828 return mReceiver;
829 }
830
831 IIntentReceiver getIIntentReceiver() {
832 return mIIntentReceiver;
833 }
834
835 void setUnregisterLocation(RuntimeException ex) {
836 mUnregisterLocation = ex;
837 }
838
839 RuntimeException getUnregisterLocation() {
840 return mUnregisterLocation;
841 }
842
Dianne Hackborn20e80982012-08-31 19:00:44 -0700843 public void performReceive(Intent intent, int resultCode, String data,
844 Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700845 if (ActivityThread.DEBUG_BROADCAST) {
846 int seq = intent.getIntExtra("seq", -1);
847 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
848 + " to " + mReceiver);
849 }
Dianne Hackborn20e80982012-08-31 19:00:44 -0700850 Args args = new Args(intent, resultCode, data, extras, ordered,
851 sticky, sendingUser);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700852 if (!mActivityThread.post(args)) {
853 if (mRegistered && ordered) {
854 IActivityManager mgr = ActivityManagerNative.getDefault();
Dianne Hackborne829fef2010-10-26 17:44:01 -0700855 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
856 "Finishing sync broadcast to " + mReceiver);
857 args.sendFinished(mgr);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700858 }
859 }
860 }
861
862 }
863
864 public final IServiceConnection getServiceDispatcher(ServiceConnection c,
865 Context context, Handler handler, int flags) {
866 synchronized (mServices) {
867 LoadedApk.ServiceDispatcher sd = null;
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700868 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700869 if (map != null) {
870 sd = map.get(c);
871 }
872 if (sd == null) {
873 sd = new ServiceDispatcher(c, context, handler, flags);
874 if (map == null) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700875 map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700876 mServices.put(context, map);
877 }
878 map.put(c, sd);
879 } else {
880 sd.validate(context, handler);
881 }
882 return sd.getIServiceConnection();
883 }
884 }
885
886 public final IServiceConnection forgetServiceDispatcher(Context context,
887 ServiceConnection c) {
888 synchronized (mServices) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700889 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700890 = mServices.get(context);
891 LoadedApk.ServiceDispatcher sd = null;
892 if (map != null) {
893 sd = map.get(c);
894 if (sd != null) {
895 map.remove(c);
896 sd.doForget();
897 if (map.size() == 0) {
898 mServices.remove(context);
899 }
900 if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700901 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700902 = mUnboundServices.get(context);
903 if (holder == null) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700904 holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700905 mUnboundServices.put(context, holder);
906 }
907 RuntimeException ex = new IllegalArgumentException(
908 "Originally unbound here:");
909 ex.fillInStackTrace();
910 sd.setUnbindLocation(ex);
911 holder.put(c, sd);
912 }
913 return sd.getIServiceConnection();
914 }
915 }
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700916 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700917 = mUnboundServices.get(context);
918 if (holder != null) {
919 sd = holder.get(c);
920 if (sd != null) {
921 RuntimeException ex = sd.getUnbindLocation();
922 throw new IllegalArgumentException(
923 "Unbinding Service " + c
924 + " that was already unbound", ex);
925 }
926 }
927 if (context == null) {
928 throw new IllegalStateException("Unbinding Service " + c
929 + " from Context that is no longer in use: " + context);
930 } else {
931 throw new IllegalArgumentException("Service not registered: " + c);
932 }
933 }
934 }
935
936 static final class ServiceDispatcher {
937 private final ServiceDispatcher.InnerConnection mIServiceConnection;
938 private final ServiceConnection mConnection;
939 private final Context mContext;
940 private final Handler mActivityThread;
941 private final ServiceConnectionLeaked mLocation;
942 private final int mFlags;
943
944 private RuntimeException mUnbindLocation;
945
946 private boolean mDied;
Dianne Hackborn5a6ef732011-11-11 12:31:52 -0800947 private boolean mForgotten;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700948
949 private static class ConnectionInfo {
950 IBinder binder;
951 IBinder.DeathRecipient deathMonitor;
952 }
953
954 private static class InnerConnection extends IServiceConnection.Stub {
955 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
956
957 InnerConnection(LoadedApk.ServiceDispatcher sd) {
958 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
959 }
960
961 public void connected(ComponentName name, IBinder service) throws RemoteException {
962 LoadedApk.ServiceDispatcher sd = mDispatcher.get();
963 if (sd != null) {
964 sd.connected(name, service);
965 }
966 }
967 }
968
Dianne Hackbornadd005c2013-07-17 18:43:12 -0700969 private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
970 = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700971
972 ServiceDispatcher(ServiceConnection conn,
973 Context context, Handler activityThread, int flags) {
974 mIServiceConnection = new InnerConnection(this);
975 mConnection = conn;
976 mContext = context;
977 mActivityThread = activityThread;
978 mLocation = new ServiceConnectionLeaked(null);
979 mLocation.fillInStackTrace();
980 mFlags = flags;
981 }
982
983 void validate(Context context, Handler activityThread) {
984 if (mContext != context) {
985 throw new RuntimeException(
986 "ServiceConnection " + mConnection +
987 " registered with differing Context (was " +
988 mContext + " now " + context + ")");
989 }
990 if (mActivityThread != activityThread) {
991 throw new RuntimeException(
992 "ServiceConnection " + mConnection +
993 " registered with differing handler (was " +
994 mActivityThread + " now " + activityThread + ")");
995 }
996 }
997
998 void doForget() {
999 synchronized(this) {
Dianne Hackbornadd005c2013-07-17 18:43:12 -07001000 for (int i=0; i<mActiveConnections.size(); i++) {
1001 ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i);
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001002 ci.binder.unlinkToDeath(ci.deathMonitor, 0);
1003 }
1004 mActiveConnections.clear();
Dianne Hackborn5a6ef732011-11-11 12:31:52 -08001005 mForgotten = true;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001006 }
1007 }
1008
1009 ServiceConnectionLeaked getLocation() {
1010 return mLocation;
1011 }
1012
1013 ServiceConnection getServiceConnection() {
1014 return mConnection;
1015 }
1016
1017 IServiceConnection getIServiceConnection() {
1018 return mIServiceConnection;
1019 }
1020
1021 int getFlags() {
1022 return mFlags;
1023 }
1024
1025 void setUnbindLocation(RuntimeException ex) {
1026 mUnbindLocation = ex;
1027 }
1028
1029 RuntimeException getUnbindLocation() {
1030 return mUnbindLocation;
1031 }
1032
1033 public void connected(ComponentName name, IBinder service) {
1034 if (mActivityThread != null) {
1035 mActivityThread.post(new RunConnection(name, service, 0));
1036 } else {
1037 doConnected(name, service);
1038 }
1039 }
1040
1041 public void death(ComponentName name, IBinder service) {
1042 ServiceDispatcher.ConnectionInfo old;
1043
1044 synchronized (this) {
1045 mDied = true;
1046 old = mActiveConnections.remove(name);
1047 if (old == null || old.binder != service) {
1048 // Death for someone different than who we last
1049 // reported... just ignore it.
1050 return;
1051 }
1052 old.binder.unlinkToDeath(old.deathMonitor, 0);
1053 }
1054
1055 if (mActivityThread != null) {
1056 mActivityThread.post(new RunConnection(name, service, 1));
1057 } else {
1058 doDeath(name, service);
1059 }
1060 }
1061
1062 public void doConnected(ComponentName name, IBinder service) {
1063 ServiceDispatcher.ConnectionInfo old;
1064 ServiceDispatcher.ConnectionInfo info;
1065
1066 synchronized (this) {
Dianne Hackborn5a6ef732011-11-11 12:31:52 -08001067 if (mForgotten) {
1068 // We unbound before receiving the connection; ignore
1069 // any connection received.
1070 return;
1071 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001072 old = mActiveConnections.get(name);
1073 if (old != null && old.binder == service) {
1074 // Huh, already have this one. Oh well!
1075 return;
1076 }
1077
1078 if (service != null) {
1079 // A new service is being connected... set it all up.
1080 mDied = false;
1081 info = new ConnectionInfo();
1082 info.binder = service;
1083 info.deathMonitor = new DeathMonitor(name, service);
1084 try {
1085 service.linkToDeath(info.deathMonitor, 0);
1086 mActiveConnections.put(name, info);
1087 } catch (RemoteException e) {
1088 // This service was dead before we got it... just
1089 // don't do anything with it.
1090 mActiveConnections.remove(name);
1091 return;
1092 }
1093
1094 } else {
1095 // The named service is being disconnected... clean up.
1096 mActiveConnections.remove(name);
1097 }
1098
1099 if (old != null) {
1100 old.binder.unlinkToDeath(old.deathMonitor, 0);
1101 }
1102 }
1103
1104 // If there was an old service, it is not disconnected.
1105 if (old != null) {
1106 mConnection.onServiceDisconnected(name);
1107 }
1108 // If there is a new service, it is now connected.
1109 if (service != null) {
1110 mConnection.onServiceConnected(name, service);
1111 }
1112 }
1113
1114 public void doDeath(ComponentName name, IBinder service) {
1115 mConnection.onServiceDisconnected(name);
1116 }
1117
1118 private final class RunConnection implements Runnable {
1119 RunConnection(ComponentName name, IBinder service, int command) {
1120 mName = name;
1121 mService = service;
1122 mCommand = command;
1123 }
1124
1125 public void run() {
1126 if (mCommand == 0) {
1127 doConnected(mName, mService);
1128 } else if (mCommand == 1) {
1129 doDeath(mName, mService);
1130 }
1131 }
1132
1133 final ComponentName mName;
1134 final IBinder mService;
1135 final int mCommand;
1136 }
1137
1138 private final class DeathMonitor implements IBinder.DeathRecipient
1139 {
1140 DeathMonitor(ComponentName name, IBinder service) {
1141 mName = name;
1142 mService = service;
1143 }
1144
1145 public void binderDied() {
1146 death(mName, mService);
1147 }
1148
1149 final ComponentName mName;
1150 final IBinder mService;
1151 }
1152 }
1153}