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