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