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