ActivityThread.java revision b4bc78b16a05554c57508b488e21dd8eca4e13e6
1/*
2 * Copyright (C) 2006 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.app.backup.BackupAgent;
20import android.content.BroadcastReceiver;
21import android.content.ComponentCallbacks;
22import android.content.ComponentName;
23import android.content.ContentProvider;
24import android.content.Context;
25import android.content.IContentProvider;
26import android.content.Intent;
27import android.content.IIntentReceiver;
28import android.content.ServiceConnection;
29import android.content.pm.ActivityInfo;
30import android.content.pm.ApplicationInfo;
31import android.content.pm.IPackageManager;
32import android.content.pm.InstrumentationInfo;
33import android.content.pm.PackageManager;
34import android.content.pm.ProviderInfo;
35import android.content.pm.ServiceInfo;
36import android.content.res.AssetManager;
37import android.content.res.CompatibilityInfo;
38import android.content.res.Configuration;
39import android.content.res.Resources;
40import android.database.sqlite.SQLiteDatabase;
41import android.database.sqlite.SQLiteDebug;
42import android.database.sqlite.SQLiteDebug.DbStats;
43import android.graphics.Bitmap;
44import android.graphics.Canvas;
45import android.os.Bundle;
46import android.os.Debug;
47import android.os.Handler;
48import android.os.IBinder;
49import android.os.Looper;
50import android.os.Message;
51import android.os.MessageQueue;
52import android.os.ParcelFileDescriptor;
53import android.os.Process;
54import android.os.RemoteException;
55import android.os.ServiceManager;
56import android.os.SystemClock;
57import android.util.AndroidRuntimeException;
58import android.util.Config;
59import android.util.DisplayMetrics;
60import android.util.EventLog;
61import android.util.Log;
62import android.util.Slog;
63import android.view.Display;
64import android.view.View;
65import android.view.ViewDebug;
66import android.view.ViewManager;
67import android.view.ViewRoot;
68import android.view.Window;
69import android.view.WindowManager;
70import android.view.WindowManagerImpl;
71
72import com.android.internal.os.BinderInternal;
73import com.android.internal.os.RuntimeInit;
74import com.android.internal.os.SamplingProfilerIntegration;
75import com.android.internal.util.ArrayUtils;
76
77import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
78
79import java.io.File;
80import java.io.FileDescriptor;
81import java.io.FileOutputStream;
82import java.io.IOException;
83import java.io.InputStream;
84import java.io.PrintWriter;
85import java.lang.ref.WeakReference;
86import java.net.URL;
87import java.util.ArrayList;
88import java.util.Enumeration;
89import java.util.HashMap;
90import java.util.Iterator;
91import java.util.List;
92import java.util.Locale;
93import java.util.Map;
94import java.util.TimeZone;
95import java.util.regex.Pattern;
96
97import dalvik.system.SamplingProfiler;
98
99final class IntentReceiverLeaked extends AndroidRuntimeException {
100    public IntentReceiverLeaked(String msg) {
101        super(msg);
102    }
103}
104
105final class ServiceConnectionLeaked extends AndroidRuntimeException {
106    public ServiceConnectionLeaked(String msg) {
107        super(msg);
108    }
109}
110
111final class SuperNotCalledException extends AndroidRuntimeException {
112    public SuperNotCalledException(String msg) {
113        super(msg);
114    }
115}
116
117/**
118 * This manages the execution of the main thread in an
119 * application process, scheduling and executing activities,
120 * broadcasts, and other operations on it as the activity
121 * manager requests.
122 *
123 * {@hide}
124 */
125public final class ActivityThread {
126    private static final String TAG = "ActivityThread";
127    private static final boolean DEBUG = false;
128    private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
129    private static final boolean DEBUG_BROADCAST = false;
130    private static final boolean DEBUG_RESULTS = false;
131    private static final boolean DEBUG_BACKUP = false;
132    private static final boolean DEBUG_CONFIGURATION = false;
133    private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
134    private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
135    private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
136    private static final int LOG_ON_PAUSE_CALLED = 30021;
137    private static final int LOG_ON_RESUME_CALLED = 30022;
138
139
140    public static final ActivityThread currentActivityThread() {
141        return (ActivityThread)sThreadLocal.get();
142    }
143
144    public static final String currentPackageName()
145    {
146        ActivityThread am = currentActivityThread();
147        return (am != null && am.mBoundApplication != null)
148            ? am.mBoundApplication.processName : null;
149    }
150
151    public static IPackageManager getPackageManager() {
152        if (sPackageManager != null) {
153            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
154            return sPackageManager;
155        }
156        IBinder b = ServiceManager.getService("package");
157        //Slog.v("PackageManager", "default service binder = " + b);
158        sPackageManager = IPackageManager.Stub.asInterface(b);
159        //Slog.v("PackageManager", "default service = " + sPackageManager);
160        return sPackageManager;
161    }
162
163    DisplayMetrics getDisplayMetricsLocked(boolean forceUpdate) {
164        if (mDisplayMetrics != null && !forceUpdate) {
165            return mDisplayMetrics;
166        }
167        if (mDisplay == null) {
168            WindowManager wm = WindowManagerImpl.getDefault();
169            mDisplay = wm.getDefaultDisplay();
170        }
171        DisplayMetrics metrics = mDisplayMetrics = new DisplayMetrics();
172        mDisplay.getMetrics(metrics);
173        //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
174        //        + metrics.heightPixels + " den=" + metrics.density
175        //        + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
176        return metrics;
177    }
178
179    /**
180     * Creates the top level Resources for applications with the given compatibility info.
181     *
182     * @param resDir the resource directory.
183     * @param compInfo the compability info. It will use the default compatibility info when it's
184     * null.
185     */
186    Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo) {
187        ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale);
188        Resources r;
189        synchronized (mPackages) {
190            // Resources is app scale dependent.
191            if (false) {
192                Slog.w(TAG, "getTopLevelResources: " + resDir + " / "
193                        + compInfo.applicationScale);
194            }
195            WeakReference<Resources> wr = mActiveResources.get(key);
196            r = wr != null ? wr.get() : null;
197            //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
198            if (r != null && r.getAssets().isUpToDate()) {
199                if (false) {
200                    Slog.w(TAG, "Returning cached resources " + r + " " + resDir
201                            + ": appScale=" + r.getCompatibilityInfo().applicationScale);
202                }
203                return r;
204            }
205        }
206
207        //if (r != null) {
208        //    Slog.w(TAG, "Throwing away out-of-date resources!!!! "
209        //            + r + " " + resDir);
210        //}
211
212        AssetManager assets = new AssetManager();
213        if (assets.addAssetPath(resDir) == 0) {
214            return null;
215        }
216
217        //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
218        DisplayMetrics metrics = getDisplayMetricsLocked(false);
219        r = new Resources(assets, metrics, getConfiguration(), compInfo);
220        if (false) {
221            Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
222                    + r.getConfiguration() + " appScale="
223                    + r.getCompatibilityInfo().applicationScale);
224        }
225
226        synchronized (mPackages) {
227            WeakReference<Resources> wr = mActiveResources.get(key);
228            Resources existing = wr != null ? wr.get() : null;
229            if (existing != null && existing.getAssets().isUpToDate()) {
230                // Someone else already created the resources while we were
231                // unlocked; go ahead and use theirs.
232                r.getAssets().close();
233                return existing;
234            }
235
236            // XXX need to remove entries when weak references go away
237            mActiveResources.put(key, new WeakReference<Resources>(r));
238            return r;
239        }
240    }
241
242    /**
243     * Creates the top level resources for the given package.
244     */
245    Resources getTopLevelResources(String resDir, PackageInfo pkgInfo) {
246        return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo);
247    }
248
249    final Handler getHandler() {
250        return mH;
251    }
252
253    public final static class PackageInfo {
254
255        private final ActivityThread mActivityThread;
256        private final ApplicationInfo mApplicationInfo;
257        private final String mPackageName;
258        private final String mAppDir;
259        private final String mResDir;
260        private final String[] mSharedLibraries;
261        private final String mDataDir;
262        private final File mDataDirFile;
263        private final ClassLoader mBaseClassLoader;
264        private final boolean mSecurityViolation;
265        private final boolean mIncludeCode;
266        private Resources mResources;
267        private ClassLoader mClassLoader;
268        private Application mApplication;
269        private CompatibilityInfo mCompatibilityInfo;
270
271        private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
272            = new HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>>();
273        private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mUnregisteredReceivers
274        = new HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>>();
275        private final HashMap<Context, HashMap<ServiceConnection, ServiceDispatcher>> mServices
276            = new HashMap<Context, HashMap<ServiceConnection, ServiceDispatcher>>();
277        private final HashMap<Context, HashMap<ServiceConnection, ServiceDispatcher>> mUnboundServices
278            = new HashMap<Context, HashMap<ServiceConnection, ServiceDispatcher>>();
279
280        int mClientCount = 0;
281
282        Application getApplication() {
283            return mApplication;
284        }
285
286        public PackageInfo(ActivityThread activityThread, ApplicationInfo aInfo,
287                ActivityThread mainThread, ClassLoader baseLoader,
288                boolean securityViolation, boolean includeCode) {
289            mActivityThread = activityThread;
290            mApplicationInfo = aInfo;
291            mPackageName = aInfo.packageName;
292            mAppDir = aInfo.sourceDir;
293            mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir
294                    : aInfo.publicSourceDir;
295            mSharedLibraries = aInfo.sharedLibraryFiles;
296            mDataDir = aInfo.dataDir;
297            mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
298            mBaseClassLoader = baseLoader;
299            mSecurityViolation = securityViolation;
300            mIncludeCode = includeCode;
301            mCompatibilityInfo = new CompatibilityInfo(aInfo);
302
303            if (mAppDir == null) {
304                if (mSystemContext == null) {
305                    mSystemContext =
306                        ContextImpl.createSystemContext(mainThread);
307                    mSystemContext.getResources().updateConfiguration(
308                             mainThread.getConfiguration(),
309                             mainThread.getDisplayMetricsLocked(false));
310                    //Slog.i(TAG, "Created system resources "
311                    //        + mSystemContext.getResources() + ": "
312                    //        + mSystemContext.getResources().getConfiguration());
313                }
314                mClassLoader = mSystemContext.getClassLoader();
315                mResources = mSystemContext.getResources();
316            }
317        }
318
319        public PackageInfo(ActivityThread activityThread, String name,
320                Context systemContext, ApplicationInfo info) {
321            mActivityThread = activityThread;
322            mApplicationInfo = info != null ? info : new ApplicationInfo();
323            mApplicationInfo.packageName = name;
324            mPackageName = name;
325            mAppDir = null;
326            mResDir = null;
327            mSharedLibraries = null;
328            mDataDir = null;
329            mDataDirFile = null;
330            mBaseClassLoader = null;
331            mSecurityViolation = false;
332            mIncludeCode = true;
333            mClassLoader = systemContext.getClassLoader();
334            mResources = systemContext.getResources();
335            mCompatibilityInfo = new CompatibilityInfo(mApplicationInfo);
336        }
337
338        public String getPackageName() {
339            return mPackageName;
340        }
341
342        public ApplicationInfo getApplicationInfo() {
343            return mApplicationInfo;
344        }
345
346        public boolean isSecurityViolation() {
347            return mSecurityViolation;
348        }
349
350        /**
351         * Gets the array of shared libraries that are listed as
352         * used by the given package.
353         *
354         * @param packageName the name of the package (note: not its
355         * file name)
356         * @return null-ok; the array of shared libraries, each one
357         * a fully-qualified path
358         */
359        private static String[] getLibrariesFor(String packageName) {
360            ApplicationInfo ai = null;
361            try {
362                ai = getPackageManager().getApplicationInfo(packageName,
363                        PackageManager.GET_SHARED_LIBRARY_FILES);
364            } catch (RemoteException e) {
365                throw new AssertionError(e);
366            }
367
368            if (ai == null) {
369                return null;
370            }
371
372            return ai.sharedLibraryFiles;
373        }
374
375        /**
376         * Combines two arrays (of library names) such that they are
377         * concatenated in order but are devoid of duplicates. The
378         * result is a single string with the names of the libraries
379         * separated by colons, or <code>null</code> if both lists
380         * were <code>null</code> or empty.
381         *
382         * @param list1 null-ok; the first list
383         * @param list2 null-ok; the second list
384         * @return null-ok; the combination
385         */
386        private static String combineLibs(String[] list1, String[] list2) {
387            StringBuilder result = new StringBuilder(300);
388            boolean first = true;
389
390            if (list1 != null) {
391                for (String s : list1) {
392                    if (first) {
393                        first = false;
394                    } else {
395                        result.append(':');
396                    }
397                    result.append(s);
398                }
399            }
400
401            // Only need to check for duplicates if list1 was non-empty.
402            boolean dupCheck = !first;
403
404            if (list2 != null) {
405                for (String s : list2) {
406                    if (dupCheck && ArrayUtils.contains(list1, s)) {
407                        continue;
408                    }
409
410                    if (first) {
411                        first = false;
412                    } else {
413                        result.append(':');
414                    }
415                    result.append(s);
416                }
417            }
418
419            return result.toString();
420        }
421
422        public ClassLoader getClassLoader() {
423            synchronized (this) {
424                if (mClassLoader != null) {
425                    return mClassLoader;
426                }
427
428                if (mIncludeCode && !mPackageName.equals("android")) {
429                    String zip = mAppDir;
430
431                    /*
432                     * The following is a bit of a hack to inject
433                     * instrumentation into the system: If the app
434                     * being started matches one of the instrumentation names,
435                     * then we combine both the "instrumentation" and
436                     * "instrumented" app into the path, along with the
437                     * concatenation of both apps' shared library lists.
438                     */
439
440                    String instrumentationAppDir =
441                            mActivityThread.mInstrumentationAppDir;
442                    String instrumentationAppPackage =
443                            mActivityThread.mInstrumentationAppPackage;
444                    String instrumentedAppDir =
445                            mActivityThread.mInstrumentedAppDir;
446                    String[] instrumentationLibs = null;
447
448                    if (mAppDir.equals(instrumentationAppDir)
449                            || mAppDir.equals(instrumentedAppDir)) {
450                        zip = instrumentationAppDir + ":" + instrumentedAppDir;
451                        if (! instrumentedAppDir.equals(instrumentationAppDir)) {
452                            instrumentationLibs =
453                                getLibrariesFor(instrumentationAppPackage);
454                        }
455                    }
456
457                    if ((mSharedLibraries != null) ||
458                            (instrumentationLibs != null)) {
459                        zip =
460                            combineLibs(mSharedLibraries, instrumentationLibs)
461                            + ':' + zip;
462                    }
463
464                    /*
465                     * With all the combination done (if necessary, actually
466                     * create the class loader.
467                     */
468
469                    if (localLOGV) Slog.v(TAG, "Class path: " + zip);
470
471                    mClassLoader =
472                        ApplicationLoaders.getDefault().getClassLoader(
473                            zip, mDataDir, mBaseClassLoader);
474                    initializeJavaContextClassLoader();
475                } else {
476                    if (mBaseClassLoader == null) {
477                        mClassLoader = ClassLoader.getSystemClassLoader();
478                    } else {
479                        mClassLoader = mBaseClassLoader;
480                    }
481                }
482                return mClassLoader;
483            }
484        }
485
486        /**
487         * Setup value for Thread.getContextClassLoader(). If the
488         * package will not run in in a VM with other packages, we set
489         * the Java context ClassLoader to the
490         * PackageInfo.getClassLoader value. However, if this VM can
491         * contain multiple packages, we intead set the Java context
492         * ClassLoader to a proxy that will warn about the use of Java
493         * context ClassLoaders and then fall through to use the
494         * system ClassLoader.
495         *
496         * <p> Note that this is similar to but not the same as the
497         * android.content.Context.getClassLoader(). While both
498         * context class loaders are typically set to the
499         * PathClassLoader used to load the package archive in the
500         * single application per VM case, a single Android process
501         * may contain several Contexts executing on one thread with
502         * their own logical ClassLoaders while the Java context
503         * ClassLoader is a thread local. This is why in the case when
504         * we have multiple packages per VM we do not set the Java
505         * context ClassLoader to an arbitrary but instead warn the
506         * user to set their own if we detect that they are using a
507         * Java library that expects it to be set.
508         */
509        private void initializeJavaContextClassLoader() {
510            IPackageManager pm = getPackageManager();
511            android.content.pm.PackageInfo pi;
512            try {
513                pi = pm.getPackageInfo(mPackageName, 0);
514            } catch (RemoteException e) {
515                throw new AssertionError(e);
516            }
517            /*
518             * Two possible indications that this package could be
519             * sharing its virtual machine with other packages:
520             *
521             * 1.) the sharedUserId attribute is set in the manifest,
522             *     indicating a request to share a VM with other
523             *     packages with the same sharedUserId.
524             *
525             * 2.) the application element of the manifest has an
526             *     attribute specifying a non-default process name,
527             *     indicating the desire to run in another packages VM.
528             */
529            boolean sharedUserIdSet = (pi.sharedUserId != null);
530            boolean processNameNotDefault =
531                (pi.applicationInfo != null &&
532                 !mPackageName.equals(pi.applicationInfo.processName));
533            boolean sharable = (sharedUserIdSet || processNameNotDefault);
534            ClassLoader contextClassLoader =
535                (sharable)
536                ? new WarningContextClassLoader()
537                : mClassLoader;
538            Thread.currentThread().setContextClassLoader(contextClassLoader);
539        }
540
541        private static class WarningContextClassLoader extends ClassLoader {
542
543            private static boolean warned = false;
544
545            private void warn(String methodName) {
546                if (warned) {
547                    return;
548                }
549                warned = true;
550                Thread.currentThread().setContextClassLoader(getParent());
551                Slog.w(TAG, "ClassLoader." + methodName + ": " +
552                      "The class loader returned by " +
553                      "Thread.getContextClassLoader() may fail for processes " +
554                      "that host multiple applications. You should explicitly " +
555                      "specify a context class loader. For example: " +
556                      "Thread.setContextClassLoader(getClass().getClassLoader());");
557            }
558
559            @Override public URL getResource(String resName) {
560                warn("getResource");
561                return getParent().getResource(resName);
562            }
563
564            @Override public Enumeration<URL> getResources(String resName) throws IOException {
565                warn("getResources");
566                return getParent().getResources(resName);
567            }
568
569            @Override public InputStream getResourceAsStream(String resName) {
570                warn("getResourceAsStream");
571                return getParent().getResourceAsStream(resName);
572            }
573
574            @Override public Class<?> loadClass(String className) throws ClassNotFoundException {
575                warn("loadClass");
576                return getParent().loadClass(className);
577            }
578
579            @Override public void setClassAssertionStatus(String cname, boolean enable) {
580                warn("setClassAssertionStatus");
581                getParent().setClassAssertionStatus(cname, enable);
582            }
583
584            @Override public void setPackageAssertionStatus(String pname, boolean enable) {
585                warn("setPackageAssertionStatus");
586                getParent().setPackageAssertionStatus(pname, enable);
587            }
588
589            @Override public void setDefaultAssertionStatus(boolean enable) {
590                warn("setDefaultAssertionStatus");
591                getParent().setDefaultAssertionStatus(enable);
592            }
593
594            @Override public void clearAssertionStatus() {
595                warn("clearAssertionStatus");
596                getParent().clearAssertionStatus();
597            }
598        }
599
600        public String getAppDir() {
601            return mAppDir;
602        }
603
604        public String getResDir() {
605            return mResDir;
606        }
607
608        public String getDataDir() {
609            return mDataDir;
610        }
611
612        public File getDataDirFile() {
613            return mDataDirFile;
614        }
615
616        public AssetManager getAssets(ActivityThread mainThread) {
617            return getResources(mainThread).getAssets();
618        }
619
620        public Resources getResources(ActivityThread mainThread) {
621            if (mResources == null) {
622                mResources = mainThread.getTopLevelResources(mResDir, this);
623            }
624            return mResources;
625        }
626
627        public Application makeApplication(boolean forceDefaultAppClass,
628                Instrumentation instrumentation) {
629            if (mApplication != null) {
630                return mApplication;
631            }
632
633            Application app = null;
634
635            String appClass = mApplicationInfo.className;
636            if (forceDefaultAppClass || (appClass == null)) {
637                appClass = "android.app.Application";
638            }
639
640            try {
641                java.lang.ClassLoader cl = getClassLoader();
642                ContextImpl appContext = new ContextImpl();
643                appContext.init(this, null, mActivityThread);
644                app = mActivityThread.mInstrumentation.newApplication(
645                        cl, appClass, appContext);
646                appContext.setOuterContext(app);
647            } catch (Exception e) {
648                if (!mActivityThread.mInstrumentation.onException(app, e)) {
649                    throw new RuntimeException(
650                        "Unable to instantiate application " + appClass
651                        + ": " + e.toString(), e);
652                }
653            }
654            mActivityThread.mAllApplications.add(app);
655            mApplication = app;
656
657            if (instrumentation != null) {
658                try {
659                    instrumentation.callApplicationOnCreate(app);
660                } catch (Exception e) {
661                    if (!instrumentation.onException(app, e)) {
662                        throw new RuntimeException(
663                            "Unable to create application " + app.getClass().getName()
664                            + ": " + e.toString(), e);
665                    }
666                }
667            }
668
669            return app;
670        }
671
672        public void removeContextRegistrations(Context context,
673                String who, String what) {
674            HashMap<BroadcastReceiver, ReceiverDispatcher> rmap =
675                mReceivers.remove(context);
676            if (rmap != null) {
677                Iterator<ReceiverDispatcher> it = rmap.values().iterator();
678                while (it.hasNext()) {
679                    ReceiverDispatcher rd = it.next();
680                    IntentReceiverLeaked leak = new IntentReceiverLeaked(
681                            what + " " + who + " has leaked IntentReceiver "
682                            + rd.getIntentReceiver() + " that was " +
683                            "originally registered here. Are you missing a " +
684                            "call to unregisterReceiver()?");
685                    leak.setStackTrace(rd.getLocation().getStackTrace());
686                    Slog.e(TAG, leak.getMessage(), leak);
687                    try {
688                        ActivityManagerNative.getDefault().unregisterReceiver(
689                                rd.getIIntentReceiver());
690                    } catch (RemoteException e) {
691                        // system crashed, nothing we can do
692                    }
693                }
694            }
695            mUnregisteredReceivers.remove(context);
696            //Slog.i(TAG, "Receiver registrations: " + mReceivers);
697            HashMap<ServiceConnection, ServiceDispatcher> smap =
698                mServices.remove(context);
699            if (smap != null) {
700                Iterator<ServiceDispatcher> it = smap.values().iterator();
701                while (it.hasNext()) {
702                    ServiceDispatcher sd = it.next();
703                    ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
704                            what + " " + who + " has leaked ServiceConnection "
705                            + sd.getServiceConnection() + " that was originally bound here");
706                    leak.setStackTrace(sd.getLocation().getStackTrace());
707                    Slog.e(TAG, leak.getMessage(), leak);
708                    try {
709                        ActivityManagerNative.getDefault().unbindService(
710                                sd.getIServiceConnection());
711                    } catch (RemoteException e) {
712                        // system crashed, nothing we can do
713                    }
714                    sd.doForget();
715                }
716            }
717            mUnboundServices.remove(context);
718            //Slog.i(TAG, "Service registrations: " + mServices);
719        }
720
721        public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
722                Context context, Handler handler,
723                Instrumentation instrumentation, boolean registered) {
724            synchronized (mReceivers) {
725                ReceiverDispatcher rd = null;
726                HashMap<BroadcastReceiver, ReceiverDispatcher> map = null;
727                if (registered) {
728                    map = mReceivers.get(context);
729                    if (map != null) {
730                        rd = map.get(r);
731                    }
732                }
733                if (rd == null) {
734                    rd = new ReceiverDispatcher(r, context, handler,
735                            instrumentation, registered);
736                    if (registered) {
737                        if (map == null) {
738                            map = new HashMap<BroadcastReceiver, ReceiverDispatcher>();
739                            mReceivers.put(context, map);
740                        }
741                        map.put(r, rd);
742                    }
743                } else {
744                    rd.validate(context, handler);
745                }
746                return rd.getIIntentReceiver();
747            }
748        }
749
750        public IIntentReceiver forgetReceiverDispatcher(Context context,
751                BroadcastReceiver r) {
752            synchronized (mReceivers) {
753                HashMap<BroadcastReceiver, ReceiverDispatcher> map = mReceivers.get(context);
754                ReceiverDispatcher rd = null;
755                if (map != null) {
756                    rd = map.get(r);
757                    if (rd != null) {
758                        map.remove(r);
759                        if (map.size() == 0) {
760                            mReceivers.remove(context);
761                        }
762                        if (r.getDebugUnregister()) {
763                            HashMap<BroadcastReceiver, ReceiverDispatcher> holder
764                                    = mUnregisteredReceivers.get(context);
765                            if (holder == null) {
766                                holder = new HashMap<BroadcastReceiver, ReceiverDispatcher>();
767                                mUnregisteredReceivers.put(context, holder);
768                            }
769                            RuntimeException ex = new IllegalArgumentException(
770                                    "Originally unregistered here:");
771                            ex.fillInStackTrace();
772                            rd.setUnregisterLocation(ex);
773                            holder.put(r, rd);
774                        }
775                        return rd.getIIntentReceiver();
776                    }
777                }
778                HashMap<BroadcastReceiver, ReceiverDispatcher> holder
779                        = mUnregisteredReceivers.get(context);
780                if (holder != null) {
781                    rd = holder.get(r);
782                    if (rd != null) {
783                        RuntimeException ex = rd.getUnregisterLocation();
784                        throw new IllegalArgumentException(
785                                "Unregistering Receiver " + r
786                                + " that was already unregistered", ex);
787                    }
788                }
789                if (context == null) {
790                    throw new IllegalStateException("Unbinding Receiver " + r
791                            + " from Context that is no longer in use: " + context);
792                } else {
793                    throw new IllegalArgumentException("Receiver not registered: " + r);
794                }
795
796            }
797        }
798
799        static final class ReceiverDispatcher {
800
801            final static class InnerReceiver extends IIntentReceiver.Stub {
802                final WeakReference<ReceiverDispatcher> mDispatcher;
803                final ReceiverDispatcher mStrongRef;
804
805                InnerReceiver(ReceiverDispatcher rd, boolean strong) {
806                    mDispatcher = new WeakReference<ReceiverDispatcher>(rd);
807                    mStrongRef = strong ? rd : null;
808                }
809                public void performReceive(Intent intent, int resultCode,
810                        String data, Bundle extras, boolean ordered, boolean sticky) {
811                    ReceiverDispatcher rd = mDispatcher.get();
812                    if (DEBUG_BROADCAST) {
813                        int seq = intent.getIntExtra("seq", -1);
814                        Slog.i(TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
815                                + " to " + (rd != null ? rd.mReceiver : null));
816                    }
817                    if (rd != null) {
818                        rd.performReceive(intent, resultCode, data, extras,
819                                ordered, sticky);
820                    } else {
821                        // The activity manager dispatched a broadcast to a registered
822                        // receiver in this process, but before it could be delivered the
823                        // receiver was unregistered.  Acknowledge the broadcast on its
824                        // behalf so that the system's broadcast sequence can continue.
825                        if (DEBUG_BROADCAST) Slog.i(TAG,
826                                "Finishing broadcast to unregistered receiver");
827                        IActivityManager mgr = ActivityManagerNative.getDefault();
828                        try {
829                            mgr.finishReceiver(this, resultCode, data, extras, false);
830                        } catch (RemoteException e) {
831                            Slog.w(TAG, "Couldn't finish broadcast to unregistered receiver");
832                        }
833                    }
834                }
835            }
836
837            final IIntentReceiver.Stub mIIntentReceiver;
838            final BroadcastReceiver mReceiver;
839            final Context mContext;
840            final Handler mActivityThread;
841            final Instrumentation mInstrumentation;
842            final boolean mRegistered;
843            final IntentReceiverLeaked mLocation;
844            RuntimeException mUnregisterLocation;
845
846            final class Args implements Runnable {
847                private Intent mCurIntent;
848                private int mCurCode;
849                private String mCurData;
850                private Bundle mCurMap;
851                private boolean mCurOrdered;
852                private boolean mCurSticky;
853
854                public void run() {
855                    BroadcastReceiver receiver = mReceiver;
856                    if (DEBUG_BROADCAST) {
857                        int seq = mCurIntent.getIntExtra("seq", -1);
858                        Slog.i(TAG, "Dispatching broadcast " + mCurIntent.getAction()
859                                + " seq=" + seq + " to " + mReceiver);
860                        Slog.i(TAG, "  mRegistered=" + mRegistered
861                                + " mCurOrdered=" + mCurOrdered);
862                    }
863
864                    IActivityManager mgr = ActivityManagerNative.getDefault();
865                    Intent intent = mCurIntent;
866                    mCurIntent = null;
867
868                    if (receiver == null) {
869                        if (mRegistered && mCurOrdered) {
870                            try {
871                                if (DEBUG_BROADCAST) Slog.i(TAG,
872                                        "Finishing null broadcast to " + mReceiver);
873                                mgr.finishReceiver(mIIntentReceiver,
874                                        mCurCode, mCurData, mCurMap, false);
875                            } catch (RemoteException ex) {
876                            }
877                        }
878                        return;
879                    }
880
881                    try {
882                        ClassLoader cl =  mReceiver.getClass().getClassLoader();
883                        intent.setExtrasClassLoader(cl);
884                        if (mCurMap != null) {
885                            mCurMap.setClassLoader(cl);
886                        }
887                        receiver.setOrderedHint(true);
888                        receiver.setResult(mCurCode, mCurData, mCurMap);
889                        receiver.clearAbortBroadcast();
890                        receiver.setOrderedHint(mCurOrdered);
891                        receiver.setInitialStickyHint(mCurSticky);
892                        receiver.onReceive(mContext, intent);
893                    } catch (Exception e) {
894                        if (mRegistered && mCurOrdered) {
895                            try {
896                                if (DEBUG_BROADCAST) Slog.i(TAG,
897                                        "Finishing failed broadcast to " + mReceiver);
898                                mgr.finishReceiver(mIIntentReceiver,
899                                        mCurCode, mCurData, mCurMap, false);
900                            } catch (RemoteException ex) {
901                            }
902                        }
903                        if (mInstrumentation == null ||
904                                !mInstrumentation.onException(mReceiver, e)) {
905                            throw new RuntimeException(
906                                "Error receiving broadcast " + intent
907                                + " in " + mReceiver, e);
908                        }
909                    }
910                    if (mRegistered && mCurOrdered) {
911                        try {
912                            if (DEBUG_BROADCAST) Slog.i(TAG,
913                                    "Finishing broadcast to " + mReceiver);
914                            mgr.finishReceiver(mIIntentReceiver,
915                                    receiver.getResultCode(),
916                                    receiver.getResultData(),
917                                    receiver.getResultExtras(false),
918                                    receiver.getAbortBroadcast());
919                        } catch (RemoteException ex) {
920                        }
921                    }
922                }
923            }
924
925            ReceiverDispatcher(BroadcastReceiver receiver, Context context,
926                    Handler activityThread, Instrumentation instrumentation,
927                    boolean registered) {
928                if (activityThread == null) {
929                    throw new NullPointerException("Handler must not be null");
930                }
931
932                mIIntentReceiver = new InnerReceiver(this, !registered);
933                mReceiver = receiver;
934                mContext = context;
935                mActivityThread = activityThread;
936                mInstrumentation = instrumentation;
937                mRegistered = registered;
938                mLocation = new IntentReceiverLeaked(null);
939                mLocation.fillInStackTrace();
940            }
941
942            void validate(Context context, Handler activityThread) {
943                if (mContext != context) {
944                    throw new IllegalStateException(
945                        "Receiver " + mReceiver +
946                        " registered with differing Context (was " +
947                        mContext + " now " + context + ")");
948                }
949                if (mActivityThread != activityThread) {
950                    throw new IllegalStateException(
951                        "Receiver " + mReceiver +
952                        " registered with differing handler (was " +
953                        mActivityThread + " now " + activityThread + ")");
954                }
955            }
956
957            IntentReceiverLeaked getLocation() {
958                return mLocation;
959            }
960
961            BroadcastReceiver getIntentReceiver() {
962                return mReceiver;
963            }
964
965            IIntentReceiver getIIntentReceiver() {
966                return mIIntentReceiver;
967            }
968
969            void setUnregisterLocation(RuntimeException ex) {
970                mUnregisterLocation = ex;
971            }
972
973            RuntimeException getUnregisterLocation() {
974                return mUnregisterLocation;
975            }
976
977            public void performReceive(Intent intent, int resultCode,
978                    String data, Bundle extras, boolean ordered, boolean sticky) {
979                if (DEBUG_BROADCAST) {
980                    int seq = intent.getIntExtra("seq", -1);
981                    Slog.i(TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
982                            + " to " + mReceiver);
983                }
984                Args args = new Args();
985                args.mCurIntent = intent;
986                args.mCurCode = resultCode;
987                args.mCurData = data;
988                args.mCurMap = extras;
989                args.mCurOrdered = ordered;
990                args.mCurSticky = sticky;
991                if (!mActivityThread.post(args)) {
992                    if (mRegistered && ordered) {
993                        IActivityManager mgr = ActivityManagerNative.getDefault();
994                        try {
995                            if (DEBUG_BROADCAST) Slog.i(TAG,
996                                    "Finishing sync broadcast to " + mReceiver);
997                            mgr.finishReceiver(mIIntentReceiver, args.mCurCode,
998                                    args.mCurData, args.mCurMap, false);
999                        } catch (RemoteException ex) {
1000                        }
1001                    }
1002                }
1003            }
1004
1005        }
1006
1007        public final IServiceConnection getServiceDispatcher(ServiceConnection c,
1008                Context context, Handler handler, int flags) {
1009            synchronized (mServices) {
1010                ServiceDispatcher sd = null;
1011                HashMap<ServiceConnection, ServiceDispatcher> map = mServices.get(context);
1012                if (map != null) {
1013                    sd = map.get(c);
1014                }
1015                if (sd == null) {
1016                    sd = new ServiceDispatcher(c, context, handler, flags);
1017                    if (map == null) {
1018                        map = new HashMap<ServiceConnection, ServiceDispatcher>();
1019                        mServices.put(context, map);
1020                    }
1021                    map.put(c, sd);
1022                } else {
1023                    sd.validate(context, handler);
1024                }
1025                return sd.getIServiceConnection();
1026            }
1027        }
1028
1029        public final IServiceConnection forgetServiceDispatcher(Context context,
1030                ServiceConnection c) {
1031            synchronized (mServices) {
1032                HashMap<ServiceConnection, ServiceDispatcher> map
1033                        = mServices.get(context);
1034                ServiceDispatcher sd = null;
1035                if (map != null) {
1036                    sd = map.get(c);
1037                    if (sd != null) {
1038                        map.remove(c);
1039                        sd.doForget();
1040                        if (map.size() == 0) {
1041                            mServices.remove(context);
1042                        }
1043                        if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
1044                            HashMap<ServiceConnection, ServiceDispatcher> holder
1045                                    = mUnboundServices.get(context);
1046                            if (holder == null) {
1047                                holder = new HashMap<ServiceConnection, ServiceDispatcher>();
1048                                mUnboundServices.put(context, holder);
1049                            }
1050                            RuntimeException ex = new IllegalArgumentException(
1051                                    "Originally unbound here:");
1052                            ex.fillInStackTrace();
1053                            sd.setUnbindLocation(ex);
1054                            holder.put(c, sd);
1055                        }
1056                        return sd.getIServiceConnection();
1057                    }
1058                }
1059                HashMap<ServiceConnection, ServiceDispatcher> holder
1060                        = mUnboundServices.get(context);
1061                if (holder != null) {
1062                    sd = holder.get(c);
1063                    if (sd != null) {
1064                        RuntimeException ex = sd.getUnbindLocation();
1065                        throw new IllegalArgumentException(
1066                                "Unbinding Service " + c
1067                                + " that was already unbound", ex);
1068                    }
1069                }
1070                if (context == null) {
1071                    throw new IllegalStateException("Unbinding Service " + c
1072                            + " from Context that is no longer in use: " + context);
1073                } else {
1074                    throw new IllegalArgumentException("Service not registered: " + c);
1075                }
1076            }
1077        }
1078
1079        static final class ServiceDispatcher {
1080            private final InnerConnection mIServiceConnection;
1081            private final ServiceConnection mConnection;
1082            private final Context mContext;
1083            private final Handler mActivityThread;
1084            private final ServiceConnectionLeaked mLocation;
1085            private final int mFlags;
1086
1087            private RuntimeException mUnbindLocation;
1088
1089            private boolean mDied;
1090
1091            private static class ConnectionInfo {
1092                IBinder binder;
1093                IBinder.DeathRecipient deathMonitor;
1094            }
1095
1096            private static class InnerConnection extends IServiceConnection.Stub {
1097                final WeakReference<ServiceDispatcher> mDispatcher;
1098
1099                InnerConnection(ServiceDispatcher sd) {
1100                    mDispatcher = new WeakReference<ServiceDispatcher>(sd);
1101                }
1102
1103                public void connected(ComponentName name, IBinder service) throws RemoteException {
1104                    ServiceDispatcher sd = mDispatcher.get();
1105                    if (sd != null) {
1106                        sd.connected(name, service);
1107                    }
1108                }
1109            }
1110
1111            private final HashMap<ComponentName, ConnectionInfo> mActiveConnections
1112                = new HashMap<ComponentName, ConnectionInfo>();
1113
1114            ServiceDispatcher(ServiceConnection conn,
1115                    Context context, Handler activityThread, int flags) {
1116                mIServiceConnection = new InnerConnection(this);
1117                mConnection = conn;
1118                mContext = context;
1119                mActivityThread = activityThread;
1120                mLocation = new ServiceConnectionLeaked(null);
1121                mLocation.fillInStackTrace();
1122                mFlags = flags;
1123            }
1124
1125            void validate(Context context, Handler activityThread) {
1126                if (mContext != context) {
1127                    throw new RuntimeException(
1128                        "ServiceConnection " + mConnection +
1129                        " registered with differing Context (was " +
1130                        mContext + " now " + context + ")");
1131                }
1132                if (mActivityThread != activityThread) {
1133                    throw new RuntimeException(
1134                        "ServiceConnection " + mConnection +
1135                        " registered with differing handler (was " +
1136                        mActivityThread + " now " + activityThread + ")");
1137                }
1138            }
1139
1140            void doForget() {
1141                synchronized(this) {
1142                    Iterator<ConnectionInfo> it = mActiveConnections.values().iterator();
1143                    while (it.hasNext()) {
1144                        ConnectionInfo ci = it.next();
1145                        ci.binder.unlinkToDeath(ci.deathMonitor, 0);
1146                    }
1147                    mActiveConnections.clear();
1148                }
1149            }
1150
1151            ServiceConnectionLeaked getLocation() {
1152                return mLocation;
1153            }
1154
1155            ServiceConnection getServiceConnection() {
1156                return mConnection;
1157            }
1158
1159            IServiceConnection getIServiceConnection() {
1160                return mIServiceConnection;
1161            }
1162
1163            int getFlags() {
1164                return mFlags;
1165            }
1166
1167            void setUnbindLocation(RuntimeException ex) {
1168                mUnbindLocation = ex;
1169            }
1170
1171            RuntimeException getUnbindLocation() {
1172                return mUnbindLocation;
1173            }
1174
1175            public void connected(ComponentName name, IBinder service) {
1176                if (mActivityThread != null) {
1177                    mActivityThread.post(new RunConnection(name, service, 0));
1178                } else {
1179                    doConnected(name, service);
1180                }
1181            }
1182
1183            public void death(ComponentName name, IBinder service) {
1184                ConnectionInfo old;
1185
1186                synchronized (this) {
1187                    mDied = true;
1188                    old = mActiveConnections.remove(name);
1189                    if (old == null || old.binder != service) {
1190                        // Death for someone different than who we last
1191                        // reported...  just ignore it.
1192                        return;
1193                    }
1194                    old.binder.unlinkToDeath(old.deathMonitor, 0);
1195                }
1196
1197                if (mActivityThread != null) {
1198                    mActivityThread.post(new RunConnection(name, service, 1));
1199                } else {
1200                    doDeath(name, service);
1201                }
1202            }
1203
1204            public void doConnected(ComponentName name, IBinder service) {
1205                ConnectionInfo old;
1206                ConnectionInfo info;
1207
1208                synchronized (this) {
1209                    old = mActiveConnections.get(name);
1210                    if (old != null && old.binder == service) {
1211                        // Huh, already have this one.  Oh well!
1212                        return;
1213                    }
1214
1215                    if (service != null) {
1216                        // A new service is being connected... set it all up.
1217                        mDied = false;
1218                        info = new ConnectionInfo();
1219                        info.binder = service;
1220                        info.deathMonitor = new DeathMonitor(name, service);
1221                        try {
1222                            service.linkToDeath(info.deathMonitor, 0);
1223                            mActiveConnections.put(name, info);
1224                        } catch (RemoteException e) {
1225                            // This service was dead before we got it...  just
1226                            // don't do anything with it.
1227                            mActiveConnections.remove(name);
1228                            return;
1229                        }
1230
1231                    } else {
1232                        // The named service is being disconnected... clean up.
1233                        mActiveConnections.remove(name);
1234                    }
1235
1236                    if (old != null) {
1237                        old.binder.unlinkToDeath(old.deathMonitor, 0);
1238                    }
1239                }
1240
1241                // If there was an old service, it is not disconnected.
1242                if (old != null) {
1243                    mConnection.onServiceDisconnected(name);
1244                }
1245                // If there is a new service, it is now connected.
1246                if (service != null) {
1247                    mConnection.onServiceConnected(name, service);
1248                }
1249            }
1250
1251            public void doDeath(ComponentName name, IBinder service) {
1252                mConnection.onServiceDisconnected(name);
1253            }
1254
1255            private final class RunConnection implements Runnable {
1256                RunConnection(ComponentName name, IBinder service, int command) {
1257                    mName = name;
1258                    mService = service;
1259                    mCommand = command;
1260                }
1261
1262                public void run() {
1263                    if (mCommand == 0) {
1264                        doConnected(mName, mService);
1265                    } else if (mCommand == 1) {
1266                        doDeath(mName, mService);
1267                    }
1268                }
1269
1270                final ComponentName mName;
1271                final IBinder mService;
1272                final int mCommand;
1273            }
1274
1275            private final class DeathMonitor implements IBinder.DeathRecipient
1276            {
1277                DeathMonitor(ComponentName name, IBinder service) {
1278                    mName = name;
1279                    mService = service;
1280                }
1281
1282                public void binderDied() {
1283                    death(mName, mService);
1284                }
1285
1286                final ComponentName mName;
1287                final IBinder mService;
1288            }
1289        }
1290    }
1291
1292    private static ContextImpl mSystemContext = null;
1293
1294    private static final class ActivityRecord {
1295        IBinder token;
1296        int ident;
1297        Intent intent;
1298        Bundle state;
1299        Activity activity;
1300        Window window;
1301        Activity parent;
1302        String embeddedID;
1303        Activity.NonConfigurationInstances lastNonConfigurationInstances;
1304        boolean paused;
1305        boolean stopped;
1306        boolean hideForNow;
1307        Configuration newConfig;
1308        Configuration createdConfig;
1309        ActivityRecord nextIdle;
1310
1311        ActivityInfo activityInfo;
1312        PackageInfo packageInfo;
1313
1314        List<ResultInfo> pendingResults;
1315        List<Intent> pendingIntents;
1316
1317        boolean startsNotResumed;
1318        boolean isForward;
1319
1320        ActivityRecord() {
1321            parent = null;
1322            embeddedID = null;
1323            paused = false;
1324            stopped = false;
1325            hideForNow = false;
1326            nextIdle = null;
1327        }
1328
1329        public String toString() {
1330            ComponentName componentName = intent.getComponent();
1331            return "ActivityRecord{"
1332                + Integer.toHexString(System.identityHashCode(this))
1333                + " token=" + token + " " + (componentName == null
1334                        ? "no component name" : componentName.toShortString())
1335                + "}";
1336        }
1337    }
1338
1339    private final class ProviderRecord implements IBinder.DeathRecipient {
1340        final String mName;
1341        final IContentProvider mProvider;
1342        final ContentProvider mLocalProvider;
1343
1344        ProviderRecord(String name, IContentProvider provider,
1345                ContentProvider localProvider) {
1346            mName = name;
1347            mProvider = provider;
1348            mLocalProvider = localProvider;
1349        }
1350
1351        public void binderDied() {
1352            removeDeadProvider(mName, mProvider);
1353        }
1354    }
1355
1356    private static final class NewIntentData {
1357        List<Intent> intents;
1358        IBinder token;
1359        public String toString() {
1360            return "NewIntentData{intents=" + intents + " token=" + token + "}";
1361        }
1362    }
1363
1364    private static final class ReceiverData {
1365        Intent intent;
1366        ActivityInfo info;
1367        int resultCode;
1368        String resultData;
1369        Bundle resultExtras;
1370        boolean sync;
1371        boolean resultAbort;
1372        public String toString() {
1373            return "ReceiverData{intent=" + intent + " packageName=" +
1374            info.packageName + " resultCode=" + resultCode
1375            + " resultData=" + resultData + " resultExtras=" + resultExtras + "}";
1376        }
1377    }
1378
1379    private static final class CreateBackupAgentData {
1380        ApplicationInfo appInfo;
1381        int backupMode;
1382        public String toString() {
1383            return "CreateBackupAgentData{appInfo=" + appInfo
1384                    + " backupAgent=" + appInfo.backupAgentName
1385                    + " mode=" + backupMode + "}";
1386        }
1387    }
1388
1389    private static final class CreateServiceData {
1390        IBinder token;
1391        ServiceInfo info;
1392        Intent intent;
1393        public String toString() {
1394            return "CreateServiceData{token=" + token + " className="
1395            + info.name + " packageName=" + info.packageName
1396            + " intent=" + intent + "}";
1397        }
1398    }
1399
1400    private static final class BindServiceData {
1401        IBinder token;
1402        Intent intent;
1403        boolean rebind;
1404        public String toString() {
1405            return "BindServiceData{token=" + token + " intent=" + intent + "}";
1406        }
1407    }
1408
1409    private static final class ServiceArgsData {
1410        IBinder token;
1411        int startId;
1412        int flags;
1413        Intent args;
1414        public String toString() {
1415            return "ServiceArgsData{token=" + token + " startId=" + startId
1416            + " args=" + args + "}";
1417        }
1418    }
1419
1420    private static final class AppBindData {
1421        PackageInfo info;
1422        String processName;
1423        ApplicationInfo appInfo;
1424        List<ProviderInfo> providers;
1425        ComponentName instrumentationName;
1426        String profileFile;
1427        Bundle instrumentationArgs;
1428        IInstrumentationWatcher instrumentationWatcher;
1429        int debugMode;
1430        boolean restrictedBackupMode;
1431        Configuration config;
1432        boolean handlingProfiling;
1433        public String toString() {
1434            return "AppBindData{appInfo=" + appInfo + "}";
1435        }
1436    }
1437
1438    private static final class DumpServiceInfo {
1439        FileDescriptor fd;
1440        IBinder service;
1441        String[] args;
1442        boolean dumped;
1443    }
1444
1445    private static final class ResultData {
1446        IBinder token;
1447        List<ResultInfo> results;
1448        public String toString() {
1449            return "ResultData{token=" + token + " results" + results + "}";
1450        }
1451    }
1452
1453    private static final class ContextCleanupInfo {
1454        ContextImpl context;
1455        String what;
1456        String who;
1457    }
1458
1459    private static final class ProfilerControlData {
1460        String path;
1461        ParcelFileDescriptor fd;
1462    }
1463
1464    private final class ApplicationThread extends ApplicationThreadNative {
1465        private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
1466        private static final String ONE_COUNT_COLUMN = "%17s %8d";
1467        private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
1468        private static final String DB_INFO_FORMAT = "  %4d %6d %8d %14s  %s";
1469
1470        // Formatting for checkin service - update version if row format changes
1471        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
1472
1473        public final void schedulePauseActivity(IBinder token, boolean finished,
1474                boolean userLeaving, int configChanges) {
1475            queueOrSendMessage(
1476                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
1477                    token,
1478                    (userLeaving ? 1 : 0),
1479                    configChanges);
1480        }
1481
1482        public final void scheduleStopActivity(IBinder token, boolean showWindow,
1483                int configChanges) {
1484           queueOrSendMessage(
1485                showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,
1486                token, 0, configChanges);
1487        }
1488
1489        public final void scheduleWindowVisibility(IBinder token, boolean showWindow) {
1490            queueOrSendMessage(
1491                showWindow ? H.SHOW_WINDOW : H.HIDE_WINDOW,
1492                token);
1493        }
1494
1495        public final void scheduleResumeActivity(IBinder token, boolean isForward) {
1496            queueOrSendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
1497        }
1498
1499        public final void scheduleSendResult(IBinder token, List<ResultInfo> results) {
1500            ResultData res = new ResultData();
1501            res.token = token;
1502            res.results = results;
1503            queueOrSendMessage(H.SEND_RESULT, res);
1504        }
1505
1506        // we use token to identify this activity without having to send the
1507        // activity itself back to the activity manager. (matters more with ipc)
1508        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
1509                ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
1510                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
1511            ActivityRecord r = new ActivityRecord();
1512
1513            r.token = token;
1514            r.ident = ident;
1515            r.intent = intent;
1516            r.activityInfo = info;
1517            r.state = state;
1518
1519            r.pendingResults = pendingResults;
1520            r.pendingIntents = pendingNewIntents;
1521
1522            r.startsNotResumed = notResumed;
1523            r.isForward = isForward;
1524
1525            queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
1526        }
1527
1528        public final void scheduleRelaunchActivity(IBinder token,
1529                List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
1530                int configChanges, boolean notResumed, Configuration config) {
1531            ActivityRecord r = new ActivityRecord();
1532
1533            r.token = token;
1534            r.pendingResults = pendingResults;
1535            r.pendingIntents = pendingNewIntents;
1536            r.startsNotResumed = notResumed;
1537            r.createdConfig = config;
1538
1539            synchronized (mPackages) {
1540                mRelaunchingActivities.add(r);
1541            }
1542
1543            queueOrSendMessage(H.RELAUNCH_ACTIVITY, r, configChanges);
1544        }
1545
1546        public final void scheduleNewIntent(List<Intent> intents, IBinder token) {
1547            NewIntentData data = new NewIntentData();
1548            data.intents = intents;
1549            data.token = token;
1550
1551            queueOrSendMessage(H.NEW_INTENT, data);
1552        }
1553
1554        public final void scheduleDestroyActivity(IBinder token, boolean finishing,
1555                int configChanges) {
1556            queueOrSendMessage(H.DESTROY_ACTIVITY, token, finishing ? 1 : 0,
1557                    configChanges);
1558        }
1559
1560        public final void scheduleReceiver(Intent intent, ActivityInfo info,
1561                int resultCode, String data, Bundle extras, boolean sync) {
1562            ReceiverData r = new ReceiverData();
1563
1564            r.intent = intent;
1565            r.info = info;
1566            r.resultCode = resultCode;
1567            r.resultData = data;
1568            r.resultExtras = extras;
1569            r.sync = sync;
1570
1571            queueOrSendMessage(H.RECEIVER, r);
1572        }
1573
1574        public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) {
1575            CreateBackupAgentData d = new CreateBackupAgentData();
1576            d.appInfo = app;
1577            d.backupMode = backupMode;
1578
1579            queueOrSendMessage(H.CREATE_BACKUP_AGENT, d);
1580        }
1581
1582        public final void scheduleDestroyBackupAgent(ApplicationInfo app) {
1583            CreateBackupAgentData d = new CreateBackupAgentData();
1584            d.appInfo = app;
1585
1586            queueOrSendMessage(H.DESTROY_BACKUP_AGENT, d);
1587        }
1588
1589        public final void scheduleCreateService(IBinder token,
1590                ServiceInfo info) {
1591            CreateServiceData s = new CreateServiceData();
1592            s.token = token;
1593            s.info = info;
1594
1595            queueOrSendMessage(H.CREATE_SERVICE, s);
1596        }
1597
1598        public final void scheduleBindService(IBinder token, Intent intent,
1599                boolean rebind) {
1600            BindServiceData s = new BindServiceData();
1601            s.token = token;
1602            s.intent = intent;
1603            s.rebind = rebind;
1604
1605            queueOrSendMessage(H.BIND_SERVICE, s);
1606        }
1607
1608        public final void scheduleUnbindService(IBinder token, Intent intent) {
1609            BindServiceData s = new BindServiceData();
1610            s.token = token;
1611            s.intent = intent;
1612
1613            queueOrSendMessage(H.UNBIND_SERVICE, s);
1614        }
1615
1616        public final void scheduleServiceArgs(IBinder token, int startId,
1617            int flags ,Intent args) {
1618            ServiceArgsData s = new ServiceArgsData();
1619            s.token = token;
1620            s.startId = startId;
1621            s.flags = flags;
1622            s.args = args;
1623
1624            queueOrSendMessage(H.SERVICE_ARGS, s);
1625        }
1626
1627        public final void scheduleStopService(IBinder token) {
1628            queueOrSendMessage(H.STOP_SERVICE, token);
1629        }
1630
1631        public final void bindApplication(String processName,
1632                ApplicationInfo appInfo, List<ProviderInfo> providers,
1633                ComponentName instrumentationName, String profileFile,
1634                Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
1635                int debugMode, boolean isRestrictedBackupMode, Configuration config,
1636                Map<String, IBinder> services) {
1637
1638            if (services != null) {
1639                // Setup the service cache in the ServiceManager
1640                ServiceManager.initServiceCache(services);
1641            }
1642
1643            AppBindData data = new AppBindData();
1644            data.processName = processName;
1645            data.appInfo = appInfo;
1646            data.providers = providers;
1647            data.instrumentationName = instrumentationName;
1648            data.profileFile = profileFile;
1649            data.instrumentationArgs = instrumentationArgs;
1650            data.instrumentationWatcher = instrumentationWatcher;
1651            data.debugMode = debugMode;
1652            data.restrictedBackupMode = isRestrictedBackupMode;
1653            data.config = config;
1654            queueOrSendMessage(H.BIND_APPLICATION, data);
1655        }
1656
1657        public final void scheduleExit() {
1658            queueOrSendMessage(H.EXIT_APPLICATION, null);
1659        }
1660
1661        public final void scheduleSuicide() {
1662            queueOrSendMessage(H.SUICIDE, null);
1663        }
1664
1665        public void requestThumbnail(IBinder token) {
1666            queueOrSendMessage(H.REQUEST_THUMBNAIL, token);
1667        }
1668
1669        public void scheduleConfigurationChanged(Configuration config) {
1670            synchronized (mPackages) {
1671                if (mPendingConfiguration == null ||
1672                        mPendingConfiguration.isOtherSeqNewer(config)) {
1673                    mPendingConfiguration = config;
1674                }
1675            }
1676            queueOrSendMessage(H.CONFIGURATION_CHANGED, config);
1677        }
1678
1679        public void updateTimeZone() {
1680            TimeZone.setDefault(null);
1681        }
1682
1683        public void processInBackground() {
1684            mH.removeMessages(H.GC_WHEN_IDLE);
1685            mH.sendMessage(mH.obtainMessage(H.GC_WHEN_IDLE));
1686        }
1687
1688        public void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args) {
1689            DumpServiceInfo data = new DumpServiceInfo();
1690            data.fd = fd;
1691            data.service = servicetoken;
1692            data.args = args;
1693            data.dumped = false;
1694            queueOrSendMessage(H.DUMP_SERVICE, data);
1695            synchronized (data) {
1696                while (!data.dumped) {
1697                    try {
1698                        data.wait();
1699                    } catch (InterruptedException e) {
1700                        // no need to do anything here, we will keep waiting until
1701                        // dumped is set
1702                    }
1703                }
1704            }
1705        }
1706
1707        // This function exists to make sure all receiver dispatching is
1708        // correctly ordered, since these are one-way calls and the binder driver
1709        // applies transaction ordering per object for such calls.
1710        public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
1711                int resultCode, String dataStr, Bundle extras, boolean ordered,
1712                boolean sticky) throws RemoteException {
1713            receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);
1714        }
1715
1716        public void scheduleLowMemory() {
1717            queueOrSendMessage(H.LOW_MEMORY, null);
1718        }
1719
1720        public void scheduleActivityConfigurationChanged(IBinder token) {
1721            queueOrSendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token);
1722        }
1723
1724        public void requestPss() {
1725            try {
1726                ActivityManagerNative.getDefault().reportPss(this,
1727                        (int)Process.getPss(Process.myPid()));
1728            } catch (RemoteException e) {
1729            }
1730        }
1731
1732        public void profilerControl(boolean start, String path, ParcelFileDescriptor fd) {
1733            ProfilerControlData pcd = new ProfilerControlData();
1734            pcd.path = path;
1735            pcd.fd = fd;
1736            queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0);
1737        }
1738
1739        public void setSchedulingGroup(int group) {
1740            // Note: do this immediately, since going into the foreground
1741            // should happen regardless of what pending work we have to do
1742            // and the activity manager will wait for us to report back that
1743            // we are done before sending us to the background.
1744            try {
1745                Process.setProcessGroup(Process.myPid(), group);
1746            } catch (Exception e) {
1747                Slog.w(TAG, "Failed setting process group to " + group, e);
1748            }
1749        }
1750
1751        public void getMemoryInfo(Debug.MemoryInfo outInfo) {
1752            Debug.getMemoryInfo(outInfo);
1753        }
1754
1755        public void dispatchPackageBroadcast(int cmd, String[] packages) {
1756            queueOrSendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);
1757        }
1758
1759        @Override
1760        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1761            long nativeMax = Debug.getNativeHeapSize() / 1024;
1762            long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
1763            long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
1764
1765            Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
1766            Debug.getMemoryInfo(memInfo);
1767
1768            final int nativeShared = memInfo.nativeSharedDirty;
1769            final int dalvikShared = memInfo.dalvikSharedDirty;
1770            final int otherShared = memInfo.otherSharedDirty;
1771
1772            final int nativePrivate = memInfo.nativePrivateDirty;
1773            final int dalvikPrivate = memInfo.dalvikPrivateDirty;
1774            final int otherPrivate = memInfo.otherPrivateDirty;
1775
1776            Runtime runtime = Runtime.getRuntime();
1777
1778            long dalvikMax = runtime.totalMemory() / 1024;
1779            long dalvikFree = runtime.freeMemory() / 1024;
1780            long dalvikAllocated = dalvikMax - dalvikFree;
1781            long viewInstanceCount = ViewDebug.getViewInstanceCount();
1782            long viewRootInstanceCount = ViewDebug.getViewRootInstanceCount();
1783            long appContextInstanceCount = ContextImpl.getInstanceCount();
1784            long activityInstanceCount = Activity.getInstanceCount();
1785            int globalAssetCount = AssetManager.getGlobalAssetCount();
1786            int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
1787            int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
1788            int binderProxyObjectCount = Debug.getBinderProxyObjectCount();
1789            int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
1790            int openSslSocketCount = OpenSSLSocketImpl.getInstanceCount();
1791            long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
1792            SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
1793
1794            // Check to see if we were called by checkin server. If so, print terse format.
1795            boolean doCheckinFormat = false;
1796            if (args != null) {
1797                for (String arg : args) {
1798                    if ("-c".equals(arg)) doCheckinFormat = true;
1799                }
1800            }
1801
1802            // For checkin, we print one long comma-separated list of values
1803            if (doCheckinFormat) {
1804                // NOTE: if you change anything significant below, also consider changing
1805                // ACTIVITY_THREAD_CHECKIN_VERSION.
1806                String processName = (mBoundApplication != null)
1807                        ? mBoundApplication.processName : "unknown";
1808
1809                // Header
1810                pw.print(ACTIVITY_THREAD_CHECKIN_VERSION); pw.print(',');
1811                pw.print(Process.myPid()); pw.print(',');
1812                pw.print(processName); pw.print(',');
1813
1814                // Heap info - max
1815                pw.print(nativeMax); pw.print(',');
1816                pw.print(dalvikMax); pw.print(',');
1817                pw.print("N/A,");
1818                pw.print(nativeMax + dalvikMax); pw.print(',');
1819
1820                // Heap info - allocated
1821                pw.print(nativeAllocated); pw.print(',');
1822                pw.print(dalvikAllocated); pw.print(',');
1823                pw.print("N/A,");
1824                pw.print(nativeAllocated + dalvikAllocated); pw.print(',');
1825
1826                // Heap info - free
1827                pw.print(nativeFree); pw.print(',');
1828                pw.print(dalvikFree); pw.print(',');
1829                pw.print("N/A,");
1830                pw.print(nativeFree + dalvikFree); pw.print(',');
1831
1832                // Heap info - proportional set size
1833                pw.print(memInfo.nativePss); pw.print(',');
1834                pw.print(memInfo.dalvikPss); pw.print(',');
1835                pw.print(memInfo.otherPss); pw.print(',');
1836                pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
1837
1838                // Heap info - shared
1839                pw.print(nativeShared); pw.print(',');
1840                pw.print(dalvikShared); pw.print(',');
1841                pw.print(otherShared); pw.print(',');
1842                pw.print(nativeShared + dalvikShared + otherShared); pw.print(',');
1843
1844                // Heap info - private
1845                pw.print(nativePrivate); pw.print(',');
1846                pw.print(dalvikPrivate); pw.print(',');
1847                pw.print(otherPrivate); pw.print(',');
1848                pw.print(nativePrivate + dalvikPrivate + otherPrivate); pw.print(',');
1849
1850                // Object counts
1851                pw.print(viewInstanceCount); pw.print(',');
1852                pw.print(viewRootInstanceCount); pw.print(',');
1853                pw.print(appContextInstanceCount); pw.print(',');
1854                pw.print(activityInstanceCount); pw.print(',');
1855
1856                pw.print(globalAssetCount); pw.print(',');
1857                pw.print(globalAssetManagerCount); pw.print(',');
1858                pw.print(binderLocalObjectCount); pw.print(',');
1859                pw.print(binderProxyObjectCount); pw.print(',');
1860
1861                pw.print(binderDeathObjectCount); pw.print(',');
1862                pw.print(openSslSocketCount); pw.print(',');
1863
1864                // SQL
1865                pw.print(sqliteAllocated); pw.print(',');
1866                pw.print(stats.memoryUsed / 1024); pw.print(',');
1867                pw.print(stats.pageCacheOverflo / 1024); pw.print(',');
1868                pw.print(stats.largestMemAlloc / 1024); pw.print(',');
1869                for (int i = 0; i < stats.dbStats.size(); i++) {
1870                    DbStats dbStats = stats.dbStats.get(i);
1871                    printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
1872                            dbStats.lookaside, dbStats.cache, dbStats.dbName);
1873                    pw.print(',');
1874                }
1875
1876                return;
1877            }
1878
1879            // otherwise, show human-readable format
1880            printRow(pw, HEAP_COLUMN, "", "native", "dalvik", "other", "total");
1881            printRow(pw, HEAP_COLUMN, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
1882            printRow(pw, HEAP_COLUMN, "allocated:", nativeAllocated, dalvikAllocated, "N/A",
1883                    nativeAllocated + dalvikAllocated);
1884            printRow(pw, HEAP_COLUMN, "free:", nativeFree, dalvikFree, "N/A",
1885                    nativeFree + dalvikFree);
1886
1887            printRow(pw, HEAP_COLUMN, "(Pss):", memInfo.nativePss, memInfo.dalvikPss,
1888                    memInfo.otherPss, memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss);
1889
1890            printRow(pw, HEAP_COLUMN, "(shared dirty):", nativeShared, dalvikShared, otherShared,
1891                    nativeShared + dalvikShared + otherShared);
1892            printRow(pw, HEAP_COLUMN, "(priv dirty):", nativePrivate, dalvikPrivate, otherPrivate,
1893                    nativePrivate + dalvikPrivate + otherPrivate);
1894
1895            pw.println(" ");
1896            pw.println(" Objects");
1897            printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRoots:",
1898                    viewRootInstanceCount);
1899
1900            printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount,
1901                    "Activities:", activityInstanceCount);
1902
1903            printRow(pw, TWO_COUNT_COLUMNS, "Assets:", globalAssetCount,
1904                    "AssetManagers:", globalAssetManagerCount);
1905
1906            printRow(pw, TWO_COUNT_COLUMNS, "Local Binders:", binderLocalObjectCount,
1907                    "Proxy Binders:", binderProxyObjectCount);
1908            printRow(pw, ONE_COUNT_COLUMN, "Death Recipients:", binderDeathObjectCount);
1909
1910            printRow(pw, ONE_COUNT_COLUMN, "OpenSSL Sockets:", openSslSocketCount);
1911
1912            // SQLite mem info
1913            pw.println(" ");
1914            pw.println(" SQL");
1915            printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "memoryUsed:",
1916                    stats.memoryUsed / 1024);
1917            printRow(pw, TWO_COUNT_COLUMNS, "pageCacheOverflo:", stats.pageCacheOverflo / 1024,
1918                    "largestMemAlloc:", stats.largestMemAlloc / 1024);
1919            pw.println(" ");
1920            int N = stats.dbStats.size();
1921            if (N > 0) {
1922                pw.println(" DATABASES");
1923                printRow(pw, "  %4s %6s %8s %14s  %s", "pgsz", "dbsz", "lkaside", "cache",
1924                    "Dbname");
1925                for (int i = 0; i < N; i++) {
1926                    DbStats dbStats = stats.dbStats.get(i);
1927                    printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
1928                            dbStats.lookaside, dbStats.cache, dbStats.dbName);
1929                }
1930            }
1931
1932            // Asset details.
1933            String assetAlloc = AssetManager.getAssetAllocations();
1934            if (assetAlloc != null) {
1935                pw.println(" ");
1936                pw.println(" Asset Allocations");
1937                pw.print(assetAlloc);
1938            }
1939        }
1940
1941        private void printRow(PrintWriter pw, String format, Object...objs) {
1942            pw.println(String.format(format, objs));
1943        }
1944    }
1945
1946    private final class H extends Handler {
1947        private H() {
1948            SamplingProfiler.getInstance().setEventThread(mLooper.getThread());
1949        }
1950
1951        public static final int LAUNCH_ACTIVITY         = 100;
1952        public static final int PAUSE_ACTIVITY          = 101;
1953        public static final int PAUSE_ACTIVITY_FINISHING= 102;
1954        public static final int STOP_ACTIVITY_SHOW      = 103;
1955        public static final int STOP_ACTIVITY_HIDE      = 104;
1956        public static final int SHOW_WINDOW             = 105;
1957        public static final int HIDE_WINDOW             = 106;
1958        public static final int RESUME_ACTIVITY         = 107;
1959        public static final int SEND_RESULT             = 108;
1960        public static final int DESTROY_ACTIVITY         = 109;
1961        public static final int BIND_APPLICATION        = 110;
1962        public static final int EXIT_APPLICATION        = 111;
1963        public static final int NEW_INTENT              = 112;
1964        public static final int RECEIVER                = 113;
1965        public static final int CREATE_SERVICE          = 114;
1966        public static final int SERVICE_ARGS            = 115;
1967        public static final int STOP_SERVICE            = 116;
1968        public static final int REQUEST_THUMBNAIL       = 117;
1969        public static final int CONFIGURATION_CHANGED   = 118;
1970        public static final int CLEAN_UP_CONTEXT        = 119;
1971        public static final int GC_WHEN_IDLE            = 120;
1972        public static final int BIND_SERVICE            = 121;
1973        public static final int UNBIND_SERVICE          = 122;
1974        public static final int DUMP_SERVICE            = 123;
1975        public static final int LOW_MEMORY              = 124;
1976        public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
1977        public static final int RELAUNCH_ACTIVITY       = 126;
1978        public static final int PROFILER_CONTROL        = 127;
1979        public static final int CREATE_BACKUP_AGENT     = 128;
1980        public static final int DESTROY_BACKUP_AGENT    = 129;
1981        public static final int SUICIDE                 = 130;
1982        public static final int REMOVE_PROVIDER         = 131;
1983        public static final int ENABLE_JIT              = 132;
1984        public static final int DISPATCH_PACKAGE_BROADCAST = 133;
1985        String codeToString(int code) {
1986            if (localLOGV) {
1987                switch (code) {
1988                    case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
1989                    case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY";
1990                    case PAUSE_ACTIVITY_FINISHING: return "PAUSE_ACTIVITY_FINISHING";
1991                    case STOP_ACTIVITY_SHOW: return "STOP_ACTIVITY_SHOW";
1992                    case STOP_ACTIVITY_HIDE: return "STOP_ACTIVITY_HIDE";
1993                    case SHOW_WINDOW: return "SHOW_WINDOW";
1994                    case HIDE_WINDOW: return "HIDE_WINDOW";
1995                    case RESUME_ACTIVITY: return "RESUME_ACTIVITY";
1996                    case SEND_RESULT: return "SEND_RESULT";
1997                    case DESTROY_ACTIVITY: return "DESTROY_ACTIVITY";
1998                    case BIND_APPLICATION: return "BIND_APPLICATION";
1999                    case EXIT_APPLICATION: return "EXIT_APPLICATION";
2000                    case NEW_INTENT: return "NEW_INTENT";
2001                    case RECEIVER: return "RECEIVER";
2002                    case CREATE_SERVICE: return "CREATE_SERVICE";
2003                    case SERVICE_ARGS: return "SERVICE_ARGS";
2004                    case STOP_SERVICE: return "STOP_SERVICE";
2005                    case REQUEST_THUMBNAIL: return "REQUEST_THUMBNAIL";
2006                    case CONFIGURATION_CHANGED: return "CONFIGURATION_CHANGED";
2007                    case CLEAN_UP_CONTEXT: return "CLEAN_UP_CONTEXT";
2008                    case GC_WHEN_IDLE: return "GC_WHEN_IDLE";
2009                    case BIND_SERVICE: return "BIND_SERVICE";
2010                    case UNBIND_SERVICE: return "UNBIND_SERVICE";
2011                    case DUMP_SERVICE: return "DUMP_SERVICE";
2012                    case LOW_MEMORY: return "LOW_MEMORY";
2013                    case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED";
2014                    case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
2015                    case PROFILER_CONTROL: return "PROFILER_CONTROL";
2016                    case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
2017                    case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
2018                    case SUICIDE: return "SUICIDE";
2019                    case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
2020                    case ENABLE_JIT: return "ENABLE_JIT";
2021                    case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST";
2022                }
2023            }
2024            return "(unknown)";
2025        }
2026        public void handleMessage(Message msg) {
2027            switch (msg.what) {
2028                case LAUNCH_ACTIVITY: {
2029                    ActivityRecord r = (ActivityRecord)msg.obj;
2030
2031                    r.packageInfo = getPackageInfoNoCheck(
2032                            r.activityInfo.applicationInfo);
2033                    handleLaunchActivity(r, null);
2034                } break;
2035                case RELAUNCH_ACTIVITY: {
2036                    ActivityRecord r = (ActivityRecord)msg.obj;
2037                    handleRelaunchActivity(r, msg.arg1);
2038                } break;
2039                case PAUSE_ACTIVITY:
2040                    handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
2041                    maybeSnapshot();
2042                    break;
2043                case PAUSE_ACTIVITY_FINISHING:
2044                    handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
2045                    break;
2046                case STOP_ACTIVITY_SHOW:
2047                    handleStopActivity((IBinder)msg.obj, true, msg.arg2);
2048                    break;
2049                case STOP_ACTIVITY_HIDE:
2050                    handleStopActivity((IBinder)msg.obj, false, msg.arg2);
2051                    break;
2052                case SHOW_WINDOW:
2053                    handleWindowVisibility((IBinder)msg.obj, true);
2054                    break;
2055                case HIDE_WINDOW:
2056                    handleWindowVisibility((IBinder)msg.obj, false);
2057                    break;
2058                case RESUME_ACTIVITY:
2059                    handleResumeActivity((IBinder)msg.obj, true,
2060                            msg.arg1 != 0);
2061                    break;
2062                case SEND_RESULT:
2063                    handleSendResult((ResultData)msg.obj);
2064                    break;
2065                case DESTROY_ACTIVITY:
2066                    handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
2067                            msg.arg2, false);
2068                    break;
2069                case BIND_APPLICATION:
2070                    AppBindData data = (AppBindData)msg.obj;
2071                    handleBindApplication(data);
2072                    break;
2073                case EXIT_APPLICATION:
2074                    if (mInitialApplication != null) {
2075                        mInitialApplication.onTerminate();
2076                    }
2077                    Looper.myLooper().quit();
2078                    break;
2079                case NEW_INTENT:
2080                    handleNewIntent((NewIntentData)msg.obj);
2081                    break;
2082                case RECEIVER:
2083                    handleReceiver((ReceiverData)msg.obj);
2084                    maybeSnapshot();
2085                    break;
2086                case CREATE_SERVICE:
2087                    handleCreateService((CreateServiceData)msg.obj);
2088                    break;
2089                case BIND_SERVICE:
2090                    handleBindService((BindServiceData)msg.obj);
2091                    break;
2092                case UNBIND_SERVICE:
2093                    handleUnbindService((BindServiceData)msg.obj);
2094                    break;
2095                case SERVICE_ARGS:
2096                    handleServiceArgs((ServiceArgsData)msg.obj);
2097                    break;
2098                case STOP_SERVICE:
2099                    handleStopService((IBinder)msg.obj);
2100                    maybeSnapshot();
2101                    break;
2102                case REQUEST_THUMBNAIL:
2103                    handleRequestThumbnail((IBinder)msg.obj);
2104                    break;
2105                case CONFIGURATION_CHANGED:
2106                    handleConfigurationChanged((Configuration)msg.obj);
2107                    break;
2108                case CLEAN_UP_CONTEXT:
2109                    ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
2110                    cci.context.performFinalCleanup(cci.who, cci.what);
2111                    break;
2112                case GC_WHEN_IDLE:
2113                    scheduleGcIdler();
2114                    break;
2115                case DUMP_SERVICE:
2116                    handleDumpService((DumpServiceInfo)msg.obj);
2117                    break;
2118                case LOW_MEMORY:
2119                    handleLowMemory();
2120                    break;
2121                case ACTIVITY_CONFIGURATION_CHANGED:
2122                    handleActivityConfigurationChanged((IBinder)msg.obj);
2123                    break;
2124                case PROFILER_CONTROL:
2125                    handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj);
2126                    break;
2127                case CREATE_BACKUP_AGENT:
2128                    handleCreateBackupAgent((CreateBackupAgentData)msg.obj);
2129                    break;
2130                case DESTROY_BACKUP_AGENT:
2131                    handleDestroyBackupAgent((CreateBackupAgentData)msg.obj);
2132                    break;
2133                case SUICIDE:
2134                    Process.killProcess(Process.myPid());
2135                    break;
2136                case REMOVE_PROVIDER:
2137                    completeRemoveProvider((IContentProvider)msg.obj);
2138                    break;
2139                case ENABLE_JIT:
2140                    ensureJitEnabled();
2141                    break;
2142                case DISPATCH_PACKAGE_BROADCAST:
2143                    handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
2144                    break;
2145            }
2146        }
2147
2148        void maybeSnapshot() {
2149            if (mBoundApplication != null) {
2150                SamplingProfilerIntegration.writeSnapshot(
2151                        mBoundApplication.processName);
2152            }
2153        }
2154    }
2155
2156    private final class Idler implements MessageQueue.IdleHandler {
2157        public final boolean queueIdle() {
2158            ActivityRecord a = mNewActivities;
2159            if (a != null) {
2160                mNewActivities = null;
2161                IActivityManager am = ActivityManagerNative.getDefault();
2162                ActivityRecord prev;
2163                do {
2164                    if (localLOGV) Slog.v(
2165                        TAG, "Reporting idle of " + a +
2166                        " finished=" +
2167                        (a.activity != null ? a.activity.mFinished : false));
2168                    if (a.activity != null && !a.activity.mFinished) {
2169                        try {
2170                            am.activityIdle(a.token, a.createdConfig);
2171                            a.createdConfig = null;
2172                        } catch (RemoteException ex) {
2173                        }
2174                    }
2175                    prev = a;
2176                    a = a.nextIdle;
2177                    prev.nextIdle = null;
2178                } while (a != null);
2179            }
2180            ensureJitEnabled();
2181            return false;
2182        }
2183    }
2184
2185    final class GcIdler implements MessageQueue.IdleHandler {
2186        public final boolean queueIdle() {
2187            doGcIfNeeded();
2188            return false;
2189        }
2190    }
2191
2192    private final static class ResourcesKey {
2193        final private String mResDir;
2194        final private float mScale;
2195        final private int mHash;
2196
2197        ResourcesKey(String resDir, float scale) {
2198            mResDir = resDir;
2199            mScale = scale;
2200            mHash = mResDir.hashCode() << 2 + (int) (mScale * 2);
2201        }
2202
2203        @Override
2204        public int hashCode() {
2205            return mHash;
2206        }
2207
2208        @Override
2209        public boolean equals(Object obj) {
2210            if (!(obj instanceof ResourcesKey)) {
2211                return false;
2212            }
2213            ResourcesKey peer = (ResourcesKey) obj;
2214            return mResDir.equals(peer.mResDir) && mScale == peer.mScale;
2215        }
2216    }
2217
2218    static IPackageManager sPackageManager;
2219
2220    final ApplicationThread mAppThread = new ApplicationThread();
2221    final Looper mLooper = Looper.myLooper();
2222    final H mH = new H();
2223    final HashMap<IBinder, ActivityRecord> mActivities
2224            = new HashMap<IBinder, ActivityRecord>();
2225    // List of new activities (via ActivityRecord.nextIdle) that should
2226    // be reported when next we idle.
2227    ActivityRecord mNewActivities = null;
2228    // Number of activities that are currently visible on-screen.
2229    int mNumVisibleActivities = 0;
2230    final HashMap<IBinder, Service> mServices
2231            = new HashMap<IBinder, Service>();
2232    AppBindData mBoundApplication;
2233    Configuration mConfiguration;
2234    Configuration mResConfiguration;
2235    Application mInitialApplication;
2236    final ArrayList<Application> mAllApplications
2237            = new ArrayList<Application>();
2238    // set of instantiated backup agents, keyed by package name
2239    final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>();
2240    static final ThreadLocal sThreadLocal = new ThreadLocal();
2241    Instrumentation mInstrumentation;
2242    String mInstrumentationAppDir = null;
2243    String mInstrumentationAppPackage = null;
2244    String mInstrumentedAppDir = null;
2245    boolean mSystemThread = false;
2246    boolean mJitEnabled = false;
2247
2248    // These can be accessed by multiple threads; mPackages is the lock.
2249    // XXX For now we keep around information about all packages we have
2250    // seen, not removing entries from this map.
2251    final HashMap<String, WeakReference<PackageInfo>> mPackages
2252            = new HashMap<String, WeakReference<PackageInfo>>();
2253    final HashMap<String, WeakReference<PackageInfo>> mResourcePackages
2254            = new HashMap<String, WeakReference<PackageInfo>>();
2255    Display mDisplay = null;
2256    DisplayMetrics mDisplayMetrics = null;
2257    final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
2258            = new HashMap<ResourcesKey, WeakReference<Resources> >();
2259    final ArrayList<ActivityRecord> mRelaunchingActivities
2260            = new ArrayList<ActivityRecord>();
2261    Configuration mPendingConfiguration = null;
2262
2263    // The lock of mProviderMap protects the following variables.
2264    final HashMap<String, ProviderRecord> mProviderMap
2265        = new HashMap<String, ProviderRecord>();
2266    final HashMap<IBinder, ProviderRefCount> mProviderRefCountMap
2267        = new HashMap<IBinder, ProviderRefCount>();
2268    final HashMap<IBinder, ProviderRecord> mLocalProviders
2269        = new HashMap<IBinder, ProviderRecord>();
2270
2271    final GcIdler mGcIdler = new GcIdler();
2272    boolean mGcIdlerScheduled = false;
2273
2274    public final PackageInfo getPackageInfo(String packageName, int flags) {
2275        synchronized (mPackages) {
2276            WeakReference<PackageInfo> ref;
2277            if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) {
2278                ref = mPackages.get(packageName);
2279            } else {
2280                ref = mResourcePackages.get(packageName);
2281            }
2282            PackageInfo packageInfo = ref != null ? ref.get() : null;
2283            //Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo);
2284            //if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir
2285            //        + ": " + packageInfo.mResources.getAssets().isUpToDate());
2286            if (packageInfo != null && (packageInfo.mResources == null
2287                    || packageInfo.mResources.getAssets().isUpToDate())) {
2288                if (packageInfo.isSecurityViolation()
2289                        && (flags&Context.CONTEXT_IGNORE_SECURITY) == 0) {
2290                    throw new SecurityException(
2291                            "Requesting code from " + packageName
2292                            + " to be run in process "
2293                            + mBoundApplication.processName
2294                            + "/" + mBoundApplication.appInfo.uid);
2295                }
2296                return packageInfo;
2297            }
2298        }
2299
2300        ApplicationInfo ai = null;
2301        try {
2302            ai = getPackageManager().getApplicationInfo(packageName,
2303                    PackageManager.GET_SHARED_LIBRARY_FILES);
2304        } catch (RemoteException e) {
2305        }
2306
2307        if (ai != null) {
2308            return getPackageInfo(ai, flags);
2309        }
2310
2311        return null;
2312    }
2313
2314    public final PackageInfo getPackageInfo(ApplicationInfo ai, int flags) {
2315        boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
2316        boolean securityViolation = includeCode && ai.uid != 0
2317                && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
2318                        ? ai.uid != mBoundApplication.appInfo.uid : true);
2319        if ((flags&(Context.CONTEXT_INCLUDE_CODE
2320                |Context.CONTEXT_IGNORE_SECURITY))
2321                == Context.CONTEXT_INCLUDE_CODE) {
2322            if (securityViolation) {
2323                String msg = "Requesting code from " + ai.packageName
2324                        + " (with uid " + ai.uid + ")";
2325                if (mBoundApplication != null) {
2326                    msg = msg + " to be run in process "
2327                        + mBoundApplication.processName + " (with uid "
2328                        + mBoundApplication.appInfo.uid + ")";
2329                }
2330                throw new SecurityException(msg);
2331            }
2332        }
2333        return getPackageInfo(ai, null, securityViolation, includeCode);
2334    }
2335
2336    public final PackageInfo getPackageInfoNoCheck(ApplicationInfo ai) {
2337        return getPackageInfo(ai, null, false, true);
2338    }
2339
2340    private final PackageInfo getPackageInfo(ApplicationInfo aInfo,
2341            ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
2342        synchronized (mPackages) {
2343            WeakReference<PackageInfo> ref;
2344            if (includeCode) {
2345                ref = mPackages.get(aInfo.packageName);
2346            } else {
2347                ref = mResourcePackages.get(aInfo.packageName);
2348            }
2349            PackageInfo packageInfo = ref != null ? ref.get() : null;
2350            if (packageInfo == null || (packageInfo.mResources != null
2351                    && !packageInfo.mResources.getAssets().isUpToDate())) {
2352                if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package "
2353                        : "Loading resource-only package ") + aInfo.packageName
2354                        + " (in " + (mBoundApplication != null
2355                                ? mBoundApplication.processName : null)
2356                        + ")");
2357                packageInfo =
2358                    new PackageInfo(this, aInfo, this, baseLoader,
2359                            securityViolation, includeCode &&
2360                            (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);
2361                if (includeCode) {
2362                    mPackages.put(aInfo.packageName,
2363                            new WeakReference<PackageInfo>(packageInfo));
2364                } else {
2365                    mResourcePackages.put(aInfo.packageName,
2366                            new WeakReference<PackageInfo>(packageInfo));
2367                }
2368            }
2369            return packageInfo;
2370        }
2371    }
2372
2373    ActivityThread() {
2374    }
2375
2376    public ApplicationThread getApplicationThread()
2377    {
2378        return mAppThread;
2379    }
2380
2381    public Instrumentation getInstrumentation()
2382    {
2383        return mInstrumentation;
2384    }
2385
2386    public Configuration getConfiguration() {
2387        return mConfiguration;
2388    }
2389
2390    public boolean isProfiling() {
2391        return mBoundApplication != null && mBoundApplication.profileFile != null;
2392    }
2393
2394    public String getProfileFilePath() {
2395        return mBoundApplication.profileFile;
2396    }
2397
2398    public Looper getLooper() {
2399        return mLooper;
2400    }
2401
2402    public Application getApplication() {
2403        return mInitialApplication;
2404    }
2405
2406    public String getProcessName() {
2407        return mBoundApplication.processName;
2408    }
2409
2410    public ContextImpl getSystemContext() {
2411        synchronized (this) {
2412            if (mSystemContext == null) {
2413                ContextImpl context =
2414                    ContextImpl.createSystemContext(this);
2415                PackageInfo info = new PackageInfo(this, "android", context, null);
2416                context.init(info, null, this);
2417                context.getResources().updateConfiguration(
2418                        getConfiguration(), getDisplayMetricsLocked(false));
2419                mSystemContext = context;
2420                //Slog.i(TAG, "Created system resources " + context.getResources()
2421                //        + ": " + context.getResources().getConfiguration());
2422            }
2423        }
2424        return mSystemContext;
2425    }
2426
2427    public void installSystemApplicationInfo(ApplicationInfo info) {
2428        synchronized (this) {
2429            ContextImpl context = getSystemContext();
2430            context.init(new PackageInfo(this, "android", context, info), null, this);
2431        }
2432    }
2433
2434    void ensureJitEnabled() {
2435        if (!mJitEnabled) {
2436            mJitEnabled = true;
2437            dalvik.system.VMRuntime.getRuntime().startJitCompilation();
2438        }
2439    }
2440
2441    void scheduleGcIdler() {
2442        if (!mGcIdlerScheduled) {
2443            mGcIdlerScheduled = true;
2444            Looper.myQueue().addIdleHandler(mGcIdler);
2445        }
2446        mH.removeMessages(H.GC_WHEN_IDLE);
2447    }
2448
2449    void unscheduleGcIdler() {
2450        if (mGcIdlerScheduled) {
2451            mGcIdlerScheduled = false;
2452            Looper.myQueue().removeIdleHandler(mGcIdler);
2453        }
2454        mH.removeMessages(H.GC_WHEN_IDLE);
2455    }
2456
2457    void doGcIfNeeded() {
2458        mGcIdlerScheduled = false;
2459        final long now = SystemClock.uptimeMillis();
2460        //Slog.i(TAG, "**** WE MIGHT WANT TO GC: then=" + Binder.getLastGcTime()
2461        //        + "m now=" + now);
2462        if ((BinderInternal.getLastGcTime()+MIN_TIME_BETWEEN_GCS) < now) {
2463            //Slog.i(TAG, "**** WE DO, WE DO WANT TO GC!");
2464            BinderInternal.forceGc("bg");
2465        }
2466    }
2467
2468    public final ActivityInfo resolveActivityInfo(Intent intent) {
2469        ActivityInfo aInfo = intent.resolveActivityInfo(
2470                mInitialApplication.getPackageManager(), PackageManager.GET_SHARED_LIBRARY_FILES);
2471        if (aInfo == null) {
2472            // Throw an exception.
2473            Instrumentation.checkStartActivityResult(
2474                    IActivityManager.START_CLASS_NOT_FOUND, intent);
2475        }
2476        return aInfo;
2477    }
2478
2479    public final Activity startActivityNow(Activity parent, String id,
2480        Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
2481        Activity.NonConfigurationInstances lastNonConfigurationInstances) {
2482        ActivityRecord r = new ActivityRecord();
2483            r.token = token;
2484            r.ident = 0;
2485            r.intent = intent;
2486            r.state = state;
2487            r.parent = parent;
2488            r.embeddedID = id;
2489            r.activityInfo = activityInfo;
2490            r.lastNonConfigurationInstances = lastNonConfigurationInstances;
2491        if (localLOGV) {
2492            ComponentName compname = intent.getComponent();
2493            String name;
2494            if (compname != null) {
2495                name = compname.toShortString();
2496            } else {
2497                name = "(Intent " + intent + ").getComponent() returned null";
2498            }
2499            Slog.v(TAG, "Performing launch: action=" + intent.getAction()
2500                    + ", comp=" + name
2501                    + ", token=" + token);
2502        }
2503        return performLaunchActivity(r, null);
2504    }
2505
2506    public final Activity getActivity(IBinder token) {
2507        return mActivities.get(token).activity;
2508    }
2509
2510    public final void sendActivityResult(
2511            IBinder token, String id, int requestCode,
2512            int resultCode, Intent data) {
2513        if (DEBUG_RESULTS) Slog.v(TAG, "sendActivityResult: id=" + id
2514                + " req=" + requestCode + " res=" + resultCode + " data=" + data);
2515        ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
2516        list.add(new ResultInfo(id, requestCode, resultCode, data));
2517        mAppThread.scheduleSendResult(token, list);
2518    }
2519
2520    // if the thread hasn't started yet, we don't have the handler, so just
2521    // save the messages until we're ready.
2522    private final void queueOrSendMessage(int what, Object obj) {
2523        queueOrSendMessage(what, obj, 0, 0);
2524    }
2525
2526    private final void queueOrSendMessage(int what, Object obj, int arg1) {
2527        queueOrSendMessage(what, obj, arg1, 0);
2528    }
2529
2530    private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
2531        synchronized (this) {
2532            if (localLOGV) Slog.v(
2533                TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
2534                + ": " + arg1 + " / " + obj);
2535            Message msg = Message.obtain();
2536            msg.what = what;
2537            msg.obj = obj;
2538            msg.arg1 = arg1;
2539            msg.arg2 = arg2;
2540            mH.sendMessage(msg);
2541        }
2542    }
2543
2544    final void scheduleContextCleanup(ContextImpl context, String who,
2545            String what) {
2546        ContextCleanupInfo cci = new ContextCleanupInfo();
2547        cci.context = context;
2548        cci.who = who;
2549        cci.what = what;
2550        queueOrSendMessage(H.CLEAN_UP_CONTEXT, cci);
2551    }
2552
2553    private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {
2554        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
2555
2556        ActivityInfo aInfo = r.activityInfo;
2557        if (r.packageInfo == null) {
2558            r.packageInfo = getPackageInfo(aInfo.applicationInfo,
2559                    Context.CONTEXT_INCLUDE_CODE);
2560        }
2561
2562        ComponentName component = r.intent.getComponent();
2563        if (component == null) {
2564            component = r.intent.resolveActivity(
2565                mInitialApplication.getPackageManager());
2566            r.intent.setComponent(component);
2567        }
2568
2569        if (r.activityInfo.targetActivity != null) {
2570            component = new ComponentName(r.activityInfo.packageName,
2571                    r.activityInfo.targetActivity);
2572        }
2573
2574        Activity activity = null;
2575        try {
2576            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
2577            activity = mInstrumentation.newActivity(
2578                    cl, component.getClassName(), r.intent);
2579            r.intent.setExtrasClassLoader(cl);
2580            if (r.state != null) {
2581                r.state.setClassLoader(cl);
2582            }
2583        } catch (Exception e) {
2584            if (!mInstrumentation.onException(activity, e)) {
2585                throw new RuntimeException(
2586                    "Unable to instantiate activity " + component
2587                    + ": " + e.toString(), e);
2588            }
2589        }
2590
2591        try {
2592            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
2593
2594            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
2595            if (localLOGV) Slog.v(
2596                    TAG, r + ": app=" + app
2597                    + ", appName=" + app.getPackageName()
2598                    + ", pkg=" + r.packageInfo.getPackageName()
2599                    + ", comp=" + r.intent.getComponent().toShortString()
2600                    + ", dir=" + r.packageInfo.getAppDir());
2601
2602            if (activity != null) {
2603                ContextImpl appContext = new ContextImpl();
2604                appContext.init(r.packageInfo, r.token, this);
2605                appContext.setOuterContext(activity);
2606                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
2607                Configuration config = new Configuration(mConfiguration);
2608                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
2609                        + r.activityInfo.name + " with config " + config);
2610                activity.attach(appContext, this, getInstrumentation(), r.token,
2611                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
2612                        r.embeddedID, r.lastNonConfigurationInstances, config);
2613
2614                if (customIntent != null) {
2615                    activity.mIntent = customIntent;
2616                }
2617                r.lastNonConfigurationInstances = null;
2618                activity.mStartedActivity = false;
2619                int theme = r.activityInfo.getThemeResource();
2620                if (theme != 0) {
2621                    activity.setTheme(theme);
2622                }
2623
2624                activity.mCalled = false;
2625                mInstrumentation.callActivityOnCreate(activity, r.state);
2626                if (!activity.mCalled) {
2627                    throw new SuperNotCalledException(
2628                        "Activity " + r.intent.getComponent().toShortString() +
2629                        " did not call through to super.onCreate()");
2630                }
2631                r.activity = activity;
2632                r.stopped = true;
2633                if (!r.activity.mFinished) {
2634                    activity.performStart();
2635                    r.stopped = false;
2636                }
2637                if (!r.activity.mFinished) {
2638                    if (r.state != null) {
2639                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
2640                    }
2641                }
2642                if (!r.activity.mFinished) {
2643                    activity.mCalled = false;
2644                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
2645                    if (!activity.mCalled) {
2646                        throw new SuperNotCalledException(
2647                            "Activity " + r.intent.getComponent().toShortString() +
2648                            " did not call through to super.onPostCreate()");
2649                    }
2650                }
2651            }
2652            r.paused = true;
2653
2654            mActivities.put(r.token, r);
2655
2656        } catch (SuperNotCalledException e) {
2657            throw e;
2658
2659        } catch (Exception e) {
2660            if (!mInstrumentation.onException(activity, e)) {
2661                throw new RuntimeException(
2662                    "Unable to start activity " + component
2663                    + ": " + e.toString(), e);
2664            }
2665        }
2666
2667        return activity;
2668    }
2669
2670    private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {
2671        // If we are getting ready to gc after going to the background, well
2672        // we are back active so skip it.
2673        unscheduleGcIdler();
2674
2675        if (localLOGV) Slog.v(
2676            TAG, "Handling launch of " + r);
2677        Activity a = performLaunchActivity(r, customIntent);
2678
2679        if (a != null) {
2680            r.createdConfig = new Configuration(mConfiguration);
2681            Bundle oldState = r.state;
2682            handleResumeActivity(r.token, false, r.isForward);
2683
2684            if (!r.activity.mFinished && r.startsNotResumed) {
2685                // The activity manager actually wants this one to start out
2686                // paused, because it needs to be visible but isn't in the
2687                // foreground.  We accomplish this by going through the
2688                // normal startup (because activities expect to go through
2689                // onResume() the first time they run, before their window
2690                // is displayed), and then pausing it.  However, in this case
2691                // we do -not- need to do the full pause cycle (of freezing
2692                // and such) because the activity manager assumes it can just
2693                // retain the current state it has.
2694                try {
2695                    r.activity.mCalled = false;
2696                    mInstrumentation.callActivityOnPause(r.activity);
2697                    // We need to keep around the original state, in case
2698                    // we need to be created again.
2699                    r.state = oldState;
2700                    if (!r.activity.mCalled) {
2701                        throw new SuperNotCalledException(
2702                            "Activity " + r.intent.getComponent().toShortString() +
2703                            " did not call through to super.onPause()");
2704                    }
2705
2706                } catch (SuperNotCalledException e) {
2707                    throw e;
2708
2709                } catch (Exception e) {
2710                    if (!mInstrumentation.onException(r.activity, e)) {
2711                        throw new RuntimeException(
2712                                "Unable to pause activity "
2713                                + r.intent.getComponent().toShortString()
2714                                + ": " + e.toString(), e);
2715                    }
2716                }
2717                r.paused = true;
2718            }
2719        } else {
2720            // If there was an error, for any reason, tell the activity
2721            // manager to stop us.
2722            try {
2723                ActivityManagerNative.getDefault()
2724                    .finishActivity(r.token, Activity.RESULT_CANCELED, null);
2725            } catch (RemoteException ex) {
2726            }
2727        }
2728    }
2729
2730    private final void deliverNewIntents(ActivityRecord r,
2731            List<Intent> intents) {
2732        final int N = intents.size();
2733        for (int i=0; i<N; i++) {
2734            Intent intent = intents.get(i);
2735            intent.setExtrasClassLoader(r.activity.getClassLoader());
2736            mInstrumentation.callActivityOnNewIntent(r.activity, intent);
2737        }
2738    }
2739
2740    public final void performNewIntents(IBinder token,
2741            List<Intent> intents) {
2742        ActivityRecord r = mActivities.get(token);
2743        if (r != null) {
2744            final boolean resumed = !r.paused;
2745            if (resumed) {
2746                mInstrumentation.callActivityOnPause(r.activity);
2747            }
2748            deliverNewIntents(r, intents);
2749            if (resumed) {
2750                mInstrumentation.callActivityOnResume(r.activity);
2751            }
2752        }
2753    }
2754
2755    private final void handleNewIntent(NewIntentData data) {
2756        performNewIntents(data.token, data.intents);
2757    }
2758
2759    private final void handleReceiver(ReceiverData data) {
2760        // If we are getting ready to gc after going to the background, well
2761        // we are back active so skip it.
2762        unscheduleGcIdler();
2763
2764        String component = data.intent.getComponent().getClassName();
2765
2766        PackageInfo packageInfo = getPackageInfoNoCheck(
2767                data.info.applicationInfo);
2768
2769        IActivityManager mgr = ActivityManagerNative.getDefault();
2770
2771        BroadcastReceiver receiver = null;
2772        try {
2773            java.lang.ClassLoader cl = packageInfo.getClassLoader();
2774            data.intent.setExtrasClassLoader(cl);
2775            if (data.resultExtras != null) {
2776                data.resultExtras.setClassLoader(cl);
2777            }
2778            receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
2779        } catch (Exception e) {
2780            try {
2781                if (DEBUG_BROADCAST) Slog.i(TAG,
2782                        "Finishing failed broadcast to " + data.intent.getComponent());
2783                mgr.finishReceiver(mAppThread.asBinder(), data.resultCode,
2784                                   data.resultData, data.resultExtras, data.resultAbort);
2785            } catch (RemoteException ex) {
2786            }
2787            throw new RuntimeException(
2788                "Unable to instantiate receiver " + component
2789                + ": " + e.toString(), e);
2790        }
2791
2792        try {
2793            Application app = packageInfo.makeApplication(false, mInstrumentation);
2794
2795            if (localLOGV) Slog.v(
2796                TAG, "Performing receive of " + data.intent
2797                + ": app=" + app
2798                + ", appName=" + app.getPackageName()
2799                + ", pkg=" + packageInfo.getPackageName()
2800                + ", comp=" + data.intent.getComponent().toShortString()
2801                + ", dir=" + packageInfo.getAppDir());
2802
2803            ContextImpl context = (ContextImpl)app.getBaseContext();
2804            receiver.setOrderedHint(true);
2805            receiver.setResult(data.resultCode, data.resultData,
2806                data.resultExtras);
2807            receiver.setOrderedHint(data.sync);
2808            receiver.onReceive(context.getReceiverRestrictedContext(),
2809                    data.intent);
2810        } catch (Exception e) {
2811            try {
2812                if (DEBUG_BROADCAST) Slog.i(TAG,
2813                        "Finishing failed broadcast to " + data.intent.getComponent());
2814                mgr.finishReceiver(mAppThread.asBinder(), data.resultCode,
2815                    data.resultData, data.resultExtras, data.resultAbort);
2816            } catch (RemoteException ex) {
2817            }
2818            if (!mInstrumentation.onException(receiver, e)) {
2819                throw new RuntimeException(
2820                    "Unable to start receiver " + component
2821                    + ": " + e.toString(), e);
2822            }
2823        }
2824
2825        try {
2826            if (data.sync) {
2827                if (DEBUG_BROADCAST) Slog.i(TAG,
2828                        "Finishing ordered broadcast to " + data.intent.getComponent());
2829                mgr.finishReceiver(
2830                    mAppThread.asBinder(), receiver.getResultCode(),
2831                    receiver.getResultData(), receiver.getResultExtras(false),
2832                        receiver.getAbortBroadcast());
2833            } else {
2834                if (DEBUG_BROADCAST) Slog.i(TAG,
2835                        "Finishing broadcast to " + data.intent.getComponent());
2836                mgr.finishReceiver(mAppThread.asBinder(), 0, null, null, false);
2837            }
2838        } catch (RemoteException ex) {
2839        }
2840    }
2841
2842    // Instantiate a BackupAgent and tell it that it's alive
2843    private final void handleCreateBackupAgent(CreateBackupAgentData data) {
2844        if (DEBUG_BACKUP) Slog.v(TAG, "handleCreateBackupAgent: " + data);
2845
2846        // no longer idle; we have backup work to do
2847        unscheduleGcIdler();
2848
2849        // instantiate the BackupAgent class named in the manifest
2850        PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo);
2851        String packageName = packageInfo.mPackageName;
2852        if (mBackupAgents.get(packageName) != null) {
2853            Slog.d(TAG, "BackupAgent " + "  for " + packageName
2854                    + " already exists");
2855            return;
2856        }
2857
2858        BackupAgent agent = null;
2859        String classname = data.appInfo.backupAgentName;
2860        if (classname == null) {
2861            if (data.backupMode == IApplicationThread.BACKUP_MODE_INCREMENTAL) {
2862                Slog.e(TAG, "Attempted incremental backup but no defined agent for "
2863                        + packageName);
2864                return;
2865            }
2866            classname = "android.app.FullBackupAgent";
2867        }
2868        try {
2869            IBinder binder = null;
2870            try {
2871                java.lang.ClassLoader cl = packageInfo.getClassLoader();
2872                agent = (BackupAgent) cl.loadClass(data.appInfo.backupAgentName).newInstance();
2873
2874                // set up the agent's context
2875                if (DEBUG_BACKUP) Slog.v(TAG, "Initializing BackupAgent "
2876                        + data.appInfo.backupAgentName);
2877
2878                ContextImpl context = new ContextImpl();
2879                context.init(packageInfo, null, this);
2880                context.setOuterContext(agent);
2881                agent.attach(context);
2882
2883                agent.onCreate();
2884                binder = agent.onBind();
2885                mBackupAgents.put(packageName, agent);
2886            } catch (Exception e) {
2887                // If this is during restore, fail silently; otherwise go
2888                // ahead and let the user see the crash.
2889                Slog.e(TAG, "Agent threw during creation: " + e);
2890                if (data.backupMode != IApplicationThread.BACKUP_MODE_RESTORE) {
2891                    throw e;
2892                }
2893                // falling through with 'binder' still null
2894            }
2895
2896            // tell the OS that we're live now
2897            try {
2898                ActivityManagerNative.getDefault().backupAgentCreated(packageName, binder);
2899            } catch (RemoteException e) {
2900                // nothing to do.
2901            }
2902        } catch (Exception e) {
2903            throw new RuntimeException("Unable to create BackupAgent "
2904                    + data.appInfo.backupAgentName + ": " + e.toString(), e);
2905        }
2906    }
2907
2908    // Tear down a BackupAgent
2909    private final void handleDestroyBackupAgent(CreateBackupAgentData data) {
2910        if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data);
2911
2912        PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo);
2913        String packageName = packageInfo.mPackageName;
2914        BackupAgent agent = mBackupAgents.get(packageName);
2915        if (agent != null) {
2916            try {
2917                agent.onDestroy();
2918            } catch (Exception e) {
2919                Slog.w(TAG, "Exception thrown in onDestroy by backup agent of " + data.appInfo);
2920                e.printStackTrace();
2921            }
2922            mBackupAgents.remove(packageName);
2923        } else {
2924            Slog.w(TAG, "Attempt to destroy unknown backup agent " + data);
2925        }
2926    }
2927
2928    private final void handleCreateService(CreateServiceData data) {
2929        // If we are getting ready to gc after going to the background, well
2930        // we are back active so skip it.
2931        unscheduleGcIdler();
2932
2933        PackageInfo packageInfo = getPackageInfoNoCheck(
2934                data.info.applicationInfo);
2935        Service service = null;
2936        try {
2937            java.lang.ClassLoader cl = packageInfo.getClassLoader();
2938            service = (Service) cl.loadClass(data.info.name).newInstance();
2939        } catch (Exception e) {
2940            if (!mInstrumentation.onException(service, e)) {
2941                throw new RuntimeException(
2942                    "Unable to instantiate service " + data.info.name
2943                    + ": " + e.toString(), e);
2944            }
2945        }
2946
2947        try {
2948            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
2949
2950            ContextImpl context = new ContextImpl();
2951            context.init(packageInfo, null, this);
2952
2953            Application app = packageInfo.makeApplication(false, mInstrumentation);
2954            context.setOuterContext(service);
2955            service.attach(context, this, data.info.name, data.token, app,
2956                    ActivityManagerNative.getDefault());
2957            service.onCreate();
2958            mServices.put(data.token, service);
2959            try {
2960                ActivityManagerNative.getDefault().serviceDoneExecuting(
2961                        data.token, 0, 0, 0);
2962            } catch (RemoteException e) {
2963                // nothing to do.
2964            }
2965        } catch (Exception e) {
2966            if (!mInstrumentation.onException(service, e)) {
2967                throw new RuntimeException(
2968                    "Unable to create service " + data.info.name
2969                    + ": " + e.toString(), e);
2970            }
2971        }
2972    }
2973
2974    private final void handleBindService(BindServiceData data) {
2975        Service s = mServices.get(data.token);
2976        if (s != null) {
2977            try {
2978                data.intent.setExtrasClassLoader(s.getClassLoader());
2979                try {
2980                    if (!data.rebind) {
2981                        IBinder binder = s.onBind(data.intent);
2982                        ActivityManagerNative.getDefault().publishService(
2983                                data.token, data.intent, binder);
2984                    } else {
2985                        s.onRebind(data.intent);
2986                        ActivityManagerNative.getDefault().serviceDoneExecuting(
2987                                data.token, 0, 0, 0);
2988                    }
2989                    ensureJitEnabled();
2990                } catch (RemoteException ex) {
2991                }
2992            } catch (Exception e) {
2993                if (!mInstrumentation.onException(s, e)) {
2994                    throw new RuntimeException(
2995                            "Unable to bind to service " + s
2996                            + " with " + data.intent + ": " + e.toString(), e);
2997                }
2998            }
2999        }
3000    }
3001
3002    private final void handleUnbindService(BindServiceData data) {
3003        Service s = mServices.get(data.token);
3004        if (s != null) {
3005            try {
3006                data.intent.setExtrasClassLoader(s.getClassLoader());
3007                boolean doRebind = s.onUnbind(data.intent);
3008                try {
3009                    if (doRebind) {
3010                        ActivityManagerNative.getDefault().unbindFinished(
3011                                data.token, data.intent, doRebind);
3012                    } else {
3013                        ActivityManagerNative.getDefault().serviceDoneExecuting(
3014                                data.token, 0, 0, 0);
3015                    }
3016                } catch (RemoteException ex) {
3017                }
3018            } catch (Exception e) {
3019                if (!mInstrumentation.onException(s, e)) {
3020                    throw new RuntimeException(
3021                            "Unable to unbind to service " + s
3022                            + " with " + data.intent + ": " + e.toString(), e);
3023                }
3024            }
3025        }
3026    }
3027
3028    private void handleDumpService(DumpServiceInfo info) {
3029        try {
3030            Service s = mServices.get(info.service);
3031            if (s != null) {
3032                PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd));
3033                s.dump(info.fd, pw, info.args);
3034                pw.close();
3035            }
3036        } finally {
3037            synchronized (info) {
3038                info.dumped = true;
3039                info.notifyAll();
3040            }
3041        }
3042    }
3043
3044    private final void handleServiceArgs(ServiceArgsData data) {
3045        Service s = mServices.get(data.token);
3046        if (s != null) {
3047            try {
3048                if (data.args != null) {
3049                    data.args.setExtrasClassLoader(s.getClassLoader());
3050                }
3051                int res = s.onStartCommand(data.args, data.flags, data.startId);
3052                try {
3053                    ActivityManagerNative.getDefault().serviceDoneExecuting(
3054                            data.token, 1, data.startId, res);
3055                } catch (RemoteException e) {
3056                    // nothing to do.
3057                }
3058                ensureJitEnabled();
3059            } catch (Exception e) {
3060                if (!mInstrumentation.onException(s, e)) {
3061                    throw new RuntimeException(
3062                            "Unable to start service " + s
3063                            + " with " + data.args + ": " + e.toString(), e);
3064                }
3065            }
3066        }
3067    }
3068
3069    private final void handleStopService(IBinder token) {
3070        Service s = mServices.remove(token);
3071        if (s != null) {
3072            try {
3073                if (localLOGV) Slog.v(TAG, "Destroying service " + s);
3074                s.onDestroy();
3075                Context context = s.getBaseContext();
3076                if (context instanceof ContextImpl) {
3077                    final String who = s.getClassName();
3078                    ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
3079                }
3080                try {
3081                    ActivityManagerNative.getDefault().serviceDoneExecuting(
3082                            token, 0, 0, 0);
3083                } catch (RemoteException e) {
3084                    // nothing to do.
3085                }
3086            } catch (Exception e) {
3087                if (!mInstrumentation.onException(s, e)) {
3088                    throw new RuntimeException(
3089                            "Unable to stop service " + s
3090                            + ": " + e.toString(), e);
3091                }
3092            }
3093        }
3094        //Slog.i(TAG, "Running services: " + mServices);
3095    }
3096
3097    public final ActivityRecord performResumeActivity(IBinder token,
3098            boolean clearHide) {
3099        ActivityRecord r = mActivities.get(token);
3100        if (localLOGV) Slog.v(TAG, "Performing resume of " + r
3101                + " finished=" + r.activity.mFinished);
3102        if (r != null && !r.activity.mFinished) {
3103            if (clearHide) {
3104                r.hideForNow = false;
3105                r.activity.mStartedActivity = false;
3106            }
3107            try {
3108                if (r.pendingIntents != null) {
3109                    deliverNewIntents(r, r.pendingIntents);
3110                    r.pendingIntents = null;
3111                }
3112                if (r.pendingResults != null) {
3113                    deliverResults(r, r.pendingResults);
3114                    r.pendingResults = null;
3115                }
3116                r.activity.performResume();
3117
3118                EventLog.writeEvent(LOG_ON_RESUME_CALLED,
3119                        r.activity.getComponentName().getClassName());
3120
3121                r.paused = false;
3122                r.stopped = false;
3123                r.state = null;
3124            } catch (Exception e) {
3125                if (!mInstrumentation.onException(r.activity, e)) {
3126                    throw new RuntimeException(
3127                        "Unable to resume activity "
3128                        + r.intent.getComponent().toShortString()
3129                        + ": " + e.toString(), e);
3130                }
3131            }
3132        }
3133        return r;
3134    }
3135
3136    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
3137        // If we are getting ready to gc after going to the background, well
3138        // we are back active so skip it.
3139        unscheduleGcIdler();
3140
3141        ActivityRecord r = performResumeActivity(token, clearHide);
3142
3143        if (r != null) {
3144            final Activity a = r.activity;
3145
3146            if (localLOGV) Slog.v(
3147                TAG, "Resume " + r + " started activity: " +
3148                a.mStartedActivity + ", hideForNow: " + r.hideForNow
3149                + ", finished: " + a.mFinished);
3150
3151            final int forwardBit = isForward ?
3152                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
3153
3154            // If the window hasn't yet been added to the window manager,
3155            // and this guy didn't finish itself or start another activity,
3156            // then go ahead and add the window.
3157            boolean willBeVisible = !a.mStartedActivity;
3158            if (!willBeVisible) {
3159                try {
3160                    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
3161                            a.getActivityToken());
3162                } catch (RemoteException e) {
3163                }
3164            }
3165            if (r.window == null && !a.mFinished && willBeVisible) {
3166                r.window = r.activity.getWindow();
3167                View decor = r.window.getDecorView();
3168                decor.setVisibility(View.INVISIBLE);
3169                ViewManager wm = a.getWindowManager();
3170                WindowManager.LayoutParams l = r.window.getAttributes();
3171                a.mDecor = decor;
3172                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
3173                l.softInputMode |= forwardBit;
3174                if (a.mVisibleFromClient) {
3175                    a.mWindowAdded = true;
3176                    wm.addView(decor, l);
3177                }
3178
3179            // If the window has already been added, but during resume
3180            // we started another activity, then don't yet make the
3181            // window visible.
3182            } else if (!willBeVisible) {
3183                if (localLOGV) Slog.v(
3184                    TAG, "Launch " + r + " mStartedActivity set");
3185                r.hideForNow = true;
3186            }
3187
3188            // The window is now visible if it has been added, we are not
3189            // simply finishing, and we are not starting another activity.
3190            if (!r.activity.mFinished && willBeVisible
3191                    && r.activity.mDecor != null && !r.hideForNow) {
3192                if (r.newConfig != null) {
3193                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
3194                            + r.activityInfo.name + " with newConfig " + r.newConfig);
3195                    performConfigurationChanged(r.activity, r.newConfig);
3196                    r.newConfig = null;
3197                }
3198                if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
3199                        + isForward);
3200                WindowManager.LayoutParams l = r.window.getAttributes();
3201                if ((l.softInputMode
3202                        & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
3203                        != forwardBit) {
3204                    l.softInputMode = (l.softInputMode
3205                            & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
3206                            | forwardBit;
3207                    if (r.activity.mVisibleFromClient) {
3208                        ViewManager wm = a.getWindowManager();
3209                        View decor = r.window.getDecorView();
3210                        wm.updateViewLayout(decor, l);
3211                    }
3212                }
3213                r.activity.mVisibleFromServer = true;
3214                mNumVisibleActivities++;
3215                if (r.activity.mVisibleFromClient) {
3216                    r.activity.makeVisible();
3217                }
3218            }
3219
3220            r.nextIdle = mNewActivities;
3221            mNewActivities = r;
3222            if (localLOGV) Slog.v(
3223                TAG, "Scheduling idle handler for " + r);
3224            Looper.myQueue().addIdleHandler(new Idler());
3225
3226        } else {
3227            // If an exception was thrown when trying to resume, then
3228            // just end this activity.
3229            try {
3230                ActivityManagerNative.getDefault()
3231                    .finishActivity(token, Activity.RESULT_CANCELED, null);
3232            } catch (RemoteException ex) {
3233            }
3234        }
3235    }
3236
3237    private int mThumbnailWidth = -1;
3238    private int mThumbnailHeight = -1;
3239
3240    private final Bitmap createThumbnailBitmap(ActivityRecord r) {
3241        Bitmap thumbnail = null;
3242        try {
3243            int w = mThumbnailWidth;
3244            int h;
3245            if (w < 0) {
3246                Resources res = r.activity.getResources();
3247                mThumbnailHeight = h =
3248                    res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
3249
3250                mThumbnailWidth = w =
3251                    res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
3252            } else {
3253                h = mThumbnailHeight;
3254            }
3255
3256            // XXX Only set hasAlpha if needed?
3257            thumbnail = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
3258            thumbnail.eraseColor(0);
3259            Canvas cv = new Canvas(thumbnail);
3260            if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
3261                thumbnail = null;
3262            }
3263        } catch (Exception e) {
3264            if (!mInstrumentation.onException(r.activity, e)) {
3265                throw new RuntimeException(
3266                        "Unable to create thumbnail of "
3267                        + r.intent.getComponent().toShortString()
3268                        + ": " + e.toString(), e);
3269            }
3270            thumbnail = null;
3271        }
3272
3273        return thumbnail;
3274    }
3275
3276    private final void handlePauseActivity(IBinder token, boolean finished,
3277            boolean userLeaving, int configChanges) {
3278        ActivityRecord r = mActivities.get(token);
3279        if (r != null) {
3280            //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
3281            if (userLeaving) {
3282                performUserLeavingActivity(r);
3283            }
3284
3285            r.activity.mConfigChangeFlags |= configChanges;
3286            Bundle state = performPauseActivity(token, finished, true);
3287
3288            // Tell the activity manager we have paused.
3289            try {
3290                ActivityManagerNative.getDefault().activityPaused(token, state);
3291            } catch (RemoteException ex) {
3292            }
3293        }
3294    }
3295
3296    final void performUserLeavingActivity(ActivityRecord r) {
3297        mInstrumentation.callActivityOnUserLeaving(r.activity);
3298    }
3299
3300    final Bundle performPauseActivity(IBinder token, boolean finished,
3301            boolean saveState) {
3302        ActivityRecord r = mActivities.get(token);
3303        return r != null ? performPauseActivity(r, finished, saveState) : null;
3304    }
3305
3306    final Bundle performPauseActivity(ActivityRecord r, boolean finished,
3307            boolean saveState) {
3308        if (r.paused) {
3309            if (r.activity.mFinished) {
3310                // If we are finishing, we won't call onResume() in certain cases.
3311                // So here we likewise don't want to call onPause() if the activity
3312                // isn't resumed.
3313                return null;
3314            }
3315            RuntimeException e = new RuntimeException(
3316                    "Performing pause of activity that is not resumed: "
3317                    + r.intent.getComponent().toShortString());
3318            Slog.e(TAG, e.getMessage(), e);
3319        }
3320        Bundle state = null;
3321        if (finished) {
3322            r.activity.mFinished = true;
3323        }
3324        try {
3325            // Next have the activity save its current state and managed dialogs...
3326            if (!r.activity.mFinished && saveState) {
3327                state = new Bundle();
3328                mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
3329                r.state = state;
3330            }
3331            // Now we are idle.
3332            r.activity.mCalled = false;
3333            mInstrumentation.callActivityOnPause(r.activity);
3334            EventLog.writeEvent(LOG_ON_PAUSE_CALLED, r.activity.getComponentName().getClassName());
3335            if (!r.activity.mCalled) {
3336                throw new SuperNotCalledException(
3337                    "Activity " + r.intent.getComponent().toShortString() +
3338                    " did not call through to super.onPause()");
3339            }
3340
3341        } catch (SuperNotCalledException e) {
3342            throw e;
3343
3344        } catch (Exception e) {
3345            if (!mInstrumentation.onException(r.activity, e)) {
3346                throw new RuntimeException(
3347                        "Unable to pause activity "
3348                        + r.intent.getComponent().toShortString()
3349                        + ": " + e.toString(), e);
3350            }
3351        }
3352        r.paused = true;
3353        return state;
3354    }
3355
3356    final void performStopActivity(IBinder token) {
3357        ActivityRecord r = mActivities.get(token);
3358        performStopActivityInner(r, null, false);
3359    }
3360
3361    private static class StopInfo {
3362        Bitmap thumbnail;
3363        CharSequence description;
3364    }
3365
3366    private final class ProviderRefCount {
3367        public int count;
3368        ProviderRefCount(int pCount) {
3369            count = pCount;
3370        }
3371    }
3372
3373    private final void performStopActivityInner(ActivityRecord r,
3374            StopInfo info, boolean keepShown) {
3375        if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
3376        if (r != null) {
3377            if (!keepShown && r.stopped) {
3378                if (r.activity.mFinished) {
3379                    // If we are finishing, we won't call onResume() in certain
3380                    // cases.  So here we likewise don't want to call onStop()
3381                    // if the activity isn't resumed.
3382                    return;
3383                }
3384                RuntimeException e = new RuntimeException(
3385                        "Performing stop of activity that is not resumed: "
3386                        + r.intent.getComponent().toShortString());
3387                Slog.e(TAG, e.getMessage(), e);
3388            }
3389
3390            if (info != null) {
3391                try {
3392                    // First create a thumbnail for the activity...
3393                    //info.thumbnail = createThumbnailBitmap(r);
3394                    info.description = r.activity.onCreateDescription();
3395                } catch (Exception e) {
3396                    if (!mInstrumentation.onException(r.activity, e)) {
3397                        throw new RuntimeException(
3398                                "Unable to save state of activity "
3399                                + r.intent.getComponent().toShortString()
3400                                + ": " + e.toString(), e);
3401                    }
3402                }
3403            }
3404
3405            if (!keepShown) {
3406                try {
3407                    // Now we are idle.
3408                    r.activity.performStop();
3409                } catch (Exception e) {
3410                    if (!mInstrumentation.onException(r.activity, e)) {
3411                        throw new RuntimeException(
3412                                "Unable to stop activity "
3413                                + r.intent.getComponent().toShortString()
3414                                + ": " + e.toString(), e);
3415                    }
3416                }
3417                r.stopped = true;
3418            }
3419
3420            r.paused = true;
3421        }
3422    }
3423
3424    private final void updateVisibility(ActivityRecord r, boolean show) {
3425        View v = r.activity.mDecor;
3426        if (v != null) {
3427            if (show) {
3428                if (!r.activity.mVisibleFromServer) {
3429                    r.activity.mVisibleFromServer = true;
3430                    mNumVisibleActivities++;
3431                    if (r.activity.mVisibleFromClient) {
3432                        r.activity.makeVisible();
3433                    }
3434                }
3435                if (r.newConfig != null) {
3436                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Updating activity vis "
3437                            + r.activityInfo.name + " with new config " + r.newConfig);
3438                    performConfigurationChanged(r.activity, r.newConfig);
3439                    r.newConfig = null;
3440                }
3441            } else {
3442                if (r.activity.mVisibleFromServer) {
3443                    r.activity.mVisibleFromServer = false;
3444                    mNumVisibleActivities--;
3445                    v.setVisibility(View.INVISIBLE);
3446                }
3447            }
3448        }
3449    }
3450
3451    private final void handleStopActivity(IBinder token, boolean show, int configChanges) {
3452        ActivityRecord r = mActivities.get(token);
3453        r.activity.mConfigChangeFlags |= configChanges;
3454
3455        StopInfo info = new StopInfo();
3456        performStopActivityInner(r, info, show);
3457
3458        if (localLOGV) Slog.v(
3459            TAG, "Finishing stop of " + r + ": show=" + show
3460            + " win=" + r.window);
3461
3462        updateVisibility(r, show);
3463
3464        // Tell activity manager we have been stopped.
3465        try {
3466            ActivityManagerNative.getDefault().activityStopped(
3467                r.token, info.thumbnail, info.description);
3468        } catch (RemoteException ex) {
3469        }
3470    }
3471
3472    final void performRestartActivity(IBinder token) {
3473        ActivityRecord r = mActivities.get(token);
3474        if (r.stopped) {
3475            r.activity.performRestart();
3476            r.stopped = false;
3477        }
3478    }
3479
3480    private final void handleWindowVisibility(IBinder token, boolean show) {
3481        ActivityRecord r = mActivities.get(token);
3482        if (!show && !r.stopped) {
3483            performStopActivityInner(r, null, show);
3484        } else if (show && r.stopped) {
3485            // If we are getting ready to gc after going to the background, well
3486            // we are back active so skip it.
3487            unscheduleGcIdler();
3488
3489            r.activity.performRestart();
3490            r.stopped = false;
3491        }
3492        if (r.activity.mDecor != null) {
3493            if (Config.LOGV) Slog.v(
3494                TAG, "Handle window " + r + " visibility: " + show);
3495            updateVisibility(r, show);
3496        }
3497    }
3498
3499    private final void deliverResults(ActivityRecord r, List<ResultInfo> results) {
3500        final int N = results.size();
3501        for (int i=0; i<N; i++) {
3502            ResultInfo ri = results.get(i);
3503            try {
3504                if (ri.mData != null) {
3505                    ri.mData.setExtrasClassLoader(r.activity.getClassLoader());
3506                }
3507                if (DEBUG_RESULTS) Slog.v(TAG,
3508                        "Delivering result to activity " + r + " : " + ri);
3509                r.activity.dispatchActivityResult(ri.mResultWho,
3510                        ri.mRequestCode, ri.mResultCode, ri.mData);
3511            } catch (Exception e) {
3512                if (!mInstrumentation.onException(r.activity, e)) {
3513                    throw new RuntimeException(
3514                            "Failure delivering result " + ri + " to activity "
3515                            + r.intent.getComponent().toShortString()
3516                            + ": " + e.toString(), e);
3517                }
3518            }
3519        }
3520    }
3521
3522    private final void handleSendResult(ResultData res) {
3523        ActivityRecord r = mActivities.get(res.token);
3524        if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r);
3525        if (r != null) {
3526            final boolean resumed = !r.paused;
3527            if (!r.activity.mFinished && r.activity.mDecor != null
3528                    && r.hideForNow && resumed) {
3529                // We had hidden the activity because it started another
3530                // one...  we have gotten a result back and we are not
3531                // paused, so make sure our window is visible.
3532                updateVisibility(r, true);
3533            }
3534            if (resumed) {
3535                try {
3536                    // Now we are idle.
3537                    r.activity.mCalled = false;
3538                    mInstrumentation.callActivityOnPause(r.activity);
3539                    if (!r.activity.mCalled) {
3540                        throw new SuperNotCalledException(
3541                            "Activity " + r.intent.getComponent().toShortString()
3542                            + " did not call through to super.onPause()");
3543                    }
3544                } catch (SuperNotCalledException e) {
3545                    throw e;
3546                } catch (Exception e) {
3547                    if (!mInstrumentation.onException(r.activity, e)) {
3548                        throw new RuntimeException(
3549                                "Unable to pause activity "
3550                                + r.intent.getComponent().toShortString()
3551                                + ": " + e.toString(), e);
3552                    }
3553                }
3554            }
3555            deliverResults(r, res.results);
3556            if (resumed) {
3557                mInstrumentation.callActivityOnResume(r.activity);
3558            }
3559        }
3560    }
3561
3562    public final ActivityRecord performDestroyActivity(IBinder token, boolean finishing) {
3563        return performDestroyActivity(token, finishing, 0, false);
3564    }
3565
3566    private final ActivityRecord performDestroyActivity(IBinder token, boolean finishing,
3567            int configChanges, boolean getNonConfigInstance) {
3568        ActivityRecord r = mActivities.get(token);
3569        if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
3570        if (r != null) {
3571            r.activity.mConfigChangeFlags |= configChanges;
3572            if (finishing) {
3573                r.activity.mFinished = true;
3574            }
3575            if (getNonConfigInstance) {
3576                r.activity.mChangingConfigurations = true;
3577            }
3578            if (!r.paused) {
3579                try {
3580                    r.activity.mCalled = false;
3581                    mInstrumentation.callActivityOnPause(r.activity);
3582                    EventLog.writeEvent(LOG_ON_PAUSE_CALLED,
3583                            r.activity.getComponentName().getClassName());
3584                    if (!r.activity.mCalled) {
3585                        throw new SuperNotCalledException(
3586                            "Activity " + safeToComponentShortString(r.intent)
3587                            + " did not call through to super.onPause()");
3588                    }
3589                } catch (SuperNotCalledException e) {
3590                    throw e;
3591                } catch (Exception e) {
3592                    if (!mInstrumentation.onException(r.activity, e)) {
3593                        throw new RuntimeException(
3594                                "Unable to pause activity "
3595                                + safeToComponentShortString(r.intent)
3596                                + ": " + e.toString(), e);
3597                    }
3598                }
3599                r.paused = true;
3600            }
3601            if (!r.stopped) {
3602                try {
3603                    r.activity.performStop();
3604                } catch (SuperNotCalledException e) {
3605                    throw e;
3606                } catch (Exception e) {
3607                    if (!mInstrumentation.onException(r.activity, e)) {
3608                        throw new RuntimeException(
3609                                "Unable to stop activity "
3610                                + safeToComponentShortString(r.intent)
3611                                + ": " + e.toString(), e);
3612                    }
3613                }
3614                r.stopped = true;
3615            }
3616            if (getNonConfigInstance) {
3617                try {
3618                    r.lastNonConfigurationInstances
3619                            = r.activity.retainNonConfigurationInstances();
3620                } catch (Exception e) {
3621                    if (!mInstrumentation.onException(r.activity, e)) {
3622                        throw new RuntimeException(
3623                                "Unable to retain activity "
3624                                + r.intent.getComponent().toShortString()
3625                                + ": " + e.toString(), e);
3626                    }
3627                }
3628            }
3629            try {
3630                r.activity.mCalled = false;
3631                mInstrumentation.callActivityOnDestroy(r.activity);
3632                if (!r.activity.mCalled) {
3633                    throw new SuperNotCalledException(
3634                        "Activity " + safeToComponentShortString(r.intent) +
3635                        " did not call through to super.onDestroy()");
3636                }
3637                if (r.window != null) {
3638                    r.window.closeAllPanels();
3639                }
3640            } catch (SuperNotCalledException e) {
3641                throw e;
3642            } catch (Exception e) {
3643                if (!mInstrumentation.onException(r.activity, e)) {
3644                    throw new RuntimeException(
3645                            "Unable to destroy activity " + safeToComponentShortString(r.intent)
3646                            + ": " + e.toString(), e);
3647                }
3648            }
3649        }
3650        mActivities.remove(token);
3651
3652        return r;
3653    }
3654
3655    private static String safeToComponentShortString(Intent intent) {
3656        ComponentName component = intent.getComponent();
3657        return component == null ? "[Unknown]" : component.toShortString();
3658    }
3659
3660    private final void handleDestroyActivity(IBinder token, boolean finishing,
3661            int configChanges, boolean getNonConfigInstance) {
3662        ActivityRecord r = performDestroyActivity(token, finishing,
3663                configChanges, getNonConfigInstance);
3664        if (r != null) {
3665            WindowManager wm = r.activity.getWindowManager();
3666            View v = r.activity.mDecor;
3667            if (v != null) {
3668                if (r.activity.mVisibleFromServer) {
3669                    mNumVisibleActivities--;
3670                }
3671                IBinder wtoken = v.getWindowToken();
3672                if (r.activity.mWindowAdded) {
3673                    wm.removeViewImmediate(v);
3674                }
3675                if (wtoken != null) {
3676                    WindowManagerImpl.getDefault().closeAll(wtoken,
3677                            r.activity.getClass().getName(), "Activity");
3678                }
3679                r.activity.mDecor = null;
3680            }
3681            WindowManagerImpl.getDefault().closeAll(token,
3682                    r.activity.getClass().getName(), "Activity");
3683
3684            // Mocked out contexts won't be participating in the normal
3685            // process lifecycle, but if we're running with a proper
3686            // ApplicationContext we need to have it tear down things
3687            // cleanly.
3688            Context c = r.activity.getBaseContext();
3689            if (c instanceof ContextImpl) {
3690                ((ContextImpl) c).scheduleFinalCleanup(
3691                        r.activity.getClass().getName(), "Activity");
3692            }
3693        }
3694        if (finishing) {
3695            try {
3696                ActivityManagerNative.getDefault().activityDestroyed(token);
3697            } catch (RemoteException ex) {
3698                // If the system process has died, it's game over for everyone.
3699            }
3700        }
3701    }
3702
3703    private final void handleRelaunchActivity(ActivityRecord tmp, int configChanges) {
3704        // If we are getting ready to gc after going to the background, well
3705        // we are back active so skip it.
3706        unscheduleGcIdler();
3707
3708        Configuration changedConfig = null;
3709
3710        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
3711                + tmp.token + " with configChanges=0x"
3712                + Integer.toHexString(configChanges));
3713
3714        // First: make sure we have the most recent configuration and most
3715        // recent version of the activity, or skip it if some previous call
3716        // had taken a more recent version.
3717        synchronized (mPackages) {
3718            int N = mRelaunchingActivities.size();
3719            IBinder token = tmp.token;
3720            tmp = null;
3721            for (int i=0; i<N; i++) {
3722                ActivityRecord r = mRelaunchingActivities.get(i);
3723                if (r.token == token) {
3724                    tmp = r;
3725                    mRelaunchingActivities.remove(i);
3726                    i--;
3727                    N--;
3728                }
3729            }
3730
3731            if (tmp == null) {
3732                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Abort, activity not relaunching!");
3733                return;
3734            }
3735
3736            if (mPendingConfiguration != null) {
3737                changedConfig = mPendingConfiguration;
3738                mPendingConfiguration = null;
3739            }
3740        }
3741
3742        if (tmp.createdConfig != null) {
3743            // If the activity manager is passing us its current config,
3744            // assume that is really what we want regardless of what we
3745            // may have pending.
3746            if (mConfiguration == null
3747                    || (tmp.createdConfig.isOtherSeqNewer(mConfiguration)
3748                            && mConfiguration.diff(tmp.createdConfig) != 0)) {
3749                if (changedConfig == null
3750                        || tmp.createdConfig.isOtherSeqNewer(changedConfig)) {
3751                    changedConfig = tmp.createdConfig;
3752                }
3753            }
3754        }
3755
3756        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
3757                + tmp.token + ": changedConfig=" + changedConfig);
3758
3759        // If there was a pending configuration change, execute it first.
3760        if (changedConfig != null) {
3761            handleConfigurationChanged(changedConfig);
3762        }
3763
3764        ActivityRecord r = mActivities.get(tmp.token);
3765        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
3766        if (r == null) {
3767            return;
3768        }
3769
3770        r.activity.mConfigChangeFlags |= configChanges;
3771        Intent currentIntent = r.activity.mIntent;
3772
3773        Bundle savedState = null;
3774        if (!r.paused) {
3775            savedState = performPauseActivity(r.token, false, true);
3776        }
3777
3778        handleDestroyActivity(r.token, false, configChanges, true);
3779
3780        r.activity = null;
3781        r.window = null;
3782        r.hideForNow = false;
3783        r.nextIdle = null;
3784        // Merge any pending results and pending intents; don't just replace them
3785        if (tmp.pendingResults != null) {
3786            if (r.pendingResults == null) {
3787                r.pendingResults = tmp.pendingResults;
3788            } else {
3789                r.pendingResults.addAll(tmp.pendingResults);
3790            }
3791        }
3792        if (tmp.pendingIntents != null) {
3793            if (r.pendingIntents == null) {
3794                r.pendingIntents = tmp.pendingIntents;
3795            } else {
3796                r.pendingIntents.addAll(tmp.pendingIntents);
3797            }
3798        }
3799        r.startsNotResumed = tmp.startsNotResumed;
3800        if (savedState != null) {
3801            r.state = savedState;
3802        }
3803
3804        handleLaunchActivity(r, currentIntent);
3805    }
3806
3807    private final void handleRequestThumbnail(IBinder token) {
3808        ActivityRecord r = mActivities.get(token);
3809        Bitmap thumbnail = createThumbnailBitmap(r);
3810        CharSequence description = null;
3811        try {
3812            description = r.activity.onCreateDescription();
3813        } catch (Exception e) {
3814            if (!mInstrumentation.onException(r.activity, e)) {
3815                throw new RuntimeException(
3816                        "Unable to create description of activity "
3817                        + r.intent.getComponent().toShortString()
3818                        + ": " + e.toString(), e);
3819            }
3820        }
3821        //System.out.println("Reporting top thumbnail " + thumbnail);
3822        try {
3823            ActivityManagerNative.getDefault().reportThumbnail(
3824                token, thumbnail, description);
3825        } catch (RemoteException ex) {
3826        }
3827    }
3828
3829    ArrayList<ComponentCallbacks> collectComponentCallbacksLocked(
3830            boolean allActivities, Configuration newConfig) {
3831        ArrayList<ComponentCallbacks> callbacks
3832                = new ArrayList<ComponentCallbacks>();
3833
3834        if (mActivities.size() > 0) {
3835            Iterator<ActivityRecord> it = mActivities.values().iterator();
3836            while (it.hasNext()) {
3837                ActivityRecord ar = it.next();
3838                Activity a = ar.activity;
3839                if (a != null) {
3840                    if (!ar.activity.mFinished && (allActivities ||
3841                            (a != null && !ar.paused))) {
3842                        // If the activity is currently resumed, its configuration
3843                        // needs to change right now.
3844                        callbacks.add(a);
3845                    } else if (newConfig != null) {
3846                        // Otherwise, we will tell it about the change
3847                        // the next time it is resumed or shown.  Note that
3848                        // the activity manager may, before then, decide the
3849                        // activity needs to be destroyed to handle its new
3850                        // configuration.
3851                        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Setting activity "
3852                                + ar.activityInfo.name + " newConfig=" + newConfig);
3853                        ar.newConfig = newConfig;
3854                    }
3855                }
3856            }
3857        }
3858        if (mServices.size() > 0) {
3859            Iterator<Service> it = mServices.values().iterator();
3860            while (it.hasNext()) {
3861                callbacks.add(it.next());
3862            }
3863        }
3864        synchronized (mProviderMap) {
3865            if (mLocalProviders.size() > 0) {
3866                Iterator<ProviderRecord> it = mLocalProviders.values().iterator();
3867                while (it.hasNext()) {
3868                    callbacks.add(it.next().mLocalProvider);
3869                }
3870            }
3871        }
3872        final int N = mAllApplications.size();
3873        for (int i=0; i<N; i++) {
3874            callbacks.add(mAllApplications.get(i));
3875        }
3876
3877        return callbacks;
3878    }
3879
3880    private final void performConfigurationChanged(
3881            ComponentCallbacks cb, Configuration config) {
3882        // Only for Activity objects, check that they actually call up to their
3883        // superclass implementation.  ComponentCallbacks is an interface, so
3884        // we check the runtime type and act accordingly.
3885        Activity activity = (cb instanceof Activity) ? (Activity) cb : null;
3886        if (activity != null) {
3887            activity.mCalled = false;
3888        }
3889
3890        boolean shouldChangeConfig = false;
3891        if ((activity == null) || (activity.mCurrentConfig == null)) {
3892            shouldChangeConfig = true;
3893        } else {
3894
3895            // If the new config is the same as the config this Activity
3896            // is already running with then don't bother calling
3897            // onConfigurationChanged
3898            int diff = activity.mCurrentConfig.diff(config);
3899            if (diff != 0) {
3900
3901                // If this activity doesn't handle any of the config changes
3902                // then don't bother calling onConfigurationChanged as we're
3903                // going to destroy it.
3904                if ((~activity.mActivityInfo.configChanges & diff) == 0) {
3905                    shouldChangeConfig = true;
3906                }
3907            }
3908        }
3909
3910        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Config callback " + cb
3911                + ": shouldChangeConfig=" + shouldChangeConfig);
3912        if (shouldChangeConfig) {
3913            cb.onConfigurationChanged(config);
3914
3915            if (activity != null) {
3916                if (!activity.mCalled) {
3917                    throw new SuperNotCalledException(
3918                            "Activity " + activity.getLocalClassName() +
3919                        " did not call through to super.onConfigurationChanged()");
3920                }
3921                activity.mConfigChangeFlags = 0;
3922                activity.mCurrentConfig = new Configuration(config);
3923            }
3924        }
3925    }
3926
3927    final boolean applyConfigurationToResourcesLocked(Configuration config) {
3928        if (mResConfiguration == null) {
3929            mResConfiguration = new Configuration();
3930        }
3931        if (!mResConfiguration.isOtherSeqNewer(config)) {
3932            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
3933                    + mResConfiguration.seq + ", newSeq=" + config.seq);
3934            return false;
3935        }
3936        int changes = mResConfiguration.updateFrom(config);
3937        DisplayMetrics dm = getDisplayMetricsLocked(true);
3938
3939        // set it for java, this also affects newly created Resources
3940        if (config.locale != null) {
3941            Locale.setDefault(config.locale);
3942        }
3943
3944        Resources.updateSystemConfiguration(config, dm);
3945
3946        ContextImpl.ApplicationPackageManager.configurationChanged();
3947        //Slog.i(TAG, "Configuration changed in " + currentPackageName());
3948
3949        Iterator<WeakReference<Resources>> it =
3950            mActiveResources.values().iterator();
3951        //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
3952        //    mActiveResources.entrySet().iterator();
3953        while (it.hasNext()) {
3954            WeakReference<Resources> v = it.next();
3955            Resources r = v.get();
3956            if (r != null) {
3957                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
3958                        + r + " config to: " + config);
3959                r.updateConfiguration(config, dm);
3960                //Slog.i(TAG, "Updated app resources " + v.getKey()
3961                //        + " " + r + ": " + r.getConfiguration());
3962            } else {
3963                //Slog.i(TAG, "Removing old resources " + v.getKey());
3964                it.remove();
3965            }
3966        }
3967
3968        return changes != 0;
3969    }
3970
3971    final void handleConfigurationChanged(Configuration config) {
3972
3973        ArrayList<ComponentCallbacks> callbacks = null;
3974
3975        synchronized (mPackages) {
3976            if (mPendingConfiguration != null) {
3977                if (!mPendingConfiguration.isOtherSeqNewer(config)) {
3978                    config = mPendingConfiguration;
3979                }
3980                mPendingConfiguration = null;
3981            }
3982
3983            if (config == null) {
3984                return;
3985            }
3986
3987            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
3988                    + config);
3989
3990            applyConfigurationToResourcesLocked(config);
3991
3992            if (mConfiguration == null) {
3993                mConfiguration = new Configuration();
3994            }
3995            if (!mConfiguration.isOtherSeqNewer(config)) {
3996                return;
3997            }
3998            mConfiguration.updateFrom(config);
3999
4000            callbacks = collectComponentCallbacksLocked(false, config);
4001        }
4002
4003        if (callbacks != null) {
4004            final int N = callbacks.size();
4005            for (int i=0; i<N; i++) {
4006                performConfigurationChanged(callbacks.get(i), config);
4007            }
4008        }
4009    }
4010
4011    final void handleActivityConfigurationChanged(IBinder token) {
4012        ActivityRecord r = mActivities.get(token);
4013        if (r == null || r.activity == null) {
4014            return;
4015        }
4016
4017        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
4018                + r.activityInfo.name);
4019
4020        performConfigurationChanged(r.activity, mConfiguration);
4021    }
4022
4023    final void handleProfilerControl(boolean start, ProfilerControlData pcd) {
4024        if (start) {
4025            try {
4026                Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(),
4027                        8 * 1024 * 1024, 0);
4028            } catch (RuntimeException e) {
4029                Slog.w(TAG, "Profiling failed on path " + pcd.path
4030                        + " -- can the process access this path?");
4031            } finally {
4032                try {
4033                    pcd.fd.close();
4034                } catch (IOException e) {
4035                    Slog.w(TAG, "Failure closing profile fd", e);
4036                }
4037            }
4038        } else {
4039            Debug.stopMethodTracing();
4040        }
4041    }
4042
4043    final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
4044        boolean hasPkgInfo = false;
4045        if (packages != null) {
4046            for (int i=packages.length-1; i>=0; i--) {
4047                //Slog.i(TAG, "Cleaning old package: " + packages[i]);
4048                if (!hasPkgInfo) {
4049                    WeakReference<PackageInfo> ref;
4050                    ref = mPackages.get(packages[i]);
4051                    if (ref != null && ref.get() != null) {
4052                        hasPkgInfo = true;
4053                    } else {
4054                        ref = mResourcePackages.get(packages[i]);
4055                        if (ref != null && ref.get() != null) {
4056                            hasPkgInfo = true;
4057                        }
4058                    }
4059                }
4060                mPackages.remove(packages[i]);
4061                mResourcePackages.remove(packages[i]);
4062            }
4063        }
4064        ContextImpl.ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
4065                hasPkgInfo);
4066    }
4067
4068    final void handleLowMemory() {
4069        ArrayList<ComponentCallbacks> callbacks
4070                = new ArrayList<ComponentCallbacks>();
4071
4072        synchronized (mPackages) {
4073            callbacks = collectComponentCallbacksLocked(true, null);
4074        }
4075
4076        final int N = callbacks.size();
4077        for (int i=0; i<N; i++) {
4078            callbacks.get(i).onLowMemory();
4079        }
4080
4081        // Ask SQLite to free up as much memory as it can, mostly from its page caches.
4082        if (Process.myUid() != Process.SYSTEM_UID) {
4083            int sqliteReleased = SQLiteDatabase.releaseMemory();
4084            EventLog.writeEvent(SQLITE_MEM_RELEASED_EVENT_LOG_TAG, sqliteReleased);
4085        }
4086
4087        // Ask graphics to free up as much as possible (font/image caches)
4088        Canvas.freeCaches();
4089
4090        BinderInternal.forceGc("mem");
4091    }
4092
4093    private final void handleBindApplication(AppBindData data) {
4094        mBoundApplication = data;
4095        mConfiguration = new Configuration(data.config);
4096
4097        // send up app name; do this *before* waiting for debugger
4098        Process.setArgV0(data.processName);
4099        android.ddm.DdmHandleAppName.setAppName(data.processName);
4100
4101        /*
4102         * Before spawning a new process, reset the time zone to be the system time zone.
4103         * This needs to be done because the system time zone could have changed after the
4104         * the spawning of this process. Without doing this this process would have the incorrect
4105         * system time zone.
4106         */
4107        TimeZone.setDefault(null);
4108
4109        /*
4110         * Initialize the default locale in this process for the reasons we set the time zone.
4111         */
4112        Locale.setDefault(data.config.locale);
4113
4114        /*
4115         * Update the system configuration since its preloaded and might not
4116         * reflect configuration changes. The configuration object passed
4117         * in AppBindData can be safely assumed to be up to date
4118         */
4119        Resources.getSystem().updateConfiguration(mConfiguration, null);
4120
4121        data.info = getPackageInfoNoCheck(data.appInfo);
4122
4123        /**
4124         * Switch this process to density compatibility mode if needed.
4125         */
4126        if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
4127                == 0) {
4128            Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
4129        }
4130
4131        if (data.debugMode != IApplicationThread.DEBUG_OFF) {
4132            // XXX should have option to change the port.
4133            Debug.changeDebugPort(8100);
4134            if (data.debugMode == IApplicationThread.DEBUG_WAIT) {
4135                Slog.w(TAG, "Application " + data.info.getPackageName()
4136                      + " is waiting for the debugger on port 8100...");
4137
4138                IActivityManager mgr = ActivityManagerNative.getDefault();
4139                try {
4140                    mgr.showWaitingForDebugger(mAppThread, true);
4141                } catch (RemoteException ex) {
4142                }
4143
4144                Debug.waitForDebugger();
4145
4146                try {
4147                    mgr.showWaitingForDebugger(mAppThread, false);
4148                } catch (RemoteException ex) {
4149                }
4150
4151            } else {
4152                Slog.w(TAG, "Application " + data.info.getPackageName()
4153                      + " can be debugged on port 8100...");
4154            }
4155        }
4156
4157        if (data.instrumentationName != null) {
4158            ContextImpl appContext = new ContextImpl();
4159            appContext.init(data.info, null, this);
4160            InstrumentationInfo ii = null;
4161            try {
4162                ii = appContext.getPackageManager().
4163                    getInstrumentationInfo(data.instrumentationName, 0);
4164            } catch (PackageManager.NameNotFoundException e) {
4165            }
4166            if (ii == null) {
4167                throw new RuntimeException(
4168                    "Unable to find instrumentation info for: "
4169                    + data.instrumentationName);
4170            }
4171
4172            mInstrumentationAppDir = ii.sourceDir;
4173            mInstrumentationAppPackage = ii.packageName;
4174            mInstrumentedAppDir = data.info.getAppDir();
4175
4176            ApplicationInfo instrApp = new ApplicationInfo();
4177            instrApp.packageName = ii.packageName;
4178            instrApp.sourceDir = ii.sourceDir;
4179            instrApp.publicSourceDir = ii.publicSourceDir;
4180            instrApp.dataDir = ii.dataDir;
4181            PackageInfo pi = getPackageInfo(instrApp,
4182                    appContext.getClassLoader(), false, true);
4183            ContextImpl instrContext = new ContextImpl();
4184            instrContext.init(pi, null, this);
4185
4186            try {
4187                java.lang.ClassLoader cl = instrContext.getClassLoader();
4188                mInstrumentation = (Instrumentation)
4189                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
4190            } catch (Exception e) {
4191                throw new RuntimeException(
4192                    "Unable to instantiate instrumentation "
4193                    + data.instrumentationName + ": " + e.toString(), e);
4194            }
4195
4196            mInstrumentation.init(this, instrContext, appContext,
4197                    new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher);
4198
4199            if (data.profileFile != null && !ii.handleProfiling) {
4200                data.handlingProfiling = true;
4201                File file = new File(data.profileFile);
4202                file.getParentFile().mkdirs();
4203                Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
4204            }
4205
4206            try {
4207                mInstrumentation.onCreate(data.instrumentationArgs);
4208            }
4209            catch (Exception e) {
4210                throw new RuntimeException(
4211                    "Exception thrown in onCreate() of "
4212                    + data.instrumentationName + ": " + e.toString(), e);
4213            }
4214
4215        } else {
4216            mInstrumentation = new Instrumentation();
4217        }
4218
4219        // If the app is being launched for full backup or restore, bring it up in
4220        // a restricted environment with the base application class.
4221        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
4222        mInitialApplication = app;
4223
4224        List<ProviderInfo> providers = data.providers;
4225        if (providers != null) {
4226            installContentProviders(app, providers);
4227            // For process that contain content providers, we want to
4228            // ensure that the JIT is enabled "at some point".
4229            mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
4230        }
4231
4232        try {
4233            mInstrumentation.callApplicationOnCreate(app);
4234        } catch (Exception e) {
4235            if (!mInstrumentation.onException(app, e)) {
4236                throw new RuntimeException(
4237                    "Unable to create application " + app.getClass().getName()
4238                    + ": " + e.toString(), e);
4239            }
4240        }
4241    }
4242
4243    /*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
4244        IActivityManager am = ActivityManagerNative.getDefault();
4245        if (mBoundApplication.profileFile != null && mBoundApplication.handlingProfiling) {
4246            Debug.stopMethodTracing();
4247        }
4248        //Slog.i(TAG, "am: " + ActivityManagerNative.getDefault()
4249        //      + ", app thr: " + mAppThread);
4250        try {
4251            am.finishInstrumentation(mAppThread, resultCode, results);
4252        } catch (RemoteException ex) {
4253        }
4254    }
4255
4256    private final void installContentProviders(
4257            Context context, List<ProviderInfo> providers) {
4258        final ArrayList<IActivityManager.ContentProviderHolder> results =
4259            new ArrayList<IActivityManager.ContentProviderHolder>();
4260
4261        Iterator<ProviderInfo> i = providers.iterator();
4262        while (i.hasNext()) {
4263            ProviderInfo cpi = i.next();
4264            StringBuilder buf = new StringBuilder(128);
4265            buf.append("Publishing provider ");
4266            buf.append(cpi.authority);
4267            buf.append(": ");
4268            buf.append(cpi.name);
4269            Log.i(TAG, buf.toString());
4270            IContentProvider cp = installProvider(context, null, cpi, false);
4271            if (cp != null) {
4272                IActivityManager.ContentProviderHolder cph =
4273                    new IActivityManager.ContentProviderHolder(cpi);
4274                cph.provider = cp;
4275                results.add(cph);
4276                // Don't ever unload this provider from the process.
4277                synchronized(mProviderMap) {
4278                    mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000));
4279                }
4280            }
4281        }
4282
4283        try {
4284            ActivityManagerNative.getDefault().publishContentProviders(
4285                getApplicationThread(), results);
4286        } catch (RemoteException ex) {
4287        }
4288    }
4289
4290    private final IContentProvider getProvider(Context context, String name) {
4291        synchronized(mProviderMap) {
4292            final ProviderRecord pr = mProviderMap.get(name);
4293            if (pr != null) {
4294                return pr.mProvider;
4295            }
4296        }
4297
4298        IActivityManager.ContentProviderHolder holder = null;
4299        try {
4300            holder = ActivityManagerNative.getDefault().getContentProvider(
4301                getApplicationThread(), name);
4302        } catch (RemoteException ex) {
4303        }
4304        if (holder == null) {
4305            Slog.e(TAG, "Failed to find provider info for " + name);
4306            return null;
4307        }
4308        if (holder.permissionFailure != null) {
4309            throw new SecurityException("Permission " + holder.permissionFailure
4310                    + " required for provider " + name);
4311        }
4312
4313        IContentProvider prov = installProvider(context, holder.provider,
4314                holder.info, true);
4315        //Slog.i(TAG, "noReleaseNeeded=" + holder.noReleaseNeeded);
4316        if (holder.noReleaseNeeded || holder.provider == null) {
4317            // We are not going to release the provider if it is an external
4318            // provider that doesn't care about being released, or if it is
4319            // a local provider running in this process.
4320            //Slog.i(TAG, "*** NO RELEASE NEEDED");
4321            synchronized(mProviderMap) {
4322                mProviderRefCountMap.put(prov.asBinder(), new ProviderRefCount(10000));
4323            }
4324        }
4325        return prov;
4326    }
4327
4328    public final IContentProvider acquireProvider(Context c, String name) {
4329        IContentProvider provider = getProvider(c, name);
4330        if(provider == null)
4331            return null;
4332        IBinder jBinder = provider.asBinder();
4333        synchronized(mProviderMap) {
4334            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
4335            if(prc == null) {
4336                mProviderRefCountMap.put(jBinder, new ProviderRefCount(1));
4337            } else {
4338                prc.count++;
4339            } //end else
4340        } //end synchronized
4341        return provider;
4342    }
4343
4344    public final boolean releaseProvider(IContentProvider provider) {
4345        if(provider == null) {
4346            return false;
4347        }
4348        IBinder jBinder = provider.asBinder();
4349        synchronized(mProviderMap) {
4350            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
4351            if(prc == null) {
4352                if(localLOGV) Slog.v(TAG, "releaseProvider::Weird shouldnt be here");
4353                return false;
4354            } else {
4355                prc.count--;
4356                if(prc.count == 0) {
4357                    // Schedule the actual remove asynchronously, since we
4358                    // don't know the context this will be called in.
4359                    // TODO: it would be nice to post a delayed message, so
4360                    // if we come back and need the same provider quickly
4361                    // we will still have it available.
4362                    Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, provider);
4363                    mH.sendMessage(msg);
4364                } //end if
4365            } //end else
4366        } //end synchronized
4367        return true;
4368    }
4369
4370    final void completeRemoveProvider(IContentProvider provider) {
4371        IBinder jBinder = provider.asBinder();
4372        String name = null;
4373        synchronized(mProviderMap) {
4374            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
4375            if(prc != null && prc.count == 0) {
4376                mProviderRefCountMap.remove(jBinder);
4377                //invoke removeProvider to dereference provider
4378                name = removeProviderLocked(provider);
4379            }
4380        }
4381
4382        if (name != null) {
4383            try {
4384                if(localLOGV) Slog.v(TAG, "removeProvider::Invoking " +
4385                        "ActivityManagerNative.removeContentProvider(" + name);
4386                ActivityManagerNative.getDefault().removeContentProvider(
4387                        getApplicationThread(), name);
4388            } catch (RemoteException e) {
4389                //do nothing content provider object is dead any way
4390            } //end catch
4391        }
4392    }
4393
4394    public final String removeProviderLocked(IContentProvider provider) {
4395        if (provider == null) {
4396            return null;
4397        }
4398        IBinder providerBinder = provider.asBinder();
4399
4400        String name = null;
4401
4402        // remove the provider from mProviderMap
4403        Iterator<ProviderRecord> iter = mProviderMap.values().iterator();
4404        while (iter.hasNext()) {
4405            ProviderRecord pr = iter.next();
4406            IBinder myBinder = pr.mProvider.asBinder();
4407            if (myBinder == providerBinder) {
4408                //find if its published by this process itself
4409                if(pr.mLocalProvider != null) {
4410                    if(localLOGV) Slog.i(TAG, "removeProvider::found local provider returning");
4411                    return name;
4412                }
4413                if(localLOGV) Slog.v(TAG, "removeProvider::Not local provider Unlinking " +
4414                        "death recipient");
4415                //content provider is in another process
4416                myBinder.unlinkToDeath(pr, 0);
4417                iter.remove();
4418                //invoke remove only once for the very first name seen
4419                if(name == null) {
4420                    name = pr.mName;
4421                }
4422            } //end if myBinder
4423        }  //end while iter
4424
4425        return name;
4426    }
4427
4428    final void removeDeadProvider(String name, IContentProvider provider) {
4429        synchronized(mProviderMap) {
4430            ProviderRecord pr = mProviderMap.get(name);
4431            if (pr.mProvider.asBinder() == provider.asBinder()) {
4432                Slog.i(TAG, "Removing dead content provider: " + name);
4433                ProviderRecord removed = mProviderMap.remove(name);
4434                if (removed != null) {
4435                    removed.mProvider.asBinder().unlinkToDeath(removed, 0);
4436                }
4437            }
4438        }
4439    }
4440
4441    final void removeDeadProviderLocked(String name, IContentProvider provider) {
4442        ProviderRecord pr = mProviderMap.get(name);
4443        if (pr.mProvider.asBinder() == provider.asBinder()) {
4444            Slog.i(TAG, "Removing dead content provider: " + name);
4445            ProviderRecord removed = mProviderMap.remove(name);
4446            if (removed != null) {
4447                removed.mProvider.asBinder().unlinkToDeath(removed, 0);
4448            }
4449        }
4450    }
4451
4452    private final IContentProvider installProvider(Context context,
4453            IContentProvider provider, ProviderInfo info, boolean noisy) {
4454        ContentProvider localProvider = null;
4455        if (provider == null) {
4456            if (noisy) {
4457                Slog.d(TAG, "Loading provider " + info.authority + ": "
4458                        + info.name);
4459            }
4460            Context c = null;
4461            ApplicationInfo ai = info.applicationInfo;
4462            if (context.getPackageName().equals(ai.packageName)) {
4463                c = context;
4464            } else if (mInitialApplication != null &&
4465                    mInitialApplication.getPackageName().equals(ai.packageName)) {
4466                c = mInitialApplication;
4467            } else {
4468                try {
4469                    c = context.createPackageContext(ai.packageName,
4470                            Context.CONTEXT_INCLUDE_CODE);
4471                } catch (PackageManager.NameNotFoundException e) {
4472                }
4473            }
4474            if (c == null) {
4475                Slog.w(TAG, "Unable to get context for package " +
4476                      ai.packageName +
4477                      " while loading content provider " +
4478                      info.name);
4479                return null;
4480            }
4481            try {
4482                final java.lang.ClassLoader cl = c.getClassLoader();
4483                localProvider = (ContentProvider)cl.
4484                    loadClass(info.name).newInstance();
4485                provider = localProvider.getIContentProvider();
4486                if (provider == null) {
4487                    Slog.e(TAG, "Failed to instantiate class " +
4488                          info.name + " from sourceDir " +
4489                          info.applicationInfo.sourceDir);
4490                    return null;
4491                }
4492                if (Config.LOGV) Slog.v(
4493                    TAG, "Instantiating local provider " + info.name);
4494                // XXX Need to create the correct context for this provider.
4495                localProvider.attachInfo(c, info);
4496            } catch (java.lang.Exception e) {
4497                if (!mInstrumentation.onException(null, e)) {
4498                    throw new RuntimeException(
4499                            "Unable to get provider " + info.name
4500                            + ": " + e.toString(), e);
4501                }
4502                return null;
4503            }
4504        } else if (localLOGV) {
4505            Slog.v(TAG, "Installing external provider " + info.authority + ": "
4506                    + info.name);
4507        }
4508
4509        synchronized (mProviderMap) {
4510            // Cache the pointer for the remote provider.
4511            String names[] = PATTERN_SEMICOLON.split(info.authority);
4512            for (int i=0; i<names.length; i++) {
4513                ProviderRecord pr = new ProviderRecord(names[i], provider,
4514                        localProvider);
4515                try {
4516                    provider.asBinder().linkToDeath(pr, 0);
4517                    mProviderMap.put(names[i], pr);
4518                } catch (RemoteException e) {
4519                    return null;
4520                }
4521            }
4522            if (localProvider != null) {
4523                mLocalProviders.put(provider.asBinder(),
4524                        new ProviderRecord(null, provider, localProvider));
4525            }
4526        }
4527
4528        return provider;
4529    }
4530
4531    private final void attach(boolean system) {
4532        sThreadLocal.set(this);
4533        mSystemThread = system;
4534        if (!system) {
4535            ViewRoot.addFirstDrawHandler(new Runnable() {
4536                public void run() {
4537                    ensureJitEnabled();
4538                }
4539            });
4540            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
4541            RuntimeInit.setApplicationObject(mAppThread.asBinder());
4542            IActivityManager mgr = ActivityManagerNative.getDefault();
4543            try {
4544                mgr.attachApplication(mAppThread);
4545            } catch (RemoteException ex) {
4546            }
4547        } else {
4548            // Don't set application object here -- if the system crashes,
4549            // we can't display an alert, we just want to die die die.
4550            android.ddm.DdmHandleAppName.setAppName("system_process");
4551            try {
4552                mInstrumentation = new Instrumentation();
4553                ContextImpl context = new ContextImpl();
4554                context.init(getSystemContext().mPackageInfo, null, this);
4555                Application app = Instrumentation.newApplication(Application.class, context);
4556                mAllApplications.add(app);
4557                mInitialApplication = app;
4558                app.onCreate();
4559            } catch (Exception e) {
4560                throw new RuntimeException(
4561                        "Unable to instantiate Application():" + e.toString(), e);
4562            }
4563        }
4564
4565        ViewRoot.addConfigCallback(new ComponentCallbacks() {
4566            public void onConfigurationChanged(Configuration newConfig) {
4567                synchronized (mPackages) {
4568                    // We need to apply this change to the resources
4569                    // immediately, because upon returning the view
4570                    // hierarchy will be informed about it.
4571                    if (applyConfigurationToResourcesLocked(newConfig)) {
4572                        // This actually changed the resources!  Tell
4573                        // everyone about it.
4574                        if (mPendingConfiguration == null ||
4575                                mPendingConfiguration.isOtherSeqNewer(newConfig)) {
4576                            mPendingConfiguration = newConfig;
4577
4578                            queueOrSendMessage(H.CONFIGURATION_CHANGED, newConfig);
4579                        }
4580                    }
4581                }
4582            }
4583            public void onLowMemory() {
4584            }
4585        });
4586    }
4587
4588    private final void detach()
4589    {
4590        sThreadLocal.set(null);
4591    }
4592
4593    public static final ActivityThread systemMain() {
4594        ActivityThread thread = new ActivityThread();
4595        thread.attach(true);
4596        return thread;
4597    }
4598
4599    public final void installSystemProviders(List providers) {
4600        if (providers != null) {
4601            installContentProviders(mInitialApplication,
4602                                    (List<ProviderInfo>)providers);
4603        }
4604    }
4605
4606    public static final void main(String[] args) {
4607        SamplingProfilerIntegration.start();
4608
4609        Process.setArgV0("<pre-initialized>");
4610
4611        Looper.prepareMainLooper();
4612
4613        ActivityThread thread = new ActivityThread();
4614        thread.attach(false);
4615
4616        Looper.loop();
4617
4618        if (Process.supportsProcesses()) {
4619            throw new RuntimeException("Main thread loop unexpectedly exited");
4620        }
4621
4622        thread.detach();
4623        String name = (thread.mInitialApplication != null)
4624            ? thread.mInitialApplication.getPackageName()
4625            : "<unknown>";
4626        Slog.i(TAG, "Main thread of " + name + " is now exiting");
4627    }
4628}
4629