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