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