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