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