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