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