ActivityThread.java revision 30d7189067524000c738c188c4ff91f84f474d25
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        if (!show && !r.stopped) {
2596            performStopActivityInner(r, null, show, false);
2597        } else if (show && r.stopped) {
2598            // If we are getting ready to gc after going to the background, well
2599            // we are back active so skip it.
2600            unscheduleGcIdler();
2601
2602            r.activity.performRestart();
2603            r.stopped = false;
2604        }
2605        if (r.activity.mDecor != null) {
2606            if (Config.LOGV) Slog.v(
2607                TAG, "Handle window " + r + " visibility: " + show);
2608            updateVisibility(r, show);
2609        }
2610    }
2611
2612    private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) {
2613        final int N = results.size();
2614        for (int i=0; i<N; i++) {
2615            ResultInfo ri = results.get(i);
2616            try {
2617                if (ri.mData != null) {
2618                    ri.mData.setExtrasClassLoader(r.activity.getClassLoader());
2619                }
2620                if (DEBUG_RESULTS) Slog.v(TAG,
2621                        "Delivering result to activity " + r + " : " + ri);
2622                r.activity.dispatchActivityResult(ri.mResultWho,
2623                        ri.mRequestCode, ri.mResultCode, ri.mData);
2624            } catch (Exception e) {
2625                if (!mInstrumentation.onException(r.activity, e)) {
2626                    throw new RuntimeException(
2627                            "Failure delivering result " + ri + " to activity "
2628                            + r.intent.getComponent().toShortString()
2629                            + ": " + e.toString(), e);
2630                }
2631            }
2632        }
2633    }
2634
2635    private final void handleSendResult(ResultData res) {
2636        ActivityClientRecord r = mActivities.get(res.token);
2637        if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r);
2638        if (r != null) {
2639            final boolean resumed = !r.paused;
2640            if (!r.activity.mFinished && r.activity.mDecor != null
2641                    && r.hideForNow && resumed) {
2642                // We had hidden the activity because it started another
2643                // one...  we have gotten a result back and we are not
2644                // paused, so make sure our window is visible.
2645                updateVisibility(r, true);
2646            }
2647            if (resumed) {
2648                try {
2649                    // Now we are idle.
2650                    r.activity.mCalled = false;
2651                    r.activity.mTemporaryPause = true;
2652                    mInstrumentation.callActivityOnPause(r.activity);
2653                    if (!r.activity.mCalled) {
2654                        throw new SuperNotCalledException(
2655                            "Activity " + r.intent.getComponent().toShortString()
2656                            + " did not call through to super.onPause()");
2657                    }
2658                } catch (SuperNotCalledException e) {
2659                    throw e;
2660                } catch (Exception e) {
2661                    if (!mInstrumentation.onException(r.activity, e)) {
2662                        throw new RuntimeException(
2663                                "Unable to pause activity "
2664                                + r.intent.getComponent().toShortString()
2665                                + ": " + e.toString(), e);
2666                    }
2667                }
2668            }
2669            deliverResults(r, res.results);
2670            if (resumed) {
2671                mInstrumentation.callActivityOnResume(r.activity);
2672                r.activity.mTemporaryPause = false;
2673            }
2674        }
2675    }
2676
2677    public final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing) {
2678        return performDestroyActivity(token, finishing, 0, false);
2679    }
2680
2681    private final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
2682            int configChanges, boolean getNonConfigInstance) {
2683        ActivityClientRecord r = mActivities.get(token);
2684        if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
2685        if (r != null) {
2686            r.activity.mConfigChangeFlags |= configChanges;
2687            if (finishing) {
2688                r.activity.mFinished = true;
2689            }
2690            if (!r.paused) {
2691                try {
2692                    r.activity.mCalled = false;
2693                    mInstrumentation.callActivityOnPause(r.activity);
2694                    EventLog.writeEvent(LOG_ON_PAUSE_CALLED,
2695                            r.activity.getComponentName().getClassName());
2696                    if (!r.activity.mCalled) {
2697                        throw new SuperNotCalledException(
2698                            "Activity " + safeToComponentShortString(r.intent)
2699                            + " did not call through to super.onPause()");
2700                    }
2701                } catch (SuperNotCalledException e) {
2702                    throw e;
2703                } catch (Exception e) {
2704                    if (!mInstrumentation.onException(r.activity, e)) {
2705                        throw new RuntimeException(
2706                                "Unable to pause activity "
2707                                + safeToComponentShortString(r.intent)
2708                                + ": " + e.toString(), e);
2709                    }
2710                }
2711                r.paused = true;
2712            }
2713            if (!r.stopped) {
2714                try {
2715                    r.activity.performStop();
2716                } catch (SuperNotCalledException e) {
2717                    throw e;
2718                } catch (Exception e) {
2719                    if (!mInstrumentation.onException(r.activity, e)) {
2720                        throw new RuntimeException(
2721                                "Unable to stop activity "
2722                                + safeToComponentShortString(r.intent)
2723                                + ": " + e.toString(), e);
2724                    }
2725                }
2726                r.stopped = true;
2727            }
2728            if (getNonConfigInstance) {
2729                try {
2730                    r.lastNonConfigurationInstances
2731                            = r.activity.retainNonConfigurationInstances();
2732                } catch (Exception e) {
2733                    if (!mInstrumentation.onException(r.activity, e)) {
2734                        throw new RuntimeException(
2735                                "Unable to retain activity "
2736                                + r.intent.getComponent().toShortString()
2737                                + ": " + e.toString(), e);
2738                    }
2739                }
2740            }
2741            try {
2742                r.activity.mCalled = false;
2743                mInstrumentation.callActivityOnDestroy(r.activity);
2744                if (!r.activity.mCalled) {
2745                    throw new SuperNotCalledException(
2746                        "Activity " + safeToComponentShortString(r.intent) +
2747                        " did not call through to super.onDestroy()");
2748                }
2749                if (r.window != null) {
2750                    r.window.closeAllPanels();
2751                }
2752            } catch (SuperNotCalledException e) {
2753                throw e;
2754            } catch (Exception e) {
2755                if (!mInstrumentation.onException(r.activity, e)) {
2756                    throw new RuntimeException(
2757                            "Unable to destroy activity " + safeToComponentShortString(r.intent)
2758                            + ": " + e.toString(), e);
2759                }
2760            }
2761        }
2762        mActivities.remove(token);
2763
2764        return r;
2765    }
2766
2767    private static String safeToComponentShortString(Intent intent) {
2768        ComponentName component = intent.getComponent();
2769        return component == null ? "[Unknown]" : component.toShortString();
2770    }
2771
2772    private final void handleDestroyActivity(IBinder token, boolean finishing,
2773            int configChanges, boolean getNonConfigInstance) {
2774        ActivityClientRecord r = performDestroyActivity(token, finishing,
2775                configChanges, getNonConfigInstance);
2776        if (r != null) {
2777            cleanUpPendingRemoveWindows(r);
2778            WindowManager wm = r.activity.getWindowManager();
2779            View v = r.activity.mDecor;
2780            if (v != null) {
2781                if (r.activity.mVisibleFromServer) {
2782                    mNumVisibleActivities--;
2783                }
2784                IBinder wtoken = v.getWindowToken();
2785                if (r.activity.mWindowAdded) {
2786                    if (r.onlyLocalRequest) {
2787                        // Hold off on removing this until the new activity's
2788                        // window is being added.
2789                        r.mPendingRemoveWindow = v;
2790                        r.mPendingRemoveWindowManager = wm;
2791                    } else {
2792                        wm.removeViewImmediate(v);
2793                    }
2794                }
2795                if (wtoken != null && r.mPendingRemoveWindow == null) {
2796                    WindowManagerImpl.getDefault().closeAll(wtoken,
2797                            r.activity.getClass().getName(), "Activity");
2798                }
2799                r.activity.mDecor = null;
2800            }
2801            if (r.mPendingRemoveWindow == null) {
2802                // If we are delaying the removal of the activity window, then
2803                // we can't clean up all windows here.  Note that we can't do
2804                // so later either, which means any windows that aren't closed
2805                // by the app will leak.  Well we try to warning them a lot
2806                // about leaking windows, because that is a bug, so if they are
2807                // using this recreate facility then they get to live with leaks.
2808                WindowManagerImpl.getDefault().closeAll(token,
2809                        r.activity.getClass().getName(), "Activity");
2810            }
2811
2812            // Mocked out contexts won't be participating in the normal
2813            // process lifecycle, but if we're running with a proper
2814            // ApplicationContext we need to have it tear down things
2815            // cleanly.
2816            Context c = r.activity.getBaseContext();
2817            if (c instanceof ContextImpl) {
2818                ((ContextImpl) c).scheduleFinalCleanup(
2819                        r.activity.getClass().getName(), "Activity");
2820            }
2821        }
2822        if (finishing) {
2823            try {
2824                ActivityManagerNative.getDefault().activityDestroyed(token);
2825            } catch (RemoteException ex) {
2826                // If the system process has died, it's game over for everyone.
2827            }
2828        }
2829    }
2830
2831    public final void requestRelaunchActivity(IBinder token,
2832            List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
2833            int configChanges, boolean notResumed, Configuration config,
2834            boolean fromServer) {
2835        ActivityClientRecord target = null;
2836
2837        synchronized (mPackages) {
2838            for (int i=0; i<mRelaunchingActivities.size(); i++) {
2839                ActivityClientRecord r = mRelaunchingActivities.get(i);
2840                if (r.token == token) {
2841                    target = r;
2842                    if (pendingResults != null) {
2843                        if (r.pendingResults != null) {
2844                            r.pendingResults.addAll(pendingResults);
2845                        } else {
2846                            r.pendingResults = pendingResults;
2847                        }
2848                    }
2849                    if (pendingNewIntents != null) {
2850                        if (r.pendingIntents != null) {
2851                            r.pendingIntents.addAll(pendingNewIntents);
2852                        } else {
2853                            r.pendingIntents = pendingNewIntents;
2854                        }
2855                    }
2856                    break;
2857                }
2858            }
2859
2860            if (target == null) {
2861                target = new ActivityClientRecord();
2862                target.token = token;
2863                target.pendingResults = pendingResults;
2864                target.pendingIntents = pendingNewIntents;
2865                if (!fromServer) {
2866                    ActivityClientRecord existing = mActivities.get(token);
2867                    if (existing != null) {
2868                        target.startsNotResumed = existing.paused;
2869                    }
2870                    target.onlyLocalRequest = true;
2871                }
2872                mRelaunchingActivities.add(target);
2873                queueOrSendMessage(H.RELAUNCH_ACTIVITY, target);
2874            }
2875
2876            if (fromServer) {
2877                target.startsNotResumed = notResumed;
2878                target.onlyLocalRequest = false;
2879            }
2880            if (config != null) {
2881                target.createdConfig = config;
2882            }
2883            target.pendingConfigChanges |= configChanges;
2884        }
2885    }
2886
2887    private final void handleRelaunchActivity(ActivityClientRecord tmp) {
2888        // If we are getting ready to gc after going to the background, well
2889        // we are back active so skip it.
2890        unscheduleGcIdler();
2891
2892        Configuration changedConfig = null;
2893        int configChanges = 0;
2894
2895        // First: make sure we have the most recent configuration and most
2896        // recent version of the activity, or skip it if some previous call
2897        // had taken a more recent version.
2898        synchronized (mPackages) {
2899            int N = mRelaunchingActivities.size();
2900            IBinder token = tmp.token;
2901            tmp = null;
2902            for (int i=0; i<N; i++) {
2903                ActivityClientRecord r = mRelaunchingActivities.get(i);
2904                if (r.token == token) {
2905                    tmp = r;
2906                    configChanges |= tmp.pendingConfigChanges;
2907                    mRelaunchingActivities.remove(i);
2908                    i--;
2909                    N--;
2910                }
2911            }
2912
2913            if (tmp == null) {
2914                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Abort, activity not relaunching!");
2915                return;
2916            }
2917
2918            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
2919                    + tmp.token + " with configChanges=0x"
2920                    + Integer.toHexString(configChanges));
2921
2922            if (mPendingConfiguration != null) {
2923                changedConfig = mPendingConfiguration;
2924                mPendingConfiguration = null;
2925            }
2926        }
2927
2928        if (tmp.createdConfig != null) {
2929            // If the activity manager is passing us its current config,
2930            // assume that is really what we want regardless of what we
2931            // may have pending.
2932            if (mConfiguration == null
2933                    || (tmp.createdConfig.isOtherSeqNewer(mConfiguration)
2934                            && mConfiguration.diff(tmp.createdConfig) != 0)) {
2935                if (changedConfig == null
2936                        || tmp.createdConfig.isOtherSeqNewer(changedConfig)) {
2937                    changedConfig = tmp.createdConfig;
2938                }
2939            }
2940        }
2941
2942        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
2943                + tmp.token + ": changedConfig=" + changedConfig);
2944
2945        // If there was a pending configuration change, execute it first.
2946        if (changedConfig != null) {
2947            handleConfigurationChanged(changedConfig);
2948        }
2949
2950        ActivityClientRecord r = mActivities.get(tmp.token);
2951        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
2952        if (r == null) {
2953            return;
2954        }
2955
2956        r.activity.mConfigChangeFlags |= configChanges;
2957        r.onlyLocalRequest = tmp.onlyLocalRequest;
2958        Intent currentIntent = r.activity.mIntent;
2959
2960        r.activity.mChangingConfigurations = true;
2961
2962        // Need to ensure state is saved.
2963        if (!r.paused) {
2964            performPauseActivity(r.token, false, r.isPreHoneycomb());
2965        }
2966        if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
2967            r.state = new Bundle();
2968            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
2969        }
2970
2971        handleDestroyActivity(r.token, false, configChanges, true);
2972
2973        r.activity = null;
2974        r.window = null;
2975        r.hideForNow = false;
2976        r.nextIdle = null;
2977        // Merge any pending results and pending intents; don't just replace them
2978        if (tmp.pendingResults != null) {
2979            if (r.pendingResults == null) {
2980                r.pendingResults = tmp.pendingResults;
2981            } else {
2982                r.pendingResults.addAll(tmp.pendingResults);
2983            }
2984        }
2985        if (tmp.pendingIntents != null) {
2986            if (r.pendingIntents == null) {
2987                r.pendingIntents = tmp.pendingIntents;
2988            } else {
2989                r.pendingIntents.addAll(tmp.pendingIntents);
2990            }
2991        }
2992        r.startsNotResumed = tmp.startsNotResumed;
2993
2994        handleLaunchActivity(r, currentIntent);
2995    }
2996
2997    private final void handleRequestThumbnail(IBinder token) {
2998        ActivityClientRecord r = mActivities.get(token);
2999        Bitmap thumbnail = createThumbnailBitmap(r);
3000        CharSequence description = null;
3001        try {
3002            description = r.activity.onCreateDescription();
3003        } catch (Exception e) {
3004            if (!mInstrumentation.onException(r.activity, e)) {
3005                throw new RuntimeException(
3006                        "Unable to create description of activity "
3007                        + r.intent.getComponent().toShortString()
3008                        + ": " + e.toString(), e);
3009            }
3010        }
3011        //System.out.println("Reporting top thumbnail " + thumbnail);
3012        try {
3013            ActivityManagerNative.getDefault().reportThumbnail(
3014                token, thumbnail, description);
3015        } catch (RemoteException ex) {
3016        }
3017    }
3018
3019    ArrayList<ComponentCallbacks> collectComponentCallbacksLocked(
3020            boolean allActivities, Configuration newConfig) {
3021        ArrayList<ComponentCallbacks> callbacks
3022                = new ArrayList<ComponentCallbacks>();
3023
3024        if (mActivities.size() > 0) {
3025            Iterator<ActivityClientRecord> it = mActivities.values().iterator();
3026            while (it.hasNext()) {
3027                ActivityClientRecord ar = it.next();
3028                Activity a = ar.activity;
3029                if (a != null) {
3030                    if (!ar.activity.mFinished && (allActivities ||
3031                            (a != null && !ar.paused))) {
3032                        // If the activity is currently resumed, its configuration
3033                        // needs to change right now.
3034                        callbacks.add(a);
3035                    } else if (newConfig != null) {
3036                        // Otherwise, we will tell it about the change
3037                        // the next time it is resumed or shown.  Note that
3038                        // the activity manager may, before then, decide the
3039                        // activity needs to be destroyed to handle its new
3040                        // configuration.
3041                        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Setting activity "
3042                                + ar.activityInfo.name + " newConfig=" + newConfig);
3043                        ar.newConfig = newConfig;
3044                    }
3045                }
3046            }
3047        }
3048        if (mServices.size() > 0) {
3049            Iterator<Service> it = mServices.values().iterator();
3050            while (it.hasNext()) {
3051                callbacks.add(it.next());
3052            }
3053        }
3054        synchronized (mProviderMap) {
3055            if (mLocalProviders.size() > 0) {
3056                Iterator<ProviderClientRecord> it = mLocalProviders.values().iterator();
3057                while (it.hasNext()) {
3058                    callbacks.add(it.next().mLocalProvider);
3059                }
3060            }
3061        }
3062        final int N = mAllApplications.size();
3063        for (int i=0; i<N; i++) {
3064            callbacks.add(mAllApplications.get(i));
3065        }
3066
3067        return callbacks;
3068    }
3069
3070    private final void performConfigurationChanged(
3071            ComponentCallbacks cb, Configuration config) {
3072        // Only for Activity objects, check that they actually call up to their
3073        // superclass implementation.  ComponentCallbacks is an interface, so
3074        // we check the runtime type and act accordingly.
3075        Activity activity = (cb instanceof Activity) ? (Activity) cb : null;
3076        if (activity != null) {
3077            activity.mCalled = false;
3078        }
3079
3080        boolean shouldChangeConfig = false;
3081        if ((activity == null) || (activity.mCurrentConfig == null)) {
3082            shouldChangeConfig = true;
3083        } else {
3084
3085            // If the new config is the same as the config this Activity
3086            // is already running with then don't bother calling
3087            // onConfigurationChanged
3088            int diff = activity.mCurrentConfig.diff(config);
3089            if (diff != 0) {
3090
3091                // If this activity doesn't handle any of the config changes
3092                // then don't bother calling onConfigurationChanged as we're
3093                // going to destroy it.
3094                if ((~activity.mActivityInfo.configChanges & diff) == 0) {
3095                    shouldChangeConfig = true;
3096                }
3097            }
3098        }
3099
3100        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Config callback " + cb
3101                + ": shouldChangeConfig=" + shouldChangeConfig);
3102        if (shouldChangeConfig) {
3103            cb.onConfigurationChanged(config);
3104
3105            if (activity != null) {
3106                if (!activity.mCalled) {
3107                    throw new SuperNotCalledException(
3108                            "Activity " + activity.getLocalClassName() +
3109                        " did not call through to super.onConfigurationChanged()");
3110                }
3111                activity.mConfigChangeFlags = 0;
3112                activity.mCurrentConfig = new Configuration(config);
3113            }
3114        }
3115    }
3116
3117    final boolean applyConfigurationToResourcesLocked(Configuration config) {
3118        if (mResConfiguration == null) {
3119            mResConfiguration = new Configuration();
3120        }
3121        if (!mResConfiguration.isOtherSeqNewer(config)) {
3122            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
3123                    + mResConfiguration.seq + ", newSeq=" + config.seq);
3124            return false;
3125        }
3126        int changes = mResConfiguration.updateFrom(config);
3127        DisplayMetrics dm = getDisplayMetricsLocked(true);
3128
3129        // set it for java, this also affects newly created Resources
3130        if (config.locale != null) {
3131            Locale.setDefault(config.locale);
3132        }
3133
3134        Resources.updateSystemConfiguration(config, dm);
3135
3136        ApplicationPackageManager.configurationChanged();
3137        //Slog.i(TAG, "Configuration changed in " + currentPackageName());
3138
3139        Iterator<WeakReference<Resources>> it =
3140            mActiveResources.values().iterator();
3141        //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
3142        //    mActiveResources.entrySet().iterator();
3143        while (it.hasNext()) {
3144            WeakReference<Resources> v = it.next();
3145            Resources r = v.get();
3146            if (r != null) {
3147                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
3148                        + r + " config to: " + config);
3149                r.updateConfiguration(config, dm);
3150                //Slog.i(TAG, "Updated app resources " + v.getKey()
3151                //        + " " + r + ": " + r.getConfiguration());
3152            } else {
3153                //Slog.i(TAG, "Removing old resources " + v.getKey());
3154                it.remove();
3155            }
3156        }
3157
3158        return changes != 0;
3159    }
3160
3161    final void handleConfigurationChanged(Configuration config) {
3162
3163        ArrayList<ComponentCallbacks> callbacks = null;
3164
3165        synchronized (mPackages) {
3166            if (mPendingConfiguration != null) {
3167                if (!mPendingConfiguration.isOtherSeqNewer(config)) {
3168                    config = mPendingConfiguration;
3169                }
3170                mPendingConfiguration = null;
3171            }
3172
3173            if (config == null) {
3174                return;
3175            }
3176
3177            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
3178                    + config);
3179
3180            applyConfigurationToResourcesLocked(config);
3181
3182            if (mConfiguration == null) {
3183                mConfiguration = new Configuration();
3184            }
3185            if (!mConfiguration.isOtherSeqNewer(config)) {
3186                return;
3187            }
3188            mConfiguration.updateFrom(config);
3189
3190            callbacks = collectComponentCallbacksLocked(false, config);
3191        }
3192
3193        if (callbacks != null) {
3194            final int N = callbacks.size();
3195            for (int i=0; i<N; i++) {
3196                performConfigurationChanged(callbacks.get(i), config);
3197            }
3198        }
3199    }
3200
3201    final void handleActivityConfigurationChanged(IBinder token) {
3202        ActivityClientRecord r = mActivities.get(token);
3203        if (r == null || r.activity == null) {
3204            return;
3205        }
3206
3207        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
3208                + r.activityInfo.name);
3209
3210        performConfigurationChanged(r.activity, mConfiguration);
3211    }
3212
3213    final void handleProfilerControl(boolean start, ProfilerControlData pcd) {
3214        if (start) {
3215            try {
3216                Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(),
3217                        8 * 1024 * 1024, 0);
3218            } catch (RuntimeException e) {
3219                Slog.w(TAG, "Profiling failed on path " + pcd.path
3220                        + " -- can the process access this path?");
3221            } finally {
3222                try {
3223                    pcd.fd.close();
3224                } catch (IOException e) {
3225                    Slog.w(TAG, "Failure closing profile fd", e);
3226                }
3227            }
3228        } else {
3229            Debug.stopMethodTracing();
3230        }
3231    }
3232
3233    final void handleDumpHeap(boolean managed, DumpHeapData dhd) {
3234        if (managed) {
3235            try {
3236                Debug.dumpHprofData(dhd.path, dhd.fd.getFileDescriptor());
3237            } catch (IOException e) {
3238                Slog.w(TAG, "Managed heap dump failed on path " + dhd.path
3239                        + " -- can the process access this path?");
3240            } finally {
3241                try {
3242                    dhd.fd.close();
3243                } catch (IOException e) {
3244                    Slog.w(TAG, "Failure closing profile fd", e);
3245                }
3246            }
3247        } else {
3248            Debug.dumpNativeHeap(dhd.fd.getFileDescriptor());
3249        }
3250    }
3251
3252    final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
3253        boolean hasPkgInfo = false;
3254        if (packages != null) {
3255            for (int i=packages.length-1; i>=0; i--) {
3256                //Slog.i(TAG, "Cleaning old package: " + packages[i]);
3257                if (!hasPkgInfo) {
3258                    WeakReference<LoadedApk> ref;
3259                    ref = mPackages.get(packages[i]);
3260                    if (ref != null && ref.get() != null) {
3261                        hasPkgInfo = true;
3262                    } else {
3263                        ref = mResourcePackages.get(packages[i]);
3264                        if (ref != null && ref.get() != null) {
3265                            hasPkgInfo = true;
3266                        }
3267                    }
3268                }
3269                mPackages.remove(packages[i]);
3270                mResourcePackages.remove(packages[i]);
3271            }
3272        }
3273        ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
3274                hasPkgInfo);
3275    }
3276
3277    final void handleLowMemory() {
3278        ArrayList<ComponentCallbacks> callbacks
3279                = new ArrayList<ComponentCallbacks>();
3280
3281        synchronized (mPackages) {
3282            callbacks = collectComponentCallbacksLocked(true, null);
3283        }
3284
3285        final int N = callbacks.size();
3286        for (int i=0; i<N; i++) {
3287            callbacks.get(i).onLowMemory();
3288        }
3289
3290        // Ask SQLite to free up as much memory as it can, mostly from its page caches.
3291        if (Process.myUid() != Process.SYSTEM_UID) {
3292            int sqliteReleased = SQLiteDatabase.releaseMemory();
3293            EventLog.writeEvent(SQLITE_MEM_RELEASED_EVENT_LOG_TAG, sqliteReleased);
3294        }
3295
3296        // Ask graphics to free up as much as possible (font/image caches)
3297        Canvas.freeCaches();
3298
3299        BinderInternal.forceGc("mem");
3300    }
3301
3302    private final void handleBindApplication(AppBindData data) {
3303        mBoundApplication = data;
3304        mConfiguration = new Configuration(data.config);
3305
3306        // send up app name; do this *before* waiting for debugger
3307        Process.setArgV0(data.processName);
3308        android.ddm.DdmHandleAppName.setAppName(data.processName);
3309
3310        /*
3311         * Before spawning a new process, reset the time zone to be the system time zone.
3312         * This needs to be done because the system time zone could have changed after the
3313         * the spawning of this process. Without doing this this process would have the incorrect
3314         * system time zone.
3315         */
3316        TimeZone.setDefault(null);
3317
3318        /*
3319         * Initialize the default locale in this process for the reasons we set the time zone.
3320         */
3321        Locale.setDefault(data.config.locale);
3322
3323        /*
3324         * Update the system configuration since its preloaded and might not
3325         * reflect configuration changes. The configuration object passed
3326         * in AppBindData can be safely assumed to be up to date
3327         */
3328        Resources.getSystem().updateConfiguration(mConfiguration, null);
3329
3330        data.info = getPackageInfoNoCheck(data.appInfo);
3331
3332        /**
3333         * For system applications on userdebug/eng builds, log stack
3334         * traces of disk and network access to dropbox for analysis.
3335         */
3336        if ((data.appInfo.flags &
3337             (ApplicationInfo.FLAG_SYSTEM |
3338              ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
3339            StrictMode.conditionallyEnableDebugLogging();
3340        }
3341
3342        /**
3343         * For apps targetting SDK Honeycomb or later, we don't allow
3344         * network usage on the main event loop / UI thread.
3345         *
3346         * Note to those grepping:  this is what ultimately throws
3347         * NetworkOnMainThreadException ...
3348         */
3349        if (data.appInfo.targetSdkVersion > 9) {
3350            StrictMode.enableDeathOnNetwork();
3351        }
3352
3353        /**
3354         * Switch this process to density compatibility mode if needed.
3355         */
3356        if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
3357                == 0) {
3358            Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
3359        }
3360
3361        if (data.debugMode != IApplicationThread.DEBUG_OFF) {
3362            // XXX should have option to change the port.
3363            Debug.changeDebugPort(8100);
3364            if (data.debugMode == IApplicationThread.DEBUG_WAIT) {
3365                Slog.w(TAG, "Application " + data.info.getPackageName()
3366                      + " is waiting for the debugger on port 8100...");
3367
3368                IActivityManager mgr = ActivityManagerNative.getDefault();
3369                try {
3370                    mgr.showWaitingForDebugger(mAppThread, true);
3371                } catch (RemoteException ex) {
3372                }
3373
3374                Debug.waitForDebugger();
3375
3376                try {
3377                    mgr.showWaitingForDebugger(mAppThread, false);
3378                } catch (RemoteException ex) {
3379                }
3380
3381            } else {
3382                Slog.w(TAG, "Application " + data.info.getPackageName()
3383                      + " can be debugged on port 8100...");
3384            }
3385        }
3386
3387        /**
3388         * Initialize the default http proxy in this process for the reasons we set the time zone.
3389         */
3390        IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
3391        IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
3392        try {
3393            ProxyProperties proxyProperties = service.getProxy();
3394            Proxy.setHttpProxySystemProperty(proxyProperties);
3395        } catch (RemoteException e) {}
3396
3397        if (data.instrumentationName != null) {
3398            ContextImpl appContext = new ContextImpl();
3399            appContext.init(data.info, null, this);
3400            InstrumentationInfo ii = null;
3401            try {
3402                ii = appContext.getPackageManager().
3403                    getInstrumentationInfo(data.instrumentationName, 0);
3404            } catch (PackageManager.NameNotFoundException e) {
3405            }
3406            if (ii == null) {
3407                throw new RuntimeException(
3408                    "Unable to find instrumentation info for: "
3409                    + data.instrumentationName);
3410            }
3411
3412            mInstrumentationAppDir = ii.sourceDir;
3413            mInstrumentationAppPackage = ii.packageName;
3414            mInstrumentedAppDir = data.info.getAppDir();
3415
3416            ApplicationInfo instrApp = new ApplicationInfo();
3417            instrApp.packageName = ii.packageName;
3418            instrApp.sourceDir = ii.sourceDir;
3419            instrApp.publicSourceDir = ii.publicSourceDir;
3420            instrApp.dataDir = ii.dataDir;
3421            instrApp.nativeLibraryDir = ii.nativeLibraryDir;
3422            LoadedApk pi = getPackageInfo(instrApp,
3423                    appContext.getClassLoader(), false, true);
3424            ContextImpl instrContext = new ContextImpl();
3425            instrContext.init(pi, null, this);
3426
3427            try {
3428                java.lang.ClassLoader cl = instrContext.getClassLoader();
3429                mInstrumentation = (Instrumentation)
3430                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
3431            } catch (Exception e) {
3432                throw new RuntimeException(
3433                    "Unable to instantiate instrumentation "
3434                    + data.instrumentationName + ": " + e.toString(), e);
3435            }
3436
3437            mInstrumentation.init(this, instrContext, appContext,
3438                    new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher);
3439
3440            if (data.profileFile != null && !ii.handleProfiling) {
3441                data.handlingProfiling = true;
3442                File file = new File(data.profileFile);
3443                file.getParentFile().mkdirs();
3444                Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
3445            }
3446
3447            try {
3448                mInstrumentation.onCreate(data.instrumentationArgs);
3449            }
3450            catch (Exception e) {
3451                throw new RuntimeException(
3452                    "Exception thrown in onCreate() of "
3453                    + data.instrumentationName + ": " + e.toString(), e);
3454            }
3455
3456        } else {
3457            mInstrumentation = new Instrumentation();
3458        }
3459
3460        // If the app is being launched for full backup or restore, bring it up in
3461        // a restricted environment with the base application class.
3462        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
3463        mInitialApplication = app;
3464
3465        List<ProviderInfo> providers = data.providers;
3466        if (providers != null) {
3467            installContentProviders(app, providers);
3468            // For process that contain content providers, we want to
3469            // ensure that the JIT is enabled "at some point".
3470            mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
3471        }
3472
3473        try {
3474            mInstrumentation.callApplicationOnCreate(app);
3475        } catch (Exception e) {
3476            if (!mInstrumentation.onException(app, e)) {
3477                throw new RuntimeException(
3478                    "Unable to create application " + app.getClass().getName()
3479                    + ": " + e.toString(), e);
3480            }
3481        }
3482    }
3483
3484    /*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
3485        IActivityManager am = ActivityManagerNative.getDefault();
3486        if (mBoundApplication.profileFile != null && mBoundApplication.handlingProfiling) {
3487            Debug.stopMethodTracing();
3488        }
3489        //Slog.i(TAG, "am: " + ActivityManagerNative.getDefault()
3490        //      + ", app thr: " + mAppThread);
3491        try {
3492            am.finishInstrumentation(mAppThread, resultCode, results);
3493        } catch (RemoteException ex) {
3494        }
3495    }
3496
3497    private final void installContentProviders(
3498            Context context, List<ProviderInfo> providers) {
3499        final ArrayList<IActivityManager.ContentProviderHolder> results =
3500            new ArrayList<IActivityManager.ContentProviderHolder>();
3501
3502        Iterator<ProviderInfo> i = providers.iterator();
3503        while (i.hasNext()) {
3504            ProviderInfo cpi = i.next();
3505            StringBuilder buf = new StringBuilder(128);
3506            buf.append("Pub ");
3507            buf.append(cpi.authority);
3508            buf.append(": ");
3509            buf.append(cpi.name);
3510            Log.i(TAG, buf.toString());
3511            IContentProvider cp = installProvider(context, null, cpi, false);
3512            if (cp != null) {
3513                IActivityManager.ContentProviderHolder cph =
3514                    new IActivityManager.ContentProviderHolder(cpi);
3515                cph.provider = cp;
3516                results.add(cph);
3517                // Don't ever unload this provider from the process.
3518                synchronized(mProviderMap) {
3519                    mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000));
3520                }
3521            }
3522        }
3523
3524        try {
3525            ActivityManagerNative.getDefault().publishContentProviders(
3526                getApplicationThread(), results);
3527        } catch (RemoteException ex) {
3528        }
3529    }
3530
3531    private final IContentProvider getExistingProvider(Context context, String name) {
3532        synchronized(mProviderMap) {
3533            final ProviderClientRecord pr = mProviderMap.get(name);
3534            if (pr != null) {
3535                return pr.mProvider;
3536            }
3537            return null;
3538        }
3539    }
3540
3541    private final IContentProvider getProvider(Context context, String name) {
3542        IContentProvider existing = getExistingProvider(context, name);
3543        if (existing != null) {
3544            return existing;
3545        }
3546
3547        IActivityManager.ContentProviderHolder holder = null;
3548        try {
3549            holder = ActivityManagerNative.getDefault().getContentProvider(
3550                getApplicationThread(), name);
3551        } catch (RemoteException ex) {
3552        }
3553        if (holder == null) {
3554            Slog.e(TAG, "Failed to find provider info for " + name);
3555            return null;
3556        }
3557
3558        IContentProvider prov = installProvider(context, holder.provider,
3559                holder.info, true);
3560        //Slog.i(TAG, "noReleaseNeeded=" + holder.noReleaseNeeded);
3561        if (holder.noReleaseNeeded || holder.provider == null) {
3562            // We are not going to release the provider if it is an external
3563            // provider that doesn't care about being released, or if it is
3564            // a local provider running in this process.
3565            //Slog.i(TAG, "*** NO RELEASE NEEDED");
3566            synchronized(mProviderMap) {
3567                mProviderRefCountMap.put(prov.asBinder(), new ProviderRefCount(10000));
3568            }
3569        }
3570        return prov;
3571    }
3572
3573    public final IContentProvider acquireProvider(Context c, String name) {
3574        IContentProvider provider = getProvider(c, name);
3575        if(provider == null)
3576            return null;
3577        IBinder jBinder = provider.asBinder();
3578        synchronized(mProviderMap) {
3579            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
3580            if(prc == null) {
3581                mProviderRefCountMap.put(jBinder, new ProviderRefCount(1));
3582            } else {
3583                prc.count++;
3584            } //end else
3585        } //end synchronized
3586        return provider;
3587    }
3588
3589    public final IContentProvider acquireExistingProvider(Context c, String name) {
3590        IContentProvider provider = getExistingProvider(c, name);
3591        if(provider == null)
3592            return null;
3593        IBinder jBinder = provider.asBinder();
3594        synchronized(mProviderMap) {
3595            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
3596            if(prc == null) {
3597                mProviderRefCountMap.put(jBinder, new ProviderRefCount(1));
3598            } else {
3599                prc.count++;
3600            } //end else
3601        } //end synchronized
3602        return provider;
3603    }
3604
3605    public final boolean releaseProvider(IContentProvider provider) {
3606        if(provider == null) {
3607            return false;
3608        }
3609        IBinder jBinder = provider.asBinder();
3610        synchronized(mProviderMap) {
3611            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
3612            if(prc == null) {
3613                if(localLOGV) Slog.v(TAG, "releaseProvider::Weird shouldn't be here");
3614                return false;
3615            } else {
3616                prc.count--;
3617                if(prc.count == 0) {
3618                    // Schedule the actual remove asynchronously, since we
3619                    // don't know the context this will be called in.
3620                    // TODO: it would be nice to post a delayed message, so
3621                    // if we come back and need the same provider quickly
3622                    // we will still have it available.
3623                    Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, provider);
3624                    mH.sendMessage(msg);
3625                } //end if
3626            } //end else
3627        } //end synchronized
3628        return true;
3629    }
3630
3631    final void completeRemoveProvider(IContentProvider provider) {
3632        IBinder jBinder = provider.asBinder();
3633        String name = null;
3634        synchronized(mProviderMap) {
3635            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
3636            if(prc != null && prc.count == 0) {
3637                mProviderRefCountMap.remove(jBinder);
3638                //invoke removeProvider to dereference provider
3639                name = removeProviderLocked(provider);
3640            }
3641        }
3642
3643        if (name != null) {
3644            try {
3645                if(localLOGV) Slog.v(TAG, "removeProvider::Invoking " +
3646                        "ActivityManagerNative.removeContentProvider(" + name);
3647                ActivityManagerNative.getDefault().removeContentProvider(
3648                        getApplicationThread(), name);
3649            } catch (RemoteException e) {
3650                //do nothing content provider object is dead any way
3651            } //end catch
3652        }
3653    }
3654
3655    public final String removeProviderLocked(IContentProvider provider) {
3656        if (provider == null) {
3657            return null;
3658        }
3659        IBinder providerBinder = provider.asBinder();
3660
3661        String name = null;
3662
3663        // remove the provider from mProviderMap
3664        Iterator<ProviderClientRecord> iter = mProviderMap.values().iterator();
3665        while (iter.hasNext()) {
3666            ProviderClientRecord pr = iter.next();
3667            IBinder myBinder = pr.mProvider.asBinder();
3668            if (myBinder == providerBinder) {
3669                //find if its published by this process itself
3670                if(pr.mLocalProvider != null) {
3671                    if(localLOGV) Slog.i(TAG, "removeProvider::found local provider returning");
3672                    return name;
3673                }
3674                if(localLOGV) Slog.v(TAG, "removeProvider::Not local provider Unlinking " +
3675                        "death recipient");
3676                //content provider is in another process
3677                myBinder.unlinkToDeath(pr, 0);
3678                iter.remove();
3679                //invoke remove only once for the very first name seen
3680                if(name == null) {
3681                    name = pr.mName;
3682                }
3683            } //end if myBinder
3684        }  //end while iter
3685
3686        return name;
3687    }
3688
3689    final void removeDeadProvider(String name, IContentProvider provider) {
3690        synchronized(mProviderMap) {
3691            ProviderClientRecord pr = mProviderMap.get(name);
3692            if (pr.mProvider.asBinder() == provider.asBinder()) {
3693                Slog.i(TAG, "Removing dead content provider: " + name);
3694                ProviderClientRecord removed = mProviderMap.remove(name);
3695                if (removed != null) {
3696                    removed.mProvider.asBinder().unlinkToDeath(removed, 0);
3697                }
3698            }
3699        }
3700    }
3701
3702    final void removeDeadProviderLocked(String name, IContentProvider provider) {
3703        ProviderClientRecord pr = mProviderMap.get(name);
3704        if (pr.mProvider.asBinder() == provider.asBinder()) {
3705            Slog.i(TAG, "Removing dead content provider: " + name);
3706            ProviderClientRecord removed = mProviderMap.remove(name);
3707            if (removed != null) {
3708                removed.mProvider.asBinder().unlinkToDeath(removed, 0);
3709            }
3710        }
3711    }
3712
3713    private final IContentProvider installProvider(Context context,
3714            IContentProvider provider, ProviderInfo info, boolean noisy) {
3715        ContentProvider localProvider = null;
3716        if (provider == null) {
3717            if (noisy) {
3718                Slog.d(TAG, "Loading provider " + info.authority + ": "
3719                        + info.name);
3720            }
3721            Context c = null;
3722            ApplicationInfo ai = info.applicationInfo;
3723            if (context.getPackageName().equals(ai.packageName)) {
3724                c = context;
3725            } else if (mInitialApplication != null &&
3726                    mInitialApplication.getPackageName().equals(ai.packageName)) {
3727                c = mInitialApplication;
3728            } else {
3729                try {
3730                    c = context.createPackageContext(ai.packageName,
3731                            Context.CONTEXT_INCLUDE_CODE);
3732                } catch (PackageManager.NameNotFoundException e) {
3733                }
3734            }
3735            if (c == null) {
3736                Slog.w(TAG, "Unable to get context for package " +
3737                      ai.packageName +
3738                      " while loading content provider " +
3739                      info.name);
3740                return null;
3741            }
3742            try {
3743                final java.lang.ClassLoader cl = c.getClassLoader();
3744                localProvider = (ContentProvider)cl.
3745                    loadClass(info.name).newInstance();
3746                provider = localProvider.getIContentProvider();
3747                if (provider == null) {
3748                    Slog.e(TAG, "Failed to instantiate class " +
3749                          info.name + " from sourceDir " +
3750                          info.applicationInfo.sourceDir);
3751                    return null;
3752                }
3753                if (Config.LOGV) Slog.v(
3754                    TAG, "Instantiating local provider " + info.name);
3755                // XXX Need to create the correct context for this provider.
3756                localProvider.attachInfo(c, info);
3757            } catch (java.lang.Exception e) {
3758                if (!mInstrumentation.onException(null, e)) {
3759                    throw new RuntimeException(
3760                            "Unable to get provider " + info.name
3761                            + ": " + e.toString(), e);
3762                }
3763                return null;
3764            }
3765        } else if (localLOGV) {
3766            Slog.v(TAG, "Installing external provider " + info.authority + ": "
3767                    + info.name);
3768        }
3769
3770        synchronized (mProviderMap) {
3771            // Cache the pointer for the remote provider.
3772            String names[] = PATTERN_SEMICOLON.split(info.authority);
3773            for (int i=0; i<names.length; i++) {
3774                ProviderClientRecord pr = new ProviderClientRecord(names[i], provider,
3775                        localProvider);
3776                try {
3777                    provider.asBinder().linkToDeath(pr, 0);
3778                    mProviderMap.put(names[i], pr);
3779                } catch (RemoteException e) {
3780                    return null;
3781                }
3782            }
3783            if (localProvider != null) {
3784                mLocalProviders.put(provider.asBinder(),
3785                        new ProviderClientRecord(null, provider, localProvider));
3786            }
3787        }
3788
3789        return provider;
3790    }
3791
3792    private final void attach(boolean system) {
3793        sThreadLocal.set(this);
3794        mSystemThread = system;
3795        if (!system) {
3796            ViewRoot.addFirstDrawHandler(new Runnable() {
3797                public void run() {
3798                    ensureJitEnabled();
3799                }
3800            });
3801            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
3802            RuntimeInit.setApplicationObject(mAppThread.asBinder());
3803            IActivityManager mgr = ActivityManagerNative.getDefault();
3804            try {
3805                mgr.attachApplication(mAppThread);
3806            } catch (RemoteException ex) {
3807            }
3808        } else {
3809            // Don't set application object here -- if the system crashes,
3810            // we can't display an alert, we just want to die die die.
3811            android.ddm.DdmHandleAppName.setAppName("system_process");
3812            try {
3813                mInstrumentation = new Instrumentation();
3814                ContextImpl context = new ContextImpl();
3815                context.init(getSystemContext().mPackageInfo, null, this);
3816                Application app = Instrumentation.newApplication(Application.class, context);
3817                mAllApplications.add(app);
3818                mInitialApplication = app;
3819                app.onCreate();
3820            } catch (Exception e) {
3821                throw new RuntimeException(
3822                        "Unable to instantiate Application():" + e.toString(), e);
3823            }
3824        }
3825
3826        ViewRoot.addConfigCallback(new ComponentCallbacks() {
3827            public void onConfigurationChanged(Configuration newConfig) {
3828                synchronized (mPackages) {
3829                    // We need to apply this change to the resources
3830                    // immediately, because upon returning the view
3831                    // hierarchy will be informed about it.
3832                    if (applyConfigurationToResourcesLocked(newConfig)) {
3833                        // This actually changed the resources!  Tell
3834                        // everyone about it.
3835                        if (mPendingConfiguration == null ||
3836                                mPendingConfiguration.isOtherSeqNewer(newConfig)) {
3837                            mPendingConfiguration = newConfig;
3838
3839                            queueOrSendMessage(H.CONFIGURATION_CHANGED, newConfig);
3840                        }
3841                    }
3842                }
3843            }
3844            public void onLowMemory() {
3845            }
3846        });
3847    }
3848
3849    private final void detach()
3850    {
3851        sThreadLocal.set(null);
3852    }
3853
3854    public static final ActivityThread systemMain() {
3855        HardwareRenderer.disable();
3856        ActivityThread thread = new ActivityThread();
3857        thread.attach(true);
3858        return thread;
3859    }
3860
3861    public final void installSystemProviders(List providers) {
3862        if (providers != null) {
3863            installContentProviders(mInitialApplication,
3864                                    (List<ProviderInfo>)providers);
3865        }
3866    }
3867
3868    public static final void main(String[] args) {
3869        SamplingProfilerIntegration.start();
3870
3871        // CloseGuard defaults to true and can be quite spammy.  We
3872        // disable it here, but selectively enable it later (via
3873        // StrictMode) on debug builds, but using DropBox, not logs.
3874        CloseGuard.setEnabled(false);
3875
3876        Process.setArgV0("<pre-initialized>");
3877
3878        Looper.prepareMainLooper();
3879        if (sMainThreadHandler == null) {
3880            sMainThreadHandler = new Handler();
3881        }
3882
3883        ActivityThread thread = new ActivityThread();
3884        thread.attach(false);
3885
3886        if (false) {
3887            Looper.myLooper().setMessageLogging(new
3888                    LogPrinter(Log.DEBUG, "ActivityThread"));
3889        }
3890
3891        Looper.loop();
3892
3893        if (Process.supportsProcesses()) {
3894            throw new RuntimeException("Main thread loop unexpectedly exited");
3895        }
3896
3897        thread.detach();
3898        String name = (thread.mInitialApplication != null)
3899            ? thread.mInitialApplication.getPackageName()
3900            : "<unknown>";
3901        Slog.i(TAG, "Main thread of " + name + " is now exiting");
3902    }
3903}
3904