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