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