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