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