1 /* 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 17 package android.app; 18 19 import com.android.internal.util.ArrayUtils; 20 21 import android.content.BroadcastReceiver; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.IIntentReceiver; 25 import android.content.Intent; 26 import android.content.ServiceConnection; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.IPackageManager; 29 import android.content.pm.PackageManager; 30 import android.content.res.AssetManager; 31 import android.content.res.CompatibilityInfo; 32 import android.content.res.Resources; 33 import android.os.Bundle; 34 import android.os.Handler; 35 import android.os.IBinder; 36 import android.os.Process; 37 import android.os.RemoteException; 38 import android.os.StrictMode; 39 import android.os.Trace; 40 import android.os.UserHandle; 41 import android.util.AndroidRuntimeException; 42 import android.util.Slog; 43 import android.view.CompatibilityInfoHolder; 44 import android.view.Display; 45 46 import java.io.File; 47 import java.io.IOException; 48 import java.io.InputStream; 49 import java.lang.ref.WeakReference; 50 import java.net.URL; 51 import java.util.Enumeration; 52 import java.util.HashMap; 53 import java.util.Iterator; 54 55 final class IntentReceiverLeaked extends AndroidRuntimeException { 56 public IntentReceiverLeaked(String msg) { 57 super(msg); 58 } 59 } 60 61 final 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 */ 71 public final class LoadedApk { 72 73 private static final String TAG = "LoadedApk"; 74 75 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; 82 private final String mLibDir; 83 private final File mDataDirFile; 84 private final ClassLoader mBaseClassLoader; 85 private final boolean mSecurityViolation; 86 private final boolean mIncludeCode; 87 public final CompatibilityInfoHolder mCompatibilityInfo = new CompatibilityInfoHolder(); 88 Resources mResources; 89 private ClassLoader mClassLoader; 90 private Application mApplication; 91 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 107 /** 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 */ 113 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, 114 CompatibilityInfo compatInfo, 115 ActivityThread mainThread, ClassLoader baseLoader, 116 boolean securityViolation, boolean includeCode) { 117 mActivityThread = activityThread; 118 mApplicationInfo = aInfo; 119 mPackageName = aInfo.packageName; 120 mAppDir = aInfo.sourceDir; 121 final int myUid = Process.myUid(); 122 mResDir = aInfo.uid == myUid ? aInfo.sourceDir 123 : aInfo.publicSourceDir; 124 if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) { 125 aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid), 126 mPackageName); 127 } 128 mSharedLibraries = aInfo.sharedLibraryFiles; 129 mDataDir = aInfo.dataDir; 130 mDataDirFile = mDataDir != null ? new File(mDataDir) : null; 131 mLibDir = aInfo.nativeLibraryDir; 132 mBaseClassLoader = baseLoader; 133 mSecurityViolation = securityViolation; 134 mIncludeCode = includeCode; 135 mCompatibilityInfo.set(compatInfo); 136 137 if (mAppDir == null) { 138 if (ActivityThread.mSystemContext == null) { 139 ActivityThread.mSystemContext = 140 ContextImpl.createSystemContext(mainThread); 141 ActivityThread.mSystemContext.getResources().updateConfiguration( 142 mainThread.getConfiguration(), 143 mainThread.getDisplayMetricsLocked( 144 Display.DEFAULT_DISPLAY, compatInfo), 145 compatInfo); 146 //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, 156 Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) { 157 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; 166 mLibDir = null; 167 mBaseClassLoader = null; 168 mSecurityViolation = false; 169 mIncludeCode = true; 170 mClassLoader = systemContext.getClassLoader(); 171 mResources = systemContext.getResources(); 172 mCompatibilityInfo.set(compatInfo); 173 } 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, 200 PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId()); 201 } 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; 267 String libraryPath = mLibDir; 268 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; 280 String instrumentationAppLibraryDir = 281 mActivityThread.mInstrumentationAppLibraryDir; 282 String instrumentationAppPackage = 283 mActivityThread.mInstrumentationAppPackage; 284 String instrumentedAppDir = 285 mActivityThread.mInstrumentedAppDir; 286 String instrumentedAppLibraryDir = 287 mActivityThread.mInstrumentedAppLibraryDir; 288 String[] instrumentationLibs = null; 289 290 if (mAppDir.equals(instrumentationAppDir) 291 || mAppDir.equals(instrumentedAppDir)) { 292 zip = instrumentationAppDir + ":" + instrumentedAppDir; 293 libraryPath = instrumentationAppLibraryDir + ":" + instrumentedAppLibraryDir; 294 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 312 if (ActivityThread.localLOGV) 313 Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + libraryPath); 314 315 // Temporarily disable logging of disk reads on the Looper thread 316 // as this is early and necessary. 317 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 318 319 mClassLoader = 320 ApplicationLoaders.getDefault().getClassLoader( 321 zip, libraryPath, mBaseClassLoader); 322 initializeJavaContextClassLoader(); 323 324 StrictMode.setThreadPolicy(oldPolicy); 325 } 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 { 363 pi = pm.getPackageInfo(mPackageName, 0, UserHandle.myUserId()); 364 } catch (RemoteException e) { 365 throw new AssertionError(e); 366 } 367 /* 368 * Two possible indications that this package could be 369 * sharing its virtual machine with other packages: 370 * 371 * 1.) the sharedUserId attribute is set in the manifest, 372 * indicating a request to share a VM with other 373 * packages with the same sharedUserId. 374 * 375 * 2.) the application element of the manifest has an 376 * attribute specifying a non-default process name, 377 * indicating the desire to run in another packages VM. 378 */ 379 boolean sharedUserIdSet = (pi.sharedUserId != null); 380 boolean processNameNotDefault = 381 (pi.applicationInfo != null && 382 !mPackageName.equals(pi.applicationInfo.processName)); 383 boolean sharable = (sharedUserIdSet || processNameNotDefault); 384 ClassLoader contextClassLoader = 385 (sharable) 386 ? new WarningContextClassLoader() 387 : mClassLoader; 388 Thread.currentThread().setContextClassLoader(contextClassLoader); 389 } 390 391 private static class WarningContextClassLoader extends ClassLoader { 392 393 private static boolean warned = false; 394 395 private void warn(String methodName) { 396 if (warned) { 397 return; 398 } 399 warned = true; 400 Thread.currentThread().setContextClassLoader(getParent()); 401 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " + 402 "The class loader returned by " + 403 "Thread.getContextClassLoader() may fail for processes " + 404 "that host multiple applications. You should explicitly " + 405 "specify a context class loader. For example: " + 406 "Thread.setContextClassLoader(getClass().getClassLoader());"); 407 } 408 409 @Override public URL getResource(String resName) { 410 warn("getResource"); 411 return getParent().getResource(resName); 412 } 413 414 @Override public Enumeration<URL> getResources(String resName) throws IOException { 415 warn("getResources"); 416 return getParent().getResources(resName); 417 } 418 419 @Override public InputStream getResourceAsStream(String resName) { 420 warn("getResourceAsStream"); 421 return getParent().getResourceAsStream(resName); 422 } 423 424 @Override public Class<?> loadClass(String className) throws ClassNotFoundException { 425 warn("loadClass"); 426 return getParent().loadClass(className); 427 } 428 429 @Override public void setClassAssertionStatus(String cname, boolean enable) { 430 warn("setClassAssertionStatus"); 431 getParent().setClassAssertionStatus(cname, enable); 432 } 433 434 @Override public void setPackageAssertionStatus(String pname, boolean enable) { 435 warn("setPackageAssertionStatus"); 436 getParent().setPackageAssertionStatus(pname, enable); 437 } 438 439 @Override public void setDefaultAssertionStatus(boolean enable) { 440 warn("setDefaultAssertionStatus"); 441 getParent().setDefaultAssertionStatus(enable); 442 } 443 444 @Override public void clearAssertionStatus() { 445 warn("clearAssertionStatus"); 446 getParent().clearAssertionStatus(); 447 } 448 } 449 450 public String getAppDir() { 451 return mAppDir; 452 } 453 454 public String getLibDir() { 455 return mLibDir; 456 } 457 458 public String getResDir() { 459 return mResDir; 460 } 461 462 public String getDataDir() { 463 return mDataDir; 464 } 465 466 public File getDataDirFile() { 467 return mDataDirFile; 468 } 469 470 public AssetManager getAssets(ActivityThread mainThread) { 471 return getResources(mainThread).getAssets(); 472 } 473 474 public Resources getResources(ActivityThread mainThread) { 475 if (mResources == null) { 476 mResources = mainThread.getTopLevelResources(mResDir, 477 Display.DEFAULT_DISPLAY, null, this); 478 } 479 return mResources; 480 } 481 482 public Application makeApplication(boolean forceDefaultAppClass, 483 Instrumentation instrumentation) { 484 if (mApplication != null) { 485 return mApplication; 486 } 487 488 Application app = null; 489 490 String appClass = mApplicationInfo.className; 491 if (forceDefaultAppClass || (appClass == null)) { 492 appClass = "android.app.Application"; 493 } 494 495 try { 496 java.lang.ClassLoader cl = getClassLoader(); 497 ContextImpl appContext = new ContextImpl(); 498 appContext.init(this, null, mActivityThread); 499 app = mActivityThread.mInstrumentation.newApplication( 500 cl, appClass, appContext); 501 appContext.setOuterContext(app); 502 } catch (Exception e) { 503 if (!mActivityThread.mInstrumentation.onException(app, e)) { 504 throw new RuntimeException( 505 "Unable to instantiate application " + appClass 506 + ": " + e.toString(), e); 507 } 508 } 509 mActivityThread.mAllApplications.add(app); 510 mApplication = app; 511 512 if (instrumentation != null) { 513 try { 514 instrumentation.callApplicationOnCreate(app); 515 } catch (Exception e) { 516 if (!instrumentation.onException(app, e)) { 517 throw new RuntimeException( 518 "Unable to create application " + app.getClass().getName() 519 + ": " + e.toString(), e); 520 } 521 } 522 } 523 524 return app; 525 } 526 527 public void removeContextRegistrations(Context context, 528 String who, String what) { 529 final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled(); 530 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = 531 mReceivers.remove(context); 532 if (rmap != null) { 533 Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator(); 534 while (it.hasNext()) { 535 LoadedApk.ReceiverDispatcher rd = it.next(); 536 IntentReceiverLeaked leak = new IntentReceiverLeaked( 537 what + " " + who + " has leaked IntentReceiver " 538 + rd.getIntentReceiver() + " that was " + 539 "originally registered here. Are you missing a " + 540 "call to unregisterReceiver()?"); 541 leak.setStackTrace(rd.getLocation().getStackTrace()); 542 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 543 if (reportRegistrationLeaks) { 544 StrictMode.onIntentReceiverLeaked(leak); 545 } 546 try { 547 ActivityManagerNative.getDefault().unregisterReceiver( 548 rd.getIIntentReceiver()); 549 } catch (RemoteException e) { 550 // system crashed, nothing we can do 551 } 552 } 553 } 554 mUnregisteredReceivers.remove(context); 555 //Slog.i(TAG, "Receiver registrations: " + mReceivers); 556 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = 557 mServices.remove(context); 558 if (smap != null) { 559 Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator(); 560 while (it.hasNext()) { 561 LoadedApk.ServiceDispatcher sd = it.next(); 562 ServiceConnectionLeaked leak = new ServiceConnectionLeaked( 563 what + " " + who + " has leaked ServiceConnection " 564 + sd.getServiceConnection() + " that was originally bound here"); 565 leak.setStackTrace(sd.getLocation().getStackTrace()); 566 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 567 if (reportRegistrationLeaks) { 568 StrictMode.onServiceConnectionLeaked(leak); 569 } 570 try { 571 ActivityManagerNative.getDefault().unbindService( 572 sd.getIServiceConnection()); 573 } catch (RemoteException e) { 574 // system crashed, nothing we can do 575 } 576 sd.doForget(); 577 } 578 } 579 mUnboundServices.remove(context); 580 //Slog.i(TAG, "Service registrations: " + mServices); 581 } 582 583 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, 584 Context context, Handler handler, 585 Instrumentation instrumentation, boolean registered) { 586 synchronized (mReceivers) { 587 LoadedApk.ReceiverDispatcher rd = null; 588 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; 589 if (registered) { 590 map = mReceivers.get(context); 591 if (map != null) { 592 rd = map.get(r); 593 } 594 } 595 if (rd == null) { 596 rd = new ReceiverDispatcher(r, context, handler, 597 instrumentation, registered); 598 if (registered) { 599 if (map == null) { 600 map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 601 mReceivers.put(context, map); 602 } 603 map.put(r, rd); 604 } 605 } else { 606 rd.validate(context, handler); 607 } 608 rd.mForgotten = false; 609 return rd.getIIntentReceiver(); 610 } 611 } 612 613 public IIntentReceiver forgetReceiverDispatcher(Context context, 614 BroadcastReceiver r) { 615 synchronized (mReceivers) { 616 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); 617 LoadedApk.ReceiverDispatcher rd = null; 618 if (map != null) { 619 rd = map.get(r); 620 if (rd != null) { 621 map.remove(r); 622 if (map.size() == 0) { 623 mReceivers.remove(context); 624 } 625 if (r.getDebugUnregister()) { 626 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 627 = mUnregisteredReceivers.get(context); 628 if (holder == null) { 629 holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 630 mUnregisteredReceivers.put(context, holder); 631 } 632 RuntimeException ex = new IllegalArgumentException( 633 "Originally unregistered here:"); 634 ex.fillInStackTrace(); 635 rd.setUnregisterLocation(ex); 636 holder.put(r, rd); 637 } 638 rd.mForgotten = true; 639 return rd.getIIntentReceiver(); 640 } 641 } 642 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 643 = mUnregisteredReceivers.get(context); 644 if (holder != null) { 645 rd = holder.get(r); 646 if (rd != null) { 647 RuntimeException ex = rd.getUnregisterLocation(); 648 throw new IllegalArgumentException( 649 "Unregistering Receiver " + r 650 + " that was already unregistered", ex); 651 } 652 } 653 if (context == null) { 654 throw new IllegalStateException("Unbinding Receiver " + r 655 + " from Context that is no longer in use: " + context); 656 } else { 657 throw new IllegalArgumentException("Receiver not registered: " + r); 658 } 659 660 } 661 } 662 663 static final class ReceiverDispatcher { 664 665 final static class InnerReceiver extends IIntentReceiver.Stub { 666 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; 667 final LoadedApk.ReceiverDispatcher mStrongRef; 668 669 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { 670 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); 671 mStrongRef = strong ? rd : null; 672 } 673 public void performReceive(Intent intent, int resultCode, String data, 674 Bundle extras, boolean ordered, boolean sticky, int sendingUser) { 675 LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); 676 if (ActivityThread.DEBUG_BROADCAST) { 677 int seq = intent.getIntExtra("seq", -1); 678 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq 679 + " to " + (rd != null ? rd.mReceiver : null)); 680 } 681 if (rd != null) { 682 rd.performReceive(intent, resultCode, data, extras, 683 ordered, sticky, sendingUser); 684 } else { 685 // The activity manager dispatched a broadcast to a registered 686 // receiver in this process, but before it could be delivered the 687 // receiver was unregistered. Acknowledge the broadcast on its 688 // behalf so that the system's broadcast sequence can continue. 689 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 690 "Finishing broadcast to unregistered receiver"); 691 IActivityManager mgr = ActivityManagerNative.getDefault(); 692 try { 693 if (extras != null) { 694 extras.setAllowFds(false); 695 } 696 mgr.finishReceiver(this, resultCode, data, extras, false); 697 } catch (RemoteException e) { 698 Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver"); 699 } 700 } 701 } 702 } 703 704 final IIntentReceiver.Stub mIIntentReceiver; 705 final BroadcastReceiver mReceiver; 706 final Context mContext; 707 final Handler mActivityThread; 708 final Instrumentation mInstrumentation; 709 final boolean mRegistered; 710 final IntentReceiverLeaked mLocation; 711 RuntimeException mUnregisterLocation; 712 boolean mForgotten; 713 714 final class Args extends BroadcastReceiver.PendingResult implements Runnable { 715 private Intent mCurIntent; 716 private final boolean mOrdered; 717 718 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, 719 boolean ordered, boolean sticky, int sendingUser) { 720 super(resultCode, resultData, resultExtras, 721 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, 722 ordered, sticky, mIIntentReceiver.asBinder(), sendingUser); 723 mCurIntent = intent; 724 mOrdered = ordered; 725 } 726 727 public void run() { 728 final BroadcastReceiver receiver = mReceiver; 729 final boolean ordered = mOrdered; 730 731 if (ActivityThread.DEBUG_BROADCAST) { 732 int seq = mCurIntent.getIntExtra("seq", -1); 733 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction() 734 + " seq=" + seq + " to " + mReceiver); 735 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered 736 + " mOrderedHint=" + ordered); 737 } 738 739 final IActivityManager mgr = ActivityManagerNative.getDefault(); 740 final Intent intent = mCurIntent; 741 mCurIntent = null; 742 743 if (receiver == null || mForgotten) { 744 if (mRegistered && ordered) { 745 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 746 "Finishing null broadcast to " + mReceiver); 747 sendFinished(mgr); 748 } 749 return; 750 } 751 752 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg"); 753 try { 754 ClassLoader cl = mReceiver.getClass().getClassLoader(); 755 intent.setExtrasClassLoader(cl); 756 setExtrasClassLoader(cl); 757 receiver.setPendingResult(this); 758 receiver.onReceive(mContext, intent); 759 } catch (Exception e) { 760 if (mRegistered && ordered) { 761 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 762 "Finishing failed broadcast to " + mReceiver); 763 sendFinished(mgr); 764 } 765 if (mInstrumentation == null || 766 !mInstrumentation.onException(mReceiver, e)) { 767 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 768 throw new RuntimeException( 769 "Error receiving broadcast " + intent 770 + " in " + mReceiver, e); 771 } 772 } 773 774 if (receiver.getPendingResult() != null) { 775 finish(); 776 } 777 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 778 } 779 } 780 781 ReceiverDispatcher(BroadcastReceiver receiver, Context context, 782 Handler activityThread, Instrumentation instrumentation, 783 boolean registered) { 784 if (activityThread == null) { 785 throw new NullPointerException("Handler must not be null"); 786 } 787 788 mIIntentReceiver = new InnerReceiver(this, !registered); 789 mReceiver = receiver; 790 mContext = context; 791 mActivityThread = activityThread; 792 mInstrumentation = instrumentation; 793 mRegistered = registered; 794 mLocation = new IntentReceiverLeaked(null); 795 mLocation.fillInStackTrace(); 796 } 797 798 void validate(Context context, Handler activityThread) { 799 if (mContext != context) { 800 throw new IllegalStateException( 801 "Receiver " + mReceiver + 802 " registered with differing Context (was " + 803 mContext + " now " + context + ")"); 804 } 805 if (mActivityThread != activityThread) { 806 throw new IllegalStateException( 807 "Receiver " + mReceiver + 808 " registered with differing handler (was " + 809 mActivityThread + " now " + activityThread + ")"); 810 } 811 } 812 813 IntentReceiverLeaked getLocation() { 814 return mLocation; 815 } 816 817 BroadcastReceiver getIntentReceiver() { 818 return mReceiver; 819 } 820 821 IIntentReceiver getIIntentReceiver() { 822 return mIIntentReceiver; 823 } 824 825 void setUnregisterLocation(RuntimeException ex) { 826 mUnregisterLocation = ex; 827 } 828 829 RuntimeException getUnregisterLocation() { 830 return mUnregisterLocation; 831 } 832 833 public void performReceive(Intent intent, int resultCode, String data, 834 Bundle extras, boolean ordered, boolean sticky, int sendingUser) { 835 if (ActivityThread.DEBUG_BROADCAST) { 836 int seq = intent.getIntExtra("seq", -1); 837 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq 838 + " to " + mReceiver); 839 } 840 Args args = new Args(intent, resultCode, data, extras, ordered, 841 sticky, sendingUser); 842 if (!mActivityThread.post(args)) { 843 if (mRegistered && ordered) { 844 IActivityManager mgr = ActivityManagerNative.getDefault(); 845 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 846 "Finishing sync broadcast to " + mReceiver); 847 args.sendFinished(mgr); 848 } 849 } 850 } 851 852 } 853 854 public final IServiceConnection getServiceDispatcher(ServiceConnection c, 855 Context context, Handler handler, int flags) { 856 synchronized (mServices) { 857 LoadedApk.ServiceDispatcher sd = null; 858 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); 859 if (map != null) { 860 sd = map.get(c); 861 } 862 if (sd == null) { 863 sd = new ServiceDispatcher(c, context, handler, flags); 864 if (map == null) { 865 map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 866 mServices.put(context, map); 867 } 868 map.put(c, sd); 869 } else { 870 sd.validate(context, handler); 871 } 872 return sd.getIServiceConnection(); 873 } 874 } 875 876 public final IServiceConnection forgetServiceDispatcher(Context context, 877 ServiceConnection c) { 878 synchronized (mServices) { 879 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map 880 = mServices.get(context); 881 LoadedApk.ServiceDispatcher sd = null; 882 if (map != null) { 883 sd = map.get(c); 884 if (sd != null) { 885 map.remove(c); 886 sd.doForget(); 887 if (map.size() == 0) { 888 mServices.remove(context); 889 } 890 if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) { 891 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 892 = mUnboundServices.get(context); 893 if (holder == null) { 894 holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 895 mUnboundServices.put(context, holder); 896 } 897 RuntimeException ex = new IllegalArgumentException( 898 "Originally unbound here:"); 899 ex.fillInStackTrace(); 900 sd.setUnbindLocation(ex); 901 holder.put(c, sd); 902 } 903 return sd.getIServiceConnection(); 904 } 905 } 906 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 907 = mUnboundServices.get(context); 908 if (holder != null) { 909 sd = holder.get(c); 910 if (sd != null) { 911 RuntimeException ex = sd.getUnbindLocation(); 912 throw new IllegalArgumentException( 913 "Unbinding Service " + c 914 + " that was already unbound", ex); 915 } 916 } 917 if (context == null) { 918 throw new IllegalStateException("Unbinding Service " + c 919 + " from Context that is no longer in use: " + context); 920 } else { 921 throw new IllegalArgumentException("Service not registered: " + c); 922 } 923 } 924 } 925 926 static final class ServiceDispatcher { 927 private final ServiceDispatcher.InnerConnection mIServiceConnection; 928 private final ServiceConnection mConnection; 929 private final Context mContext; 930 private final Handler mActivityThread; 931 private final ServiceConnectionLeaked mLocation; 932 private final int mFlags; 933 934 private RuntimeException mUnbindLocation; 935 936 private boolean mDied; 937 private boolean mForgotten; 938 939 private static class ConnectionInfo { 940 IBinder binder; 941 IBinder.DeathRecipient deathMonitor; 942 } 943 944 private static class InnerConnection extends IServiceConnection.Stub { 945 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; 946 947 InnerConnection(LoadedApk.ServiceDispatcher sd) { 948 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); 949 } 950 951 public void connected(ComponentName name, IBinder service) throws RemoteException { 952 LoadedApk.ServiceDispatcher sd = mDispatcher.get(); 953 if (sd != null) { 954 sd.connected(name, service); 955 } 956 } 957 } 958 959 private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections 960 = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>(); 961 962 ServiceDispatcher(ServiceConnection conn, 963 Context context, Handler activityThread, int flags) { 964 mIServiceConnection = new InnerConnection(this); 965 mConnection = conn; 966 mContext = context; 967 mActivityThread = activityThread; 968 mLocation = new ServiceConnectionLeaked(null); 969 mLocation.fillInStackTrace(); 970 mFlags = flags; 971 } 972 973 void validate(Context context, Handler activityThread) { 974 if (mContext != context) { 975 throw new RuntimeException( 976 "ServiceConnection " + mConnection + 977 " registered with differing Context (was " + 978 mContext + " now " + context + ")"); 979 } 980 if (mActivityThread != activityThread) { 981 throw new RuntimeException( 982 "ServiceConnection " + mConnection + 983 " registered with differing handler (was " + 984 mActivityThread + " now " + activityThread + ")"); 985 } 986 } 987 988 void doForget() { 989 synchronized(this) { 990 Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator(); 991 while (it.hasNext()) { 992 ServiceDispatcher.ConnectionInfo ci = it.next(); 993 ci.binder.unlinkToDeath(ci.deathMonitor, 0); 994 } 995 mActiveConnections.clear(); 996 mForgotten = true; 997 } 998 } 999 1000 ServiceConnectionLeaked getLocation() { 1001 return mLocation; 1002 } 1003 1004 ServiceConnection getServiceConnection() { 1005 return mConnection; 1006 } 1007 1008 IServiceConnection getIServiceConnection() { 1009 return mIServiceConnection; 1010 } 1011 1012 int getFlags() { 1013 return mFlags; 1014 } 1015 1016 void setUnbindLocation(RuntimeException ex) { 1017 mUnbindLocation = ex; 1018 } 1019 1020 RuntimeException getUnbindLocation() { 1021 return mUnbindLocation; 1022 } 1023 1024 public void connected(ComponentName name, IBinder service) { 1025 if (mActivityThread != null) { 1026 mActivityThread.post(new RunConnection(name, service, 0)); 1027 } else { 1028 doConnected(name, service); 1029 } 1030 } 1031 1032 public void death(ComponentName name, IBinder service) { 1033 ServiceDispatcher.ConnectionInfo old; 1034 1035 synchronized (this) { 1036 mDied = true; 1037 old = mActiveConnections.remove(name); 1038 if (old == null || old.binder != service) { 1039 // Death for someone different than who we last 1040 // reported... just ignore it. 1041 return; 1042 } 1043 old.binder.unlinkToDeath(old.deathMonitor, 0); 1044 } 1045 1046 if (mActivityThread != null) { 1047 mActivityThread.post(new RunConnection(name, service, 1)); 1048 } else { 1049 doDeath(name, service); 1050 } 1051 } 1052 1053 public void doConnected(ComponentName name, IBinder service) { 1054 ServiceDispatcher.ConnectionInfo old; 1055 ServiceDispatcher.ConnectionInfo info; 1056 1057 synchronized (this) { 1058 if (mForgotten) { 1059 // We unbound before receiving the connection; ignore 1060 // any connection received. 1061 return; 1062 } 1063 old = mActiveConnections.get(name); 1064 if (old != null && old.binder == service) { 1065 // Huh, already have this one. Oh well! 1066 return; 1067 } 1068 1069 if (service != null) { 1070 // A new service is being connected... set it all up. 1071 mDied = false; 1072 info = new ConnectionInfo(); 1073 info.binder = service; 1074 info.deathMonitor = new DeathMonitor(name, service); 1075 try { 1076 service.linkToDeath(info.deathMonitor, 0); 1077 mActiveConnections.put(name, info); 1078 } catch (RemoteException e) { 1079 // This service was dead before we got it... just 1080 // don't do anything with it. 1081 mActiveConnections.remove(name); 1082 return; 1083 } 1084 1085 } else { 1086 // The named service is being disconnected... clean up. 1087 mActiveConnections.remove(name); 1088 } 1089 1090 if (old != null) { 1091 old.binder.unlinkToDeath(old.deathMonitor, 0); 1092 } 1093 } 1094 1095 // If there was an old service, it is not disconnected. 1096 if (old != null) { 1097 mConnection.onServiceDisconnected(name); 1098 } 1099 // If there is a new service, it is now connected. 1100 if (service != null) { 1101 mConnection.onServiceConnected(name, service); 1102 } 1103 } 1104 1105 public void doDeath(ComponentName name, IBinder service) { 1106 mConnection.onServiceDisconnected(name); 1107 } 1108 1109 private final class RunConnection implements Runnable { 1110 RunConnection(ComponentName name, IBinder service, int command) { 1111 mName = name; 1112 mService = service; 1113 mCommand = command; 1114 } 1115 1116 public void run() { 1117 if (mCommand == 0) { 1118 doConnected(mName, mService); 1119 } else if (mCommand == 1) { 1120 doDeath(mName, mService); 1121 } 1122 } 1123 1124 final ComponentName mName; 1125 final IBinder mService; 1126 final int mCommand; 1127 } 1128 1129 private final class DeathMonitor implements IBinder.DeathRecipient 1130 { 1131 DeathMonitor(ComponentName name, IBinder service) { 1132 mName = name; 1133 mService = service; 1134 } 1135 1136 public void binderDied() { 1137 death(mName, mService); 1138 } 1139 1140 final ComponentName mName; 1141 final IBinder mService; 1142 } 1143 } 1144 } 1145