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