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