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