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