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