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