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 IllegalStateException("Unable to get package info for " 366 + mPackageName + "; is system dying?", e); 367 } 368 if (pi == null) { 369 throw new IllegalStateException("Unable to get package info for " 370 + mPackageName + "; is package not installed?"); 371 } 372 /* 373 * Two possible indications that this package could be 374 * sharing its virtual machine with other packages: 375 * 376 * 1.) the sharedUserId attribute is set in the manifest, 377 * indicating a request to share a VM with other 378 * packages with the same sharedUserId. 379 * 380 * 2.) the application element of the manifest has an 381 * attribute specifying a non-default process name, 382 * indicating the desire to run in another packages VM. 383 */ 384 boolean sharedUserIdSet = (pi.sharedUserId != null); 385 boolean processNameNotDefault = 386 (pi.applicationInfo != null && 387 !mPackageName.equals(pi.applicationInfo.processName)); 388 boolean sharable = (sharedUserIdSet || processNameNotDefault); 389 ClassLoader contextClassLoader = 390 (sharable) 391 ? new WarningContextClassLoader() 392 : mClassLoader; 393 Thread.currentThread().setContextClassLoader(contextClassLoader); 394 } 395 396 private static class WarningContextClassLoader extends ClassLoader { 397 398 private static boolean warned = false; 399 warn(String methodName)400 private void warn(String methodName) { 401 if (warned) { 402 return; 403 } 404 warned = true; 405 Thread.currentThread().setContextClassLoader(getParent()); 406 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " + 407 "The class loader returned by " + 408 "Thread.getContextClassLoader() may fail for processes " + 409 "that host multiple applications. You should explicitly " + 410 "specify a context class loader. For example: " + 411 "Thread.setContextClassLoader(getClass().getClassLoader());"); 412 } 413 getResource(String resName)414 @Override public URL getResource(String resName) { 415 warn("getResource"); 416 return getParent().getResource(resName); 417 } 418 getResources(String resName)419 @Override public Enumeration<URL> getResources(String resName) throws IOException { 420 warn("getResources"); 421 return getParent().getResources(resName); 422 } 423 getResourceAsStream(String resName)424 @Override public InputStream getResourceAsStream(String resName) { 425 warn("getResourceAsStream"); 426 return getParent().getResourceAsStream(resName); 427 } 428 loadClass(String className)429 @Override public Class<?> loadClass(String className) throws ClassNotFoundException { 430 warn("loadClass"); 431 return getParent().loadClass(className); 432 } 433 setClassAssertionStatus(String cname, boolean enable)434 @Override public void setClassAssertionStatus(String cname, boolean enable) { 435 warn("setClassAssertionStatus"); 436 getParent().setClassAssertionStatus(cname, enable); 437 } 438 setPackageAssertionStatus(String pname, boolean enable)439 @Override public void setPackageAssertionStatus(String pname, boolean enable) { 440 warn("setPackageAssertionStatus"); 441 getParent().setPackageAssertionStatus(pname, enable); 442 } 443 setDefaultAssertionStatus(boolean enable)444 @Override public void setDefaultAssertionStatus(boolean enable) { 445 warn("setDefaultAssertionStatus"); 446 getParent().setDefaultAssertionStatus(enable); 447 } 448 clearAssertionStatus()449 @Override public void clearAssertionStatus() { 450 warn("clearAssertionStatus"); 451 getParent().clearAssertionStatus(); 452 } 453 } 454 getAppDir()455 public String getAppDir() { 456 return mAppDir; 457 } 458 getLibDir()459 public String getLibDir() { 460 return mLibDir; 461 } 462 getResDir()463 public String getResDir() { 464 return mResDir; 465 } 466 getDataDir()467 public String getDataDir() { 468 return mDataDir; 469 } 470 getDataDirFile()471 public File getDataDirFile() { 472 return mDataDirFile; 473 } 474 getAssets(ActivityThread mainThread)475 public AssetManager getAssets(ActivityThread mainThread) { 476 return getResources(mainThread).getAssets(); 477 } 478 getResources(ActivityThread mainThread)479 public Resources getResources(ActivityThread mainThread) { 480 if (mResources == null) { 481 mResources = mainThread.getTopLevelResources(mResDir, 482 Display.DEFAULT_DISPLAY, null, this); 483 } 484 return mResources; 485 } 486 makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation)487 public Application makeApplication(boolean forceDefaultAppClass, 488 Instrumentation instrumentation) { 489 if (mApplication != null) { 490 return mApplication; 491 } 492 493 Application app = null; 494 495 String appClass = mApplicationInfo.className; 496 if (forceDefaultAppClass || (appClass == null)) { 497 appClass = "android.app.Application"; 498 } 499 500 try { 501 java.lang.ClassLoader cl = getClassLoader(); 502 ContextImpl appContext = new ContextImpl(); 503 appContext.init(this, null, mActivityThread); 504 app = mActivityThread.mInstrumentation.newApplication( 505 cl, appClass, appContext); 506 appContext.setOuterContext(app); 507 } catch (Exception e) { 508 if (!mActivityThread.mInstrumentation.onException(app, e)) { 509 throw new RuntimeException( 510 "Unable to instantiate application " + appClass 511 + ": " + e.toString(), e); 512 } 513 } 514 mActivityThread.mAllApplications.add(app); 515 mApplication = app; 516 517 if (instrumentation != null) { 518 try { 519 instrumentation.callApplicationOnCreate(app); 520 } catch (Exception e) { 521 if (!instrumentation.onException(app, e)) { 522 throw new RuntimeException( 523 "Unable to create application " + app.getClass().getName() 524 + ": " + e.toString(), e); 525 } 526 } 527 } 528 529 return app; 530 } 531 removeContextRegistrations(Context context, String who, String what)532 public void removeContextRegistrations(Context context, 533 String who, String what) { 534 final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled(); 535 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = 536 mReceivers.remove(context); 537 if (rmap != null) { 538 Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator(); 539 while (it.hasNext()) { 540 LoadedApk.ReceiverDispatcher rd = it.next(); 541 IntentReceiverLeaked leak = new IntentReceiverLeaked( 542 what + " " + who + " has leaked IntentReceiver " 543 + rd.getIntentReceiver() + " that was " + 544 "originally registered here. Are you missing a " + 545 "call to unregisterReceiver()?"); 546 leak.setStackTrace(rd.getLocation().getStackTrace()); 547 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 548 if (reportRegistrationLeaks) { 549 StrictMode.onIntentReceiverLeaked(leak); 550 } 551 try { 552 ActivityManagerNative.getDefault().unregisterReceiver( 553 rd.getIIntentReceiver()); 554 } catch (RemoteException e) { 555 // system crashed, nothing we can do 556 } 557 } 558 } 559 mUnregisteredReceivers.remove(context); 560 //Slog.i(TAG, "Receiver registrations: " + mReceivers); 561 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = 562 mServices.remove(context); 563 if (smap != null) { 564 Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator(); 565 while (it.hasNext()) { 566 LoadedApk.ServiceDispatcher sd = it.next(); 567 ServiceConnectionLeaked leak = new ServiceConnectionLeaked( 568 what + " " + who + " has leaked ServiceConnection " 569 + sd.getServiceConnection() + " that was originally bound here"); 570 leak.setStackTrace(sd.getLocation().getStackTrace()); 571 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 572 if (reportRegistrationLeaks) { 573 StrictMode.onServiceConnectionLeaked(leak); 574 } 575 try { 576 ActivityManagerNative.getDefault().unbindService( 577 sd.getIServiceConnection()); 578 } catch (RemoteException e) { 579 // system crashed, nothing we can do 580 } 581 sd.doForget(); 582 } 583 } 584 mUnboundServices.remove(context); 585 //Slog.i(TAG, "Service registrations: " + mServices); 586 } 587 getReceiverDispatcher(BroadcastReceiver r, Context context, Handler handler, Instrumentation instrumentation, boolean registered)588 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, 589 Context context, Handler handler, 590 Instrumentation instrumentation, boolean registered) { 591 synchronized (mReceivers) { 592 LoadedApk.ReceiverDispatcher rd = null; 593 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; 594 if (registered) { 595 map = mReceivers.get(context); 596 if (map != null) { 597 rd = map.get(r); 598 } 599 } 600 if (rd == null) { 601 rd = new ReceiverDispatcher(r, context, handler, 602 instrumentation, registered); 603 if (registered) { 604 if (map == null) { 605 map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 606 mReceivers.put(context, map); 607 } 608 map.put(r, rd); 609 } 610 } else { 611 rd.validate(context, handler); 612 } 613 rd.mForgotten = false; 614 return rd.getIIntentReceiver(); 615 } 616 } 617 forgetReceiverDispatcher(Context context, BroadcastReceiver r)618 public IIntentReceiver forgetReceiverDispatcher(Context context, 619 BroadcastReceiver r) { 620 synchronized (mReceivers) { 621 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); 622 LoadedApk.ReceiverDispatcher rd = null; 623 if (map != null) { 624 rd = map.get(r); 625 if (rd != null) { 626 map.remove(r); 627 if (map.size() == 0) { 628 mReceivers.remove(context); 629 } 630 if (r.getDebugUnregister()) { 631 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 632 = mUnregisteredReceivers.get(context); 633 if (holder == null) { 634 holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 635 mUnregisteredReceivers.put(context, holder); 636 } 637 RuntimeException ex = new IllegalArgumentException( 638 "Originally unregistered here:"); 639 ex.fillInStackTrace(); 640 rd.setUnregisterLocation(ex); 641 holder.put(r, rd); 642 } 643 rd.mForgotten = true; 644 return rd.getIIntentReceiver(); 645 } 646 } 647 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 648 = mUnregisteredReceivers.get(context); 649 if (holder != null) { 650 rd = holder.get(r); 651 if (rd != null) { 652 RuntimeException ex = rd.getUnregisterLocation(); 653 throw new IllegalArgumentException( 654 "Unregistering Receiver " + r 655 + " that was already unregistered", ex); 656 } 657 } 658 if (context == null) { 659 throw new IllegalStateException("Unbinding Receiver " + r 660 + " from Context that is no longer in use: " + context); 661 } else { 662 throw new IllegalArgumentException("Receiver not registered: " + r); 663 } 664 665 } 666 } 667 668 static final class ReceiverDispatcher { 669 670 final static class InnerReceiver extends IIntentReceiver.Stub { 671 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; 672 final LoadedApk.ReceiverDispatcher mStrongRef; 673 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong)674 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { 675 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); 676 mStrongRef = strong ? rd : null; 677 } performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser)678 public void performReceive(Intent intent, int resultCode, String data, 679 Bundle extras, boolean ordered, boolean sticky, int sendingUser) { 680 LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); 681 if (ActivityThread.DEBUG_BROADCAST) { 682 int seq = intent.getIntExtra("seq", -1); 683 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq 684 + " to " + (rd != null ? rd.mReceiver : null)); 685 } 686 if (rd != null) { 687 rd.performReceive(intent, resultCode, data, extras, 688 ordered, sticky, sendingUser); 689 } else { 690 // The activity manager dispatched a broadcast to a registered 691 // receiver in this process, but before it could be delivered the 692 // receiver was unregistered. Acknowledge the broadcast on its 693 // behalf so that the system's broadcast sequence can continue. 694 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 695 "Finishing broadcast to unregistered receiver"); 696 IActivityManager mgr = ActivityManagerNative.getDefault(); 697 try { 698 if (extras != null) { 699 extras.setAllowFds(false); 700 } 701 mgr.finishReceiver(this, resultCode, data, extras, false); 702 } catch (RemoteException e) { 703 Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver"); 704 } 705 } 706 } 707 } 708 709 final IIntentReceiver.Stub mIIntentReceiver; 710 final BroadcastReceiver mReceiver; 711 final Context mContext; 712 final Handler mActivityThread; 713 final Instrumentation mInstrumentation; 714 final boolean mRegistered; 715 final IntentReceiverLeaked mLocation; 716 RuntimeException mUnregisterLocation; 717 boolean mForgotten; 718 719 final class Args extends BroadcastReceiver.PendingResult implements Runnable { 720 private Intent mCurIntent; 721 private final boolean mOrdered; 722 Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, int sendingUser)723 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, 724 boolean ordered, boolean sticky, int sendingUser) { 725 super(resultCode, resultData, resultExtras, 726 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, 727 ordered, sticky, mIIntentReceiver.asBinder(), sendingUser); 728 mCurIntent = intent; 729 mOrdered = ordered; 730 } 731 run()732 public void run() { 733 final BroadcastReceiver receiver = mReceiver; 734 final boolean ordered = mOrdered; 735 736 if (ActivityThread.DEBUG_BROADCAST) { 737 int seq = mCurIntent.getIntExtra("seq", -1); 738 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction() 739 + " seq=" + seq + " to " + mReceiver); 740 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered 741 + " mOrderedHint=" + ordered); 742 } 743 744 final IActivityManager mgr = ActivityManagerNative.getDefault(); 745 final Intent intent = mCurIntent; 746 mCurIntent = null; 747 748 if (receiver == null || mForgotten) { 749 if (mRegistered && ordered) { 750 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 751 "Finishing null broadcast to " + mReceiver); 752 sendFinished(mgr); 753 } 754 return; 755 } 756 757 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg"); 758 try { 759 ClassLoader cl = mReceiver.getClass().getClassLoader(); 760 intent.setExtrasClassLoader(cl); 761 setExtrasClassLoader(cl); 762 receiver.setPendingResult(this); 763 receiver.onReceive(mContext, intent); 764 } catch (Exception e) { 765 if (mRegistered && ordered) { 766 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 767 "Finishing failed broadcast to " + mReceiver); 768 sendFinished(mgr); 769 } 770 if (mInstrumentation == null || 771 !mInstrumentation.onException(mReceiver, e)) { 772 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 773 throw new RuntimeException( 774 "Error receiving broadcast " + intent 775 + " in " + mReceiver, e); 776 } 777 } 778 779 if (receiver.getPendingResult() != null) { 780 finish(); 781 } 782 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 783 } 784 } 785 ReceiverDispatcher(BroadcastReceiver receiver, Context context, Handler activityThread, Instrumentation instrumentation, boolean registered)786 ReceiverDispatcher(BroadcastReceiver receiver, Context context, 787 Handler activityThread, Instrumentation instrumentation, 788 boolean registered) { 789 if (activityThread == null) { 790 throw new NullPointerException("Handler must not be null"); 791 } 792 793 mIIntentReceiver = new InnerReceiver(this, !registered); 794 mReceiver = receiver; 795 mContext = context; 796 mActivityThread = activityThread; 797 mInstrumentation = instrumentation; 798 mRegistered = registered; 799 mLocation = new IntentReceiverLeaked(null); 800 mLocation.fillInStackTrace(); 801 } 802 validate(Context context, Handler activityThread)803 void validate(Context context, Handler activityThread) { 804 if (mContext != context) { 805 throw new IllegalStateException( 806 "Receiver " + mReceiver + 807 " registered with differing Context (was " + 808 mContext + " now " + context + ")"); 809 } 810 if (mActivityThread != activityThread) { 811 throw new IllegalStateException( 812 "Receiver " + mReceiver + 813 " registered with differing handler (was " + 814 mActivityThread + " now " + activityThread + ")"); 815 } 816 } 817 getLocation()818 IntentReceiverLeaked getLocation() { 819 return mLocation; 820 } 821 getIntentReceiver()822 BroadcastReceiver getIntentReceiver() { 823 return mReceiver; 824 } 825 getIIntentReceiver()826 IIntentReceiver getIIntentReceiver() { 827 return mIIntentReceiver; 828 } 829 setUnregisterLocation(RuntimeException ex)830 void setUnregisterLocation(RuntimeException ex) { 831 mUnregisterLocation = ex; 832 } 833 getUnregisterLocation()834 RuntimeException getUnregisterLocation() { 835 return mUnregisterLocation; 836 } 837 performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser)838 public void performReceive(Intent intent, int resultCode, String data, 839 Bundle extras, boolean ordered, boolean sticky, int sendingUser) { 840 if (ActivityThread.DEBUG_BROADCAST) { 841 int seq = intent.getIntExtra("seq", -1); 842 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq 843 + " to " + mReceiver); 844 } 845 Args args = new Args(intent, resultCode, data, extras, ordered, 846 sticky, sendingUser); 847 if (!mActivityThread.post(args)) { 848 if (mRegistered && ordered) { 849 IActivityManager mgr = ActivityManagerNative.getDefault(); 850 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 851 "Finishing sync broadcast to " + mReceiver); 852 args.sendFinished(mgr); 853 } 854 } 855 } 856 857 } 858 getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags)859 public final IServiceConnection getServiceDispatcher(ServiceConnection c, 860 Context context, Handler handler, int flags) { 861 synchronized (mServices) { 862 LoadedApk.ServiceDispatcher sd = null; 863 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); 864 if (map != null) { 865 sd = map.get(c); 866 } 867 if (sd == null) { 868 sd = new ServiceDispatcher(c, context, handler, flags); 869 if (map == null) { 870 map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 871 mServices.put(context, map); 872 } 873 map.put(c, sd); 874 } else { 875 sd.validate(context, handler); 876 } 877 return sd.getIServiceConnection(); 878 } 879 } 880 forgetServiceDispatcher(Context context, ServiceConnection c)881 public final IServiceConnection forgetServiceDispatcher(Context context, 882 ServiceConnection c) { 883 synchronized (mServices) { 884 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map 885 = mServices.get(context); 886 LoadedApk.ServiceDispatcher sd = null; 887 if (map != null) { 888 sd = map.get(c); 889 if (sd != null) { 890 map.remove(c); 891 sd.doForget(); 892 if (map.size() == 0) { 893 mServices.remove(context); 894 } 895 if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) { 896 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 897 = mUnboundServices.get(context); 898 if (holder == null) { 899 holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 900 mUnboundServices.put(context, holder); 901 } 902 RuntimeException ex = new IllegalArgumentException( 903 "Originally unbound here:"); 904 ex.fillInStackTrace(); 905 sd.setUnbindLocation(ex); 906 holder.put(c, sd); 907 } 908 return sd.getIServiceConnection(); 909 } 910 } 911 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 912 = mUnboundServices.get(context); 913 if (holder != null) { 914 sd = holder.get(c); 915 if (sd != null) { 916 RuntimeException ex = sd.getUnbindLocation(); 917 throw new IllegalArgumentException( 918 "Unbinding Service " + c 919 + " that was already unbound", ex); 920 } 921 } 922 if (context == null) { 923 throw new IllegalStateException("Unbinding Service " + c 924 + " from Context that is no longer in use: " + context); 925 } else { 926 throw new IllegalArgumentException("Service not registered: " + c); 927 } 928 } 929 } 930 931 static final class ServiceDispatcher { 932 private final ServiceDispatcher.InnerConnection mIServiceConnection; 933 private final ServiceConnection mConnection; 934 private final Context mContext; 935 private final Handler mActivityThread; 936 private final ServiceConnectionLeaked mLocation; 937 private final int mFlags; 938 939 private RuntimeException mUnbindLocation; 940 941 private boolean mDied; 942 private boolean mForgotten; 943 944 private static class ConnectionInfo { 945 IBinder binder; 946 IBinder.DeathRecipient deathMonitor; 947 } 948 949 private static class InnerConnection extends IServiceConnection.Stub { 950 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; 951 InnerConnection(LoadedApk.ServiceDispatcher sd)952 InnerConnection(LoadedApk.ServiceDispatcher sd) { 953 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); 954 } 955 connected(ComponentName name, IBinder service)956 public void connected(ComponentName name, IBinder service) throws RemoteException { 957 LoadedApk.ServiceDispatcher sd = mDispatcher.get(); 958 if (sd != null) { 959 sd.connected(name, service); 960 } 961 } 962 } 963 964 private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections 965 = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>(); 966 ServiceDispatcher(ServiceConnection conn, Context context, Handler activityThread, int flags)967 ServiceDispatcher(ServiceConnection conn, 968 Context context, Handler activityThread, int flags) { 969 mIServiceConnection = new InnerConnection(this); 970 mConnection = conn; 971 mContext = context; 972 mActivityThread = activityThread; 973 mLocation = new ServiceConnectionLeaked(null); 974 mLocation.fillInStackTrace(); 975 mFlags = flags; 976 } 977 validate(Context context, Handler activityThread)978 void validate(Context context, Handler activityThread) { 979 if (mContext != context) { 980 throw new RuntimeException( 981 "ServiceConnection " + mConnection + 982 " registered with differing Context (was " + 983 mContext + " now " + context + ")"); 984 } 985 if (mActivityThread != activityThread) { 986 throw new RuntimeException( 987 "ServiceConnection " + mConnection + 988 " registered with differing handler (was " + 989 mActivityThread + " now " + activityThread + ")"); 990 } 991 } 992 doForget()993 void doForget() { 994 synchronized(this) { 995 Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator(); 996 while (it.hasNext()) { 997 ServiceDispatcher.ConnectionInfo ci = it.next(); 998 ci.binder.unlinkToDeath(ci.deathMonitor, 0); 999 } 1000 mActiveConnections.clear(); 1001 mForgotten = true; 1002 } 1003 } 1004 getLocation()1005 ServiceConnectionLeaked getLocation() { 1006 return mLocation; 1007 } 1008 getServiceConnection()1009 ServiceConnection getServiceConnection() { 1010 return mConnection; 1011 } 1012 getIServiceConnection()1013 IServiceConnection getIServiceConnection() { 1014 return mIServiceConnection; 1015 } 1016 getFlags()1017 int getFlags() { 1018 return mFlags; 1019 } 1020 setUnbindLocation(RuntimeException ex)1021 void setUnbindLocation(RuntimeException ex) { 1022 mUnbindLocation = ex; 1023 } 1024 getUnbindLocation()1025 RuntimeException getUnbindLocation() { 1026 return mUnbindLocation; 1027 } 1028 connected(ComponentName name, IBinder service)1029 public void connected(ComponentName name, IBinder service) { 1030 if (mActivityThread != null) { 1031 mActivityThread.post(new RunConnection(name, service, 0)); 1032 } else { 1033 doConnected(name, service); 1034 } 1035 } 1036 death(ComponentName name, IBinder service)1037 public void death(ComponentName name, IBinder service) { 1038 ServiceDispatcher.ConnectionInfo old; 1039 1040 synchronized (this) { 1041 mDied = true; 1042 old = mActiveConnections.remove(name); 1043 if (old == null || old.binder != service) { 1044 // Death for someone different than who we last 1045 // reported... just ignore it. 1046 return; 1047 } 1048 old.binder.unlinkToDeath(old.deathMonitor, 0); 1049 } 1050 1051 if (mActivityThread != null) { 1052 mActivityThread.post(new RunConnection(name, service, 1)); 1053 } else { 1054 doDeath(name, service); 1055 } 1056 } 1057 doConnected(ComponentName name, IBinder service)1058 public void doConnected(ComponentName name, IBinder service) { 1059 ServiceDispatcher.ConnectionInfo old; 1060 ServiceDispatcher.ConnectionInfo info; 1061 1062 synchronized (this) { 1063 if (mForgotten) { 1064 // We unbound before receiving the connection; ignore 1065 // any connection received. 1066 return; 1067 } 1068 old = mActiveConnections.get(name); 1069 if (old != null && old.binder == service) { 1070 // Huh, already have this one. Oh well! 1071 return; 1072 } 1073 1074 if (service != null) { 1075 // A new service is being connected... set it all up. 1076 mDied = false; 1077 info = new ConnectionInfo(); 1078 info.binder = service; 1079 info.deathMonitor = new DeathMonitor(name, service); 1080 try { 1081 service.linkToDeath(info.deathMonitor, 0); 1082 mActiveConnections.put(name, info); 1083 } catch (RemoteException e) { 1084 // This service was dead before we got it... just 1085 // don't do anything with it. 1086 mActiveConnections.remove(name); 1087 return; 1088 } 1089 1090 } else { 1091 // The named service is being disconnected... clean up. 1092 mActiveConnections.remove(name); 1093 } 1094 1095 if (old != null) { 1096 old.binder.unlinkToDeath(old.deathMonitor, 0); 1097 } 1098 } 1099 1100 // If there was an old service, it is not disconnected. 1101 if (old != null) { 1102 mConnection.onServiceDisconnected(name); 1103 } 1104 // If there is a new service, it is now connected. 1105 if (service != null) { 1106 mConnection.onServiceConnected(name, service); 1107 } 1108 } 1109 doDeath(ComponentName name, IBinder service)1110 public void doDeath(ComponentName name, IBinder service) { 1111 mConnection.onServiceDisconnected(name); 1112 } 1113 1114 private final class RunConnection implements Runnable { RunConnection(ComponentName name, IBinder service, int command)1115 RunConnection(ComponentName name, IBinder service, int command) { 1116 mName = name; 1117 mService = service; 1118 mCommand = command; 1119 } 1120 run()1121 public void run() { 1122 if (mCommand == 0) { 1123 doConnected(mName, mService); 1124 } else if (mCommand == 1) { 1125 doDeath(mName, mService); 1126 } 1127 } 1128 1129 final ComponentName mName; 1130 final IBinder mService; 1131 final int mCommand; 1132 } 1133 1134 private final class DeathMonitor implements IBinder.DeathRecipient 1135 { DeathMonitor(ComponentName name, IBinder service)1136 DeathMonitor(ComponentName name, IBinder service) { 1137 mName = name; 1138 mService = service; 1139 } 1140 binderDied()1141 public void binderDied() { 1142 death(mName, mService); 1143 } 1144 1145 final ComponentName mName; 1146 final IBinder mService; 1147 } 1148 } 1149 } 1150