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