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 android.util.ArrayMap; 20 import com.android.internal.util.ArrayUtils; 21 22 import android.content.BroadcastReceiver; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.IIntentReceiver; 26 import android.content.Intent; 27 import android.content.ServiceConnection; 28 import android.content.pm.ApplicationInfo; 29 import android.content.pm.IPackageManager; 30 import android.content.pm.PackageManager; 31 import android.content.res.AssetManager; 32 import android.content.res.CompatibilityInfo; 33 import android.content.res.Resources; 34 import android.os.Bundle; 35 import android.os.Handler; 36 import android.os.IBinder; 37 import android.os.Process; 38 import android.os.RemoteException; 39 import android.os.StrictMode; 40 import android.os.Trace; 41 import android.os.UserHandle; 42 import android.util.AndroidRuntimeException; 43 import android.util.Slog; 44 import android.view.DisplayAdjustments; 45 import android.view.Display; 46 47 import java.io.File; 48 import java.io.IOException; 49 import java.io.InputStream; 50 import java.lang.ref.WeakReference; 51 import java.net.URL; 52 import java.util.Enumeration; 53 54 final class IntentReceiverLeaked extends AndroidRuntimeException { 55 public IntentReceiverLeaked(String msg) { 56 super(msg); 57 } 58 } 59 60 final 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 */ 70 public final class LoadedApk { 71 72 private static final String TAG = "LoadedApk"; 73 74 private final ActivityThread mActivityThread; 75 private 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; 81 private final String mLibDir; 82 private final File mDataDirFile; 83 private final ClassLoader mBaseClassLoader; 84 private final boolean mSecurityViolation; 85 private final boolean mIncludeCode; 86 private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); 87 Resources mResources; 88 private ClassLoader mClassLoader; 89 private Application mApplication; 90 91 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>>(); 99 100 int mClientCount = 0; 101 102 Application getApplication() { 103 return mApplication; 104 } 105 106 /** 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 */ 112 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, 113 CompatibilityInfo compatInfo, ClassLoader baseLoader, 114 boolean securityViolation, boolean includeCode) { 115 mActivityThread = activityThread; 116 mApplicationInfo = aInfo; 117 mPackageName = aInfo.packageName; 118 mAppDir = aInfo.sourceDir; 119 final int myUid = Process.myUid(); 120 mResDir = aInfo.uid == myUid ? aInfo.sourceDir 121 : aInfo.publicSourceDir; 122 if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) { 123 aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid), 124 mPackageName); 125 } 126 mSharedLibraries = aInfo.sharedLibraryFiles; 127 mDataDir = aInfo.dataDir; 128 mDataDirFile = mDataDir != null ? new File(mDataDir) : null; 129 mLibDir = aInfo.nativeLibraryDir; 130 mBaseClassLoader = baseLoader; 131 mSecurityViolation = securityViolation; 132 mIncludeCode = includeCode; 133 mDisplayAdjustments.setCompatibilityInfo(compatInfo); 134 } 135 136 /** 137 * Create information about the system package. 138 * Must call {@link #installSystemApplicationInfo} later. 139 */ 140 LoadedApk(ActivityThread activityThread) { 141 mActivityThread = activityThread; 142 mApplicationInfo = new ApplicationInfo(); 143 mApplicationInfo.packageName = "android"; 144 mPackageName = "android"; 145 mAppDir = null; 146 mResDir = null; 147 mSharedLibraries = null; 148 mDataDir = null; 149 mDataDirFile = null; 150 mLibDir = null; 151 mBaseClassLoader = null; 152 mSecurityViolation = false; 153 mIncludeCode = true; 154 mClassLoader = ClassLoader.getSystemClassLoader(); 155 mResources = Resources.getSystem(); 156 } 157 158 /** 159 * Sets application info about the system package. 160 */ 161 void installSystemApplicationInfo(ApplicationInfo info) { 162 assert info.packageName.equals("android"); 163 mApplicationInfo = info; 164 } 165 166 public String getPackageName() { 167 return mPackageName; 168 } 169 170 public ApplicationInfo getApplicationInfo() { 171 return mApplicationInfo; 172 } 173 174 public boolean isSecurityViolation() { 175 return mSecurityViolation; 176 } 177 178 public CompatibilityInfo getCompatibilityInfo() { 179 return mDisplayAdjustments.getCompatibilityInfo(); 180 } 181 182 public void setCompatibilityInfo(CompatibilityInfo compatInfo) { 183 mDisplayAdjustments.setCompatibilityInfo(compatInfo); 184 } 185 186 /** 187 * Gets the array of shared libraries that are listed as 188 * used by the given package. 189 * 190 * @param packageName the name of the package (note: not its 191 * file name) 192 * @return null-ok; the array of shared libraries, each one 193 * a fully-qualified path 194 */ 195 private static String[] getLibrariesFor(String packageName) { 196 ApplicationInfo ai = null; 197 try { 198 ai = ActivityThread.getPackageManager().getApplicationInfo(packageName, 199 PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId()); 200 } catch (RemoteException e) { 201 throw new AssertionError(e); 202 } 203 204 if (ai == null) { 205 return null; 206 } 207 208 return ai.sharedLibraryFiles; 209 } 210 211 /** 212 * Combines two arrays (of library names) such that they are 213 * concatenated in order but are devoid of duplicates. The 214 * result is a single string with the names of the libraries 215 * separated by colons, or <code>null</code> if both lists 216 * were <code>null</code> or empty. 217 * 218 * @param list1 null-ok; the first list 219 * @param list2 null-ok; the second list 220 * @return null-ok; the combination 221 */ 222 private static String combineLibs(String[] list1, String[] list2) { 223 StringBuilder result = new StringBuilder(300); 224 boolean first = true; 225 226 if (list1 != null) { 227 for (String s : list1) { 228 if (first) { 229 first = false; 230 } else { 231 result.append(':'); 232 } 233 result.append(s); 234 } 235 } 236 237 // Only need to check for duplicates if list1 was non-empty. 238 boolean dupCheck = !first; 239 240 if (list2 != null) { 241 for (String s : list2) { 242 if (dupCheck && ArrayUtils.contains(list1, s)) { 243 continue; 244 } 245 246 if (first) { 247 first = false; 248 } else { 249 result.append(':'); 250 } 251 result.append(s); 252 } 253 } 254 255 return result.toString(); 256 } 257 258 public ClassLoader getClassLoader() { 259 synchronized (this) { 260 if (mClassLoader != null) { 261 return mClassLoader; 262 } 263 264 if (mIncludeCode && !mPackageName.equals("android")) { 265 String zip = mAppDir; 266 String libraryPath = mLibDir; 267 268 /* 269 * The following is a bit of a hack to inject 270 * instrumentation into the system: If the app 271 * being started matches one of the instrumentation names, 272 * then we combine both the "instrumentation" and 273 * "instrumented" app into the path, along with the 274 * concatenation of both apps' shared library lists. 275 */ 276 277 String instrumentationAppDir = 278 mActivityThread.mInstrumentationAppDir; 279 String instrumentationAppLibraryDir = 280 mActivityThread.mInstrumentationAppLibraryDir; 281 String instrumentationAppPackage = 282 mActivityThread.mInstrumentationAppPackage; 283 String instrumentedAppDir = 284 mActivityThread.mInstrumentedAppDir; 285 String instrumentedAppLibraryDir = 286 mActivityThread.mInstrumentedAppLibraryDir; 287 String[] instrumentationLibs = null; 288 289 if (mAppDir.equals(instrumentationAppDir) 290 || mAppDir.equals(instrumentedAppDir)) { 291 zip = instrumentationAppDir + ":" + instrumentedAppDir; 292 libraryPath = instrumentationAppLibraryDir + ":" + instrumentedAppLibraryDir; 293 if (! instrumentedAppDir.equals(instrumentationAppDir)) { 294 instrumentationLibs = 295 getLibrariesFor(instrumentationAppPackage); 296 } 297 } 298 299 if ((mSharedLibraries != null) || 300 (instrumentationLibs != null)) { 301 zip = 302 combineLibs(mSharedLibraries, instrumentationLibs) 303 + ':' + zip; 304 } 305 306 /* 307 * With all the combination done (if necessary, actually 308 * create the class loader. 309 */ 310 311 if (ActivityThread.localLOGV) 312 Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + libraryPath); 313 314 // Temporarily disable logging of disk reads on the Looper thread 315 // as this is early and necessary. 316 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 317 318 mClassLoader = 319 ApplicationLoaders.getDefault().getClassLoader( 320 zip, libraryPath, mBaseClassLoader); 321 initializeJavaContextClassLoader(); 322 323 StrictMode.setThreadPolicy(oldPolicy); 324 } else { 325 if (mBaseClassLoader == null) { 326 mClassLoader = ClassLoader.getSystemClassLoader(); 327 } else { 328 mClassLoader = mBaseClassLoader; 329 } 330 } 331 return mClassLoader; 332 } 333 } 334 335 /** 336 * Setup value for Thread.getContextClassLoader(). If the 337 * package will not run in in a VM with other packages, we set 338 * the Java context ClassLoader to the 339 * PackageInfo.getClassLoader value. However, if this VM can 340 * contain multiple packages, we intead set the Java context 341 * ClassLoader to a proxy that will warn about the use of Java 342 * context ClassLoaders and then fall through to use the 343 * system ClassLoader. 344 * 345 * <p> Note that this is similar to but not the same as the 346 * android.content.Context.getClassLoader(). While both 347 * context class loaders are typically set to the 348 * PathClassLoader used to load the package archive in the 349 * single application per VM case, a single Android process 350 * may contain several Contexts executing on one thread with 351 * their own logical ClassLoaders while the Java context 352 * ClassLoader is a thread local. This is why in the case when 353 * we have multiple packages per VM we do not set the Java 354 * context ClassLoader to an arbitrary but instead warn the 355 * user to set their own if we detect that they are using a 356 * Java library that expects it to be set. 357 */ 358 private void initializeJavaContextClassLoader() { 359 IPackageManager pm = ActivityThread.getPackageManager(); 360 android.content.pm.PackageInfo pi; 361 try { 362 pi = pm.getPackageInfo(mPackageName, 0, UserHandle.myUserId()); 363 } catch (RemoteException e) { 364 throw new IllegalStateException("Unable to get package info for " 365 + mPackageName + "; is system dying?", e); 366 } 367 if (pi == null) { 368 throw new IllegalStateException("Unable to get package info for " 369 + mPackageName + "; is package not installed?"); 370 } 371 /* 372 * Two possible indications that this package could be 373 * sharing its virtual machine with other packages: 374 * 375 * 1.) the sharedUserId attribute is set in the manifest, 376 * indicating a request to share a VM with other 377 * packages with the same sharedUserId. 378 * 379 * 2.) the application element of the manifest has an 380 * attribute specifying a non-default process name, 381 * indicating the desire to run in another packages VM. 382 */ 383 boolean sharedUserIdSet = (pi.sharedUserId != null); 384 boolean processNameNotDefault = 385 (pi.applicationInfo != null && 386 !mPackageName.equals(pi.applicationInfo.processName)); 387 boolean sharable = (sharedUserIdSet || processNameNotDefault); 388 ClassLoader contextClassLoader = 389 (sharable) 390 ? new WarningContextClassLoader() 391 : mClassLoader; 392 Thread.currentThread().setContextClassLoader(contextClassLoader); 393 } 394 395 private static class WarningContextClassLoader extends ClassLoader { 396 397 private static boolean warned = false; 398 399 private void warn(String methodName) { 400 if (warned) { 401 return; 402 } 403 warned = true; 404 Thread.currentThread().setContextClassLoader(getParent()); 405 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " + 406 "The class loader returned by " + 407 "Thread.getContextClassLoader() may fail for processes " + 408 "that host multiple applications. You should explicitly " + 409 "specify a context class loader. For example: " + 410 "Thread.setContextClassLoader(getClass().getClassLoader());"); 411 } 412 413 @Override public URL getResource(String resName) { 414 warn("getResource"); 415 return getParent().getResource(resName); 416 } 417 418 @Override public Enumeration<URL> getResources(String resName) throws IOException { 419 warn("getResources"); 420 return getParent().getResources(resName); 421 } 422 423 @Override public InputStream getResourceAsStream(String resName) { 424 warn("getResourceAsStream"); 425 return getParent().getResourceAsStream(resName); 426 } 427 428 @Override public Class<?> loadClass(String className) throws ClassNotFoundException { 429 warn("loadClass"); 430 return getParent().loadClass(className); 431 } 432 433 @Override public void setClassAssertionStatus(String cname, boolean enable) { 434 warn("setClassAssertionStatus"); 435 getParent().setClassAssertionStatus(cname, enable); 436 } 437 438 @Override public void setPackageAssertionStatus(String pname, boolean enable) { 439 warn("setPackageAssertionStatus"); 440 getParent().setPackageAssertionStatus(pname, enable); 441 } 442 443 @Override public void setDefaultAssertionStatus(boolean enable) { 444 warn("setDefaultAssertionStatus"); 445 getParent().setDefaultAssertionStatus(enable); 446 } 447 448 @Override public void clearAssertionStatus() { 449 warn("clearAssertionStatus"); 450 getParent().clearAssertionStatus(); 451 } 452 } 453 454 public String getAppDir() { 455 return mAppDir; 456 } 457 458 public String getLibDir() { 459 return mLibDir; 460 } 461 462 public String getResDir() { 463 return mResDir; 464 } 465 466 public String getDataDir() { 467 return mDataDir; 468 } 469 470 public File getDataDirFile() { 471 return mDataDirFile; 472 } 473 474 public AssetManager getAssets(ActivityThread mainThread) { 475 return getResources(mainThread).getAssets(); 476 } 477 478 public Resources getResources(ActivityThread mainThread) { 479 if (mResources == null) { 480 mResources = mainThread.getTopLevelResources(mResDir, 481 Display.DEFAULT_DISPLAY, null, this); 482 } 483 return mResources; 484 } 485 486 public Application makeApplication(boolean forceDefaultAppClass, 487 Instrumentation instrumentation) { 488 if (mApplication != null) { 489 return mApplication; 490 } 491 492 Application app = null; 493 494 String appClass = mApplicationInfo.className; 495 if (forceDefaultAppClass || (appClass == null)) { 496 appClass = "android.app.Application"; 497 } 498 499 try { 500 java.lang.ClassLoader cl = getClassLoader(); 501 ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); 502 app = mActivityThread.mInstrumentation.newApplication( 503 cl, appClass, appContext); 504 appContext.setOuterContext(app); 505 } catch (Exception e) { 506 if (!mActivityThread.mInstrumentation.onException(app, e)) { 507 throw new RuntimeException( 508 "Unable to instantiate application " + appClass 509 + ": " + e.toString(), e); 510 } 511 } 512 mActivityThread.mAllApplications.add(app); 513 mApplication = app; 514 515 if (instrumentation != null) { 516 try { 517 instrumentation.callApplicationOnCreate(app); 518 } catch (Exception e) { 519 if (!instrumentation.onException(app, e)) { 520 throw new RuntimeException( 521 "Unable to create application " + app.getClass().getName() 522 + ": " + e.toString(), e); 523 } 524 } 525 } 526 527 return app; 528 } 529 530 public void removeContextRegistrations(Context context, 531 String who, String what) { 532 final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled(); 533 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = 534 mReceivers.remove(context); 535 if (rmap != null) { 536 for (int i=0; i<rmap.size(); i++) { 537 LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i); 538 IntentReceiverLeaked leak = new IntentReceiverLeaked( 539 what + " " + who + " has leaked IntentReceiver " 540 + rd.getIntentReceiver() + " that was " + 541 "originally registered here. Are you missing a " + 542 "call to unregisterReceiver()?"); 543 leak.setStackTrace(rd.getLocation().getStackTrace()); 544 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 545 if (reportRegistrationLeaks) { 546 StrictMode.onIntentReceiverLeaked(leak); 547 } 548 try { 549 ActivityManagerNative.getDefault().unregisterReceiver( 550 rd.getIIntentReceiver()); 551 } catch (RemoteException e) { 552 // system crashed, nothing we can do 553 } 554 } 555 } 556 mUnregisteredReceivers.remove(context); 557 //Slog.i(TAG, "Receiver registrations: " + mReceivers); 558 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = 559 mServices.remove(context); 560 if (smap != null) { 561 for (int i=0; i<smap.size(); i++) { 562 LoadedApk.ServiceDispatcher sd = smap.valueAt(i); 563 ServiceConnectionLeaked leak = new ServiceConnectionLeaked( 564 what + " " + who + " has leaked ServiceConnection " 565 + sd.getServiceConnection() + " that was originally bound here"); 566 leak.setStackTrace(sd.getLocation().getStackTrace()); 567 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 568 if (reportRegistrationLeaks) { 569 StrictMode.onServiceConnectionLeaked(leak); 570 } 571 try { 572 ActivityManagerNative.getDefault().unbindService( 573 sd.getIServiceConnection()); 574 } catch (RemoteException e) { 575 // system crashed, nothing we can do 576 } 577 sd.doForget(); 578 } 579 } 580 mUnboundServices.remove(context); 581 //Slog.i(TAG, "Service registrations: " + mServices); 582 } 583 584 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, 585 Context context, Handler handler, 586 Instrumentation instrumentation, boolean registered) { 587 synchronized (mReceivers) { 588 LoadedApk.ReceiverDispatcher rd = null; 589 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; 590 if (registered) { 591 map = mReceivers.get(context); 592 if (map != null) { 593 rd = map.get(r); 594 } 595 } 596 if (rd == null) { 597 rd = new ReceiverDispatcher(r, context, handler, 598 instrumentation, registered); 599 if (registered) { 600 if (map == null) { 601 map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 602 mReceivers.put(context, map); 603 } 604 map.put(r, rd); 605 } 606 } else { 607 rd.validate(context, handler); 608 } 609 rd.mForgotten = false; 610 return rd.getIIntentReceiver(); 611 } 612 } 613 614 public IIntentReceiver forgetReceiverDispatcher(Context context, 615 BroadcastReceiver r) { 616 synchronized (mReceivers) { 617 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); 618 LoadedApk.ReceiverDispatcher rd = null; 619 if (map != null) { 620 rd = map.get(r); 621 if (rd != null) { 622 map.remove(r); 623 if (map.size() == 0) { 624 mReceivers.remove(context); 625 } 626 if (r.getDebugUnregister()) { 627 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 628 = mUnregisteredReceivers.get(context); 629 if (holder == null) { 630 holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 631 mUnregisteredReceivers.put(context, holder); 632 } 633 RuntimeException ex = new IllegalArgumentException( 634 "Originally unregistered here:"); 635 ex.fillInStackTrace(); 636 rd.setUnregisterLocation(ex); 637 holder.put(r, rd); 638 } 639 rd.mForgotten = true; 640 return rd.getIIntentReceiver(); 641 } 642 } 643 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 644 = mUnregisteredReceivers.get(context); 645 if (holder != null) { 646 rd = holder.get(r); 647 if (rd != null) { 648 RuntimeException ex = rd.getUnregisterLocation(); 649 throw new IllegalArgumentException( 650 "Unregistering Receiver " + r 651 + " that was already unregistered", ex); 652 } 653 } 654 if (context == null) { 655 throw new IllegalStateException("Unbinding Receiver " + r 656 + " from Context that is no longer in use: " + context); 657 } else { 658 throw new IllegalArgumentException("Receiver not registered: " + r); 659 } 660 661 } 662 } 663 664 static final class ReceiverDispatcher { 665 666 final static class InnerReceiver extends IIntentReceiver.Stub { 667 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; 668 final LoadedApk.ReceiverDispatcher mStrongRef; 669 670 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { 671 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); 672 mStrongRef = strong ? rd : null; 673 } 674 public void performReceive(Intent intent, int resultCode, String data, 675 Bundle extras, boolean ordered, boolean sticky, int sendingUser) { 676 LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); 677 if (ActivityThread.DEBUG_BROADCAST) { 678 int seq = intent.getIntExtra("seq", -1); 679 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq 680 + " to " + (rd != null ? rd.mReceiver : null)); 681 } 682 if (rd != null) { 683 rd.performReceive(intent, resultCode, data, extras, 684 ordered, sticky, sendingUser); 685 } else { 686 // The activity manager dispatched a broadcast to a registered 687 // receiver in this process, but before it could be delivered the 688 // receiver was unregistered. Acknowledge the broadcast on its 689 // behalf so that the system's broadcast sequence can continue. 690 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 691 "Finishing broadcast to unregistered receiver"); 692 IActivityManager mgr = ActivityManagerNative.getDefault(); 693 try { 694 if (extras != null) { 695 extras.setAllowFds(false); 696 } 697 mgr.finishReceiver(this, resultCode, data, extras, false); 698 } catch (RemoteException e) { 699 Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver"); 700 } 701 } 702 } 703 } 704 705 final IIntentReceiver.Stub mIIntentReceiver; 706 final BroadcastReceiver mReceiver; 707 final Context mContext; 708 final Handler mActivityThread; 709 final Instrumentation mInstrumentation; 710 final boolean mRegistered; 711 final IntentReceiverLeaked mLocation; 712 RuntimeException mUnregisterLocation; 713 boolean mForgotten; 714 715 final class Args extends BroadcastReceiver.PendingResult implements Runnable { 716 private Intent mCurIntent; 717 private final boolean mOrdered; 718 719 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, 720 boolean ordered, boolean sticky, int sendingUser) { 721 super(resultCode, resultData, resultExtras, 722 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, 723 ordered, sticky, mIIntentReceiver.asBinder(), sendingUser); 724 mCurIntent = intent; 725 mOrdered = ordered; 726 } 727 728 public void run() { 729 final BroadcastReceiver receiver = mReceiver; 730 final boolean ordered = mOrdered; 731 732 if (ActivityThread.DEBUG_BROADCAST) { 733 int seq = mCurIntent.getIntExtra("seq", -1); 734 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction() 735 + " seq=" + seq + " to " + mReceiver); 736 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered 737 + " mOrderedHint=" + ordered); 738 } 739 740 final IActivityManager mgr = ActivityManagerNative.getDefault(); 741 final Intent intent = mCurIntent; 742 mCurIntent = null; 743 744 if (receiver == null || mForgotten) { 745 if (mRegistered && ordered) { 746 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 747 "Finishing null broadcast to " + mReceiver); 748 sendFinished(mgr); 749 } 750 return; 751 } 752 753 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg"); 754 try { 755 ClassLoader cl = mReceiver.getClass().getClassLoader(); 756 intent.setExtrasClassLoader(cl); 757 setExtrasClassLoader(cl); 758 receiver.setPendingResult(this); 759 receiver.onReceive(mContext, intent); 760 } catch (Exception e) { 761 if (mRegistered && ordered) { 762 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 763 "Finishing failed broadcast to " + mReceiver); 764 sendFinished(mgr); 765 } 766 if (mInstrumentation == null || 767 !mInstrumentation.onException(mReceiver, e)) { 768 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 769 throw new RuntimeException( 770 "Error receiving broadcast " + intent 771 + " in " + mReceiver, e); 772 } 773 } 774 775 if (receiver.getPendingResult() != null) { 776 finish(); 777 } 778 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 779 } 780 } 781 782 ReceiverDispatcher(BroadcastReceiver receiver, Context context, 783 Handler activityThread, Instrumentation instrumentation, 784 boolean registered) { 785 if (activityThread == null) { 786 throw new NullPointerException("Handler must not be null"); 787 } 788 789 mIIntentReceiver = new InnerReceiver(this, !registered); 790 mReceiver = receiver; 791 mContext = context; 792 mActivityThread = activityThread; 793 mInstrumentation = instrumentation; 794 mRegistered = registered; 795 mLocation = new IntentReceiverLeaked(null); 796 mLocation.fillInStackTrace(); 797 } 798 799 void validate(Context context, Handler activityThread) { 800 if (mContext != context) { 801 throw new IllegalStateException( 802 "Receiver " + mReceiver + 803 " registered with differing Context (was " + 804 mContext + " now " + context + ")"); 805 } 806 if (mActivityThread != activityThread) { 807 throw new IllegalStateException( 808 "Receiver " + mReceiver + 809 " registered with differing handler (was " + 810 mActivityThread + " now " + activityThread + ")"); 811 } 812 } 813 814 IntentReceiverLeaked getLocation() { 815 return mLocation; 816 } 817 818 BroadcastReceiver getIntentReceiver() { 819 return mReceiver; 820 } 821 822 IIntentReceiver getIIntentReceiver() { 823 return mIIntentReceiver; 824 } 825 826 void setUnregisterLocation(RuntimeException ex) { 827 mUnregisterLocation = ex; 828 } 829 830 RuntimeException getUnregisterLocation() { 831 return mUnregisterLocation; 832 } 833 834 public void performReceive(Intent intent, int resultCode, String data, 835 Bundle extras, boolean ordered, boolean sticky, int sendingUser) { 836 if (ActivityThread.DEBUG_BROADCAST) { 837 int seq = intent.getIntExtra("seq", -1); 838 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq 839 + " to " + mReceiver); 840 } 841 Args args = new Args(intent, resultCode, data, extras, ordered, 842 sticky, sendingUser); 843 if (!mActivityThread.post(args)) { 844 if (mRegistered && ordered) { 845 IActivityManager mgr = ActivityManagerNative.getDefault(); 846 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 847 "Finishing sync broadcast to " + mReceiver); 848 args.sendFinished(mgr); 849 } 850 } 851 } 852 853 } 854 855 public final IServiceConnection getServiceDispatcher(ServiceConnection c, 856 Context context, Handler handler, int flags) { 857 synchronized (mServices) { 858 LoadedApk.ServiceDispatcher sd = null; 859 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); 860 if (map != null) { 861 sd = map.get(c); 862 } 863 if (sd == null) { 864 sd = new ServiceDispatcher(c, context, handler, flags); 865 if (map == null) { 866 map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 867 mServices.put(context, map); 868 } 869 map.put(c, sd); 870 } else { 871 sd.validate(context, handler); 872 } 873 return sd.getIServiceConnection(); 874 } 875 } 876 877 public final IServiceConnection forgetServiceDispatcher(Context context, 878 ServiceConnection c) { 879 synchronized (mServices) { 880 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map 881 = mServices.get(context); 882 LoadedApk.ServiceDispatcher sd = null; 883 if (map != null) { 884 sd = map.get(c); 885 if (sd != null) { 886 map.remove(c); 887 sd.doForget(); 888 if (map.size() == 0) { 889 mServices.remove(context); 890 } 891 if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) { 892 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 893 = mUnboundServices.get(context); 894 if (holder == null) { 895 holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 896 mUnboundServices.put(context, holder); 897 } 898 RuntimeException ex = new IllegalArgumentException( 899 "Originally unbound here:"); 900 ex.fillInStackTrace(); 901 sd.setUnbindLocation(ex); 902 holder.put(c, sd); 903 } 904 return sd.getIServiceConnection(); 905 } 906 } 907 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 908 = mUnboundServices.get(context); 909 if (holder != null) { 910 sd = holder.get(c); 911 if (sd != null) { 912 RuntimeException ex = sd.getUnbindLocation(); 913 throw new IllegalArgumentException( 914 "Unbinding Service " + c 915 + " that was already unbound", ex); 916 } 917 } 918 if (context == null) { 919 throw new IllegalStateException("Unbinding Service " + c 920 + " from Context that is no longer in use: " + context); 921 } else { 922 throw new IllegalArgumentException("Service not registered: " + c); 923 } 924 } 925 } 926 927 static final class ServiceDispatcher { 928 private final ServiceDispatcher.InnerConnection mIServiceConnection; 929 private final ServiceConnection mConnection; 930 private final Context mContext; 931 private final Handler mActivityThread; 932 private final ServiceConnectionLeaked mLocation; 933 private final int mFlags; 934 935 private RuntimeException mUnbindLocation; 936 937 private boolean mDied; 938 private boolean mForgotten; 939 940 private static class ConnectionInfo { 941 IBinder binder; 942 IBinder.DeathRecipient deathMonitor; 943 } 944 945 private static class InnerConnection extends IServiceConnection.Stub { 946 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; 947 948 InnerConnection(LoadedApk.ServiceDispatcher sd) { 949 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); 950 } 951 952 public void connected(ComponentName name, IBinder service) throws RemoteException { 953 LoadedApk.ServiceDispatcher sd = mDispatcher.get(); 954 if (sd != null) { 955 sd.connected(name, service); 956 } 957 } 958 } 959 960 private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections 961 = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>(); 962 963 ServiceDispatcher(ServiceConnection conn, 964 Context context, Handler activityThread, int flags) { 965 mIServiceConnection = new InnerConnection(this); 966 mConnection = conn; 967 mContext = context; 968 mActivityThread = activityThread; 969 mLocation = new ServiceConnectionLeaked(null); 970 mLocation.fillInStackTrace(); 971 mFlags = flags; 972 } 973 974 void validate(Context context, Handler activityThread) { 975 if (mContext != context) { 976 throw new RuntimeException( 977 "ServiceConnection " + mConnection + 978 " registered with differing Context (was " + 979 mContext + " now " + context + ")"); 980 } 981 if (mActivityThread != activityThread) { 982 throw new RuntimeException( 983 "ServiceConnection " + mConnection + 984 " registered with differing handler (was " + 985 mActivityThread + " now " + activityThread + ")"); 986 } 987 } 988 989 void doForget() { 990 synchronized(this) { 991 for (int i=0; i<mActiveConnections.size(); i++) { 992 ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i); 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