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