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