blob: 182843afeb570aad21abd6f186dac8c59a682756 [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;
1218 Intent args;
1219 public String toString() {
1220 return "ServiceArgsData{token=" + token + " startId=" + startId
1221 + " args=" + args + "}";
1222 }
1223 }
1224
1225 private static final class AppBindData {
1226 PackageInfo info;
1227 String processName;
1228 ApplicationInfo appInfo;
1229 List<ProviderInfo> providers;
1230 ComponentName instrumentationName;
1231 String profileFile;
1232 Bundle instrumentationArgs;
1233 IInstrumentationWatcher instrumentationWatcher;
1234 int debugMode;
Christopher Tate181fafa2009-05-14 11:12:14 -07001235 boolean restrictedBackupMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 Configuration config;
1237 boolean handlingProfiling;
1238 public String toString() {
1239 return "AppBindData{appInfo=" + appInfo + "}";
1240 }
1241 }
1242
1243 private static final class DumpServiceInfo {
1244 FileDescriptor fd;
1245 IBinder service;
1246 String[] args;
1247 boolean dumped;
1248 }
1249
1250 private static final class ResultData {
1251 IBinder token;
1252 List<ResultInfo> results;
1253 public String toString() {
1254 return "ResultData{token=" + token + " results" + results + "}";
1255 }
1256 }
1257
1258 private static final class ContextCleanupInfo {
1259 ApplicationContext context;
1260 String what;
1261 String who;
1262 }
1263
Dianne Hackborn9c8dd552009-06-23 19:22:52 -07001264 private static final class ProfilerControlData {
1265 String path;
1266 ParcelFileDescriptor fd;
1267 }
1268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 private final class ApplicationThread extends ApplicationThreadNative {
1270 private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
1271 private static final String ONE_COUNT_COLUMN = "%17s %8d";
1272 private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
1273
1274 // Formatting for checkin service - update version if row format changes
1275 private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
1276
1277 public final void schedulePauseActivity(IBinder token, boolean finished,
1278 boolean userLeaving, int configChanges) {
1279 queueOrSendMessage(
1280 finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
1281 token,
1282 (userLeaving ? 1 : 0),
1283 configChanges);
1284 }
1285
1286 public final void scheduleStopActivity(IBinder token, boolean showWindow,
1287 int configChanges) {
1288 queueOrSendMessage(
1289 showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,
1290 token, 0, configChanges);
1291 }
1292
1293 public final void scheduleWindowVisibility(IBinder token, boolean showWindow) {
1294 queueOrSendMessage(
1295 showWindow ? H.SHOW_WINDOW : H.HIDE_WINDOW,
1296 token);
1297 }
1298
1299 public final void scheduleResumeActivity(IBinder token, boolean isForward) {
1300 queueOrSendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
1301 }
1302
1303 public final void scheduleSendResult(IBinder token, List<ResultInfo> results) {
1304 ResultData res = new ResultData();
1305 res.token = token;
1306 res.results = results;
1307 queueOrSendMessage(H.SEND_RESULT, res);
1308 }
1309
1310 // we use token to identify this activity without having to send the
1311 // activity itself back to the activity manager. (matters more with ipc)
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001312 public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
1314 List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
1315 ActivityRecord r = new ActivityRecord();
1316
1317 r.token = token;
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001318 r.ident = ident;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 r.intent = intent;
1320 r.activityInfo = info;
1321 r.state = state;
1322
1323 r.pendingResults = pendingResults;
1324 r.pendingIntents = pendingNewIntents;
1325
1326 r.startsNotResumed = notResumed;
1327 r.isForward = isForward;
1328
1329 queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
1330 }
1331
1332 public final void scheduleRelaunchActivity(IBinder token,
1333 List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
1334 int configChanges, boolean notResumed) {
1335 ActivityRecord r = new ActivityRecord();
1336
1337 r.token = token;
1338 r.pendingResults = pendingResults;
1339 r.pendingIntents = pendingNewIntents;
1340 r.startsNotResumed = notResumed;
1341
1342 synchronized (mRelaunchingActivities) {
1343 mRelaunchingActivities.add(r);
1344 }
1345
1346 queueOrSendMessage(H.RELAUNCH_ACTIVITY, r, configChanges);
1347 }
1348
1349 public final void scheduleNewIntent(List<Intent> intents, IBinder token) {
1350 NewIntentData data = new NewIntentData();
1351 data.intents = intents;
1352 data.token = token;
1353
1354 queueOrSendMessage(H.NEW_INTENT, data);
1355 }
1356
1357 public final void scheduleDestroyActivity(IBinder token, boolean finishing,
1358 int configChanges) {
1359 queueOrSendMessage(H.DESTROY_ACTIVITY, token, finishing ? 1 : 0,
1360 configChanges);
1361 }
1362
1363 public final void scheduleReceiver(Intent intent, ActivityInfo info,
1364 int resultCode, String data, Bundle extras, boolean sync) {
1365 ReceiverData r = new ReceiverData();
1366
1367 r.intent = intent;
1368 r.info = info;
1369 r.resultCode = resultCode;
1370 r.resultData = data;
1371 r.resultExtras = extras;
1372 r.sync = sync;
1373
1374 queueOrSendMessage(H.RECEIVER, r);
1375 }
1376
Christopher Tate181fafa2009-05-14 11:12:14 -07001377 public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) {
1378 CreateBackupAgentData d = new CreateBackupAgentData();
1379 d.appInfo = app;
1380 d.backupMode = backupMode;
1381
1382 queueOrSendMessage(H.CREATE_BACKUP_AGENT, d);
1383 }
1384
1385 public final void scheduleDestroyBackupAgent(ApplicationInfo app) {
1386 CreateBackupAgentData d = new CreateBackupAgentData();
1387 d.appInfo = app;
1388
1389 queueOrSendMessage(H.DESTROY_BACKUP_AGENT, d);
1390 }
1391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 public final void scheduleCreateService(IBinder token,
1393 ServiceInfo info) {
1394 CreateServiceData s = new CreateServiceData();
1395 s.token = token;
1396 s.info = info;
1397
1398 queueOrSendMessage(H.CREATE_SERVICE, s);
1399 }
1400
1401 public final void scheduleBindService(IBinder token, Intent intent,
1402 boolean rebind) {
1403 BindServiceData s = new BindServiceData();
1404 s.token = token;
1405 s.intent = intent;
1406 s.rebind = rebind;
1407
1408 queueOrSendMessage(H.BIND_SERVICE, s);
1409 }
1410
1411 public final void scheduleUnbindService(IBinder token, Intent intent) {
1412 BindServiceData s = new BindServiceData();
1413 s.token = token;
1414 s.intent = intent;
1415
1416 queueOrSendMessage(H.UNBIND_SERVICE, s);
1417 }
1418
1419 public final void scheduleServiceArgs(IBinder token, int startId,
1420 Intent args) {
1421 ServiceArgsData s = new ServiceArgsData();
1422 s.token = token;
1423 s.startId = startId;
1424 s.args = args;
1425
1426 queueOrSendMessage(H.SERVICE_ARGS, s);
1427 }
1428
1429 public final void scheduleStopService(IBinder token) {
1430 queueOrSendMessage(H.STOP_SERVICE, token);
1431 }
1432
1433 public final void bindApplication(String processName,
1434 ApplicationInfo appInfo, List<ProviderInfo> providers,
1435 ComponentName instrumentationName, String profileFile,
1436 Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
Christopher Tate181fafa2009-05-14 11:12:14 -07001437 int debugMode, boolean isRestrictedBackupMode, Configuration config,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 Map<String, IBinder> services) {
1439 Process.setArgV0(processName);
1440
1441 if (services != null) {
1442 // Setup the service cache in the ServiceManager
1443 ServiceManager.initServiceCache(services);
1444 }
1445
1446 AppBindData data = new AppBindData();
1447 data.processName = processName;
1448 data.appInfo = appInfo;
1449 data.providers = providers;
1450 data.instrumentationName = instrumentationName;
1451 data.profileFile = profileFile;
1452 data.instrumentationArgs = instrumentationArgs;
1453 data.instrumentationWatcher = instrumentationWatcher;
1454 data.debugMode = debugMode;
Christopher Tate181fafa2009-05-14 11:12:14 -07001455 data.restrictedBackupMode = isRestrictedBackupMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 data.config = config;
1457 queueOrSendMessage(H.BIND_APPLICATION, data);
1458 }
1459
1460 public final void scheduleExit() {
1461 queueOrSendMessage(H.EXIT_APPLICATION, null);
1462 }
1463
1464 public void requestThumbnail(IBinder token) {
1465 queueOrSendMessage(H.REQUEST_THUMBNAIL, token);
1466 }
1467
1468 public void scheduleConfigurationChanged(Configuration config) {
1469 synchronized (mRelaunchingActivities) {
1470 mPendingConfiguration = config;
1471 }
1472 queueOrSendMessage(H.CONFIGURATION_CHANGED, config);
1473 }
1474
1475 public void updateTimeZone() {
1476 TimeZone.setDefault(null);
1477 }
1478
1479 public void processInBackground() {
1480 mH.removeMessages(H.GC_WHEN_IDLE);
1481 mH.sendMessage(mH.obtainMessage(H.GC_WHEN_IDLE));
1482 }
1483
1484 public void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args) {
1485 DumpServiceInfo data = new DumpServiceInfo();
1486 data.fd = fd;
1487 data.service = servicetoken;
1488 data.args = args;
1489 data.dumped = false;
1490 queueOrSendMessage(H.DUMP_SERVICE, data);
1491 synchronized (data) {
1492 while (!data.dumped) {
1493 try {
1494 data.wait();
1495 } catch (InterruptedException e) {
1496 // no need to do anything here, we will keep waiting until
1497 // dumped is set
1498 }
1499 }
1500 }
1501 }
1502
1503 // This function exists to make sure all receiver dispatching is
1504 // correctly ordered, since these are one-way calls and the binder driver
1505 // applies transaction ordering per object for such calls.
1506 public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
1507 int resultCode, String dataStr, Bundle extras, boolean ordered)
1508 throws RemoteException {
1509 receiver.performReceive(intent, resultCode, dataStr, extras, ordered);
1510 }
1511
1512 public void scheduleLowMemory() {
1513 queueOrSendMessage(H.LOW_MEMORY, null);
1514 }
1515
1516 public void scheduleActivityConfigurationChanged(IBinder token) {
1517 queueOrSendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token);
1518 }
1519
1520 public void requestPss() {
1521 try {
1522 ActivityManagerNative.getDefault().reportPss(this,
1523 (int)Process.getPss(Process.myPid()));
1524 } catch (RemoteException e) {
1525 }
1526 }
1527
Dianne Hackborn9c8dd552009-06-23 19:22:52 -07001528 public void profilerControl(boolean start, String path, ParcelFileDescriptor fd) {
1529 ProfilerControlData pcd = new ProfilerControlData();
1530 pcd.path = path;
1531 pcd.fd = fd;
1532 queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08001533 }
1534
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07001535 public void setSchedulingGroup(int group) {
1536 // Note: do this immediately, since going into the foreground
1537 // should happen regardless of what pending work we have to do
1538 // and the activity manager will wait for us to report back that
1539 // we are done before sending us to the background.
1540 try {
1541 Process.setProcessGroup(Process.myPid(), group);
1542 } catch (Exception e) {
1543 Log.w(TAG, "Failed setting process group to " + group, e);
1544 }
1545 }
1546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 @Override
1548 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1549 long nativeMax = Debug.getNativeHeapSize() / 1024;
1550 long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
1551 long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
1552
1553 Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
1554 Debug.getMemoryInfo(memInfo);
1555
1556 final int nativeShared = memInfo.nativeSharedDirty;
1557 final int dalvikShared = memInfo.dalvikSharedDirty;
1558 final int otherShared = memInfo.otherSharedDirty;
1559
1560 final int nativePrivate = memInfo.nativePrivateDirty;
1561 final int dalvikPrivate = memInfo.dalvikPrivateDirty;
1562 final int otherPrivate = memInfo.otherPrivateDirty;
1563
1564 Runtime runtime = Runtime.getRuntime();
1565
1566 long dalvikMax = runtime.totalMemory() / 1024;
1567 long dalvikFree = runtime.freeMemory() / 1024;
1568 long dalvikAllocated = dalvikMax - dalvikFree;
1569 long viewInstanceCount = ViewDebug.getViewInstanceCount();
1570 long viewRootInstanceCount = ViewDebug.getViewRootInstanceCount();
1571 long appContextInstanceCount = ApplicationContext.getInstanceCount();
1572 long activityInstanceCount = Activity.getInstanceCount();
1573 int globalAssetCount = AssetManager.getGlobalAssetCount();
1574 int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
1575 int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
1576 int binderProxyObjectCount = Debug.getBinderProxyObjectCount();
1577 int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
1578 int openSslSocketCount = OpenSSLSocketImpl.getInstanceCount();
1579 long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
1580 SQLiteDebug.PagerStats stats = new SQLiteDebug.PagerStats();
1581 SQLiteDebug.getPagerStats(stats);
1582
1583 // Check to see if we were called by checkin server. If so, print terse format.
1584 boolean doCheckinFormat = false;
1585 if (args != null) {
1586 for (String arg : args) {
1587 if ("-c".equals(arg)) doCheckinFormat = true;
1588 }
1589 }
1590
1591 // For checkin, we print one long comma-separated list of values
1592 if (doCheckinFormat) {
1593 // NOTE: if you change anything significant below, also consider changing
1594 // ACTIVITY_THREAD_CHECKIN_VERSION.
1595 String processName = (mBoundApplication != null)
1596 ? mBoundApplication.processName : "unknown";
1597
1598 // Header
1599 pw.print(ACTIVITY_THREAD_CHECKIN_VERSION); pw.print(',');
1600 pw.print(Process.myPid()); pw.print(',');
1601 pw.print(processName); pw.print(',');
1602
1603 // Heap info - max
1604 pw.print(nativeMax); pw.print(',');
1605 pw.print(dalvikMax); pw.print(',');
1606 pw.print("N/A,");
1607 pw.print(nativeMax + dalvikMax); pw.print(',');
1608
1609 // Heap info - allocated
1610 pw.print(nativeAllocated); pw.print(',');
1611 pw.print(dalvikAllocated); pw.print(',');
1612 pw.print("N/A,");
1613 pw.print(nativeAllocated + dalvikAllocated); pw.print(',');
1614
1615 // Heap info - free
1616 pw.print(nativeFree); pw.print(',');
1617 pw.print(dalvikFree); pw.print(',');
1618 pw.print("N/A,");
1619 pw.print(nativeFree + dalvikFree); pw.print(',');
1620
1621 // Heap info - proportional set size
1622 pw.print(memInfo.nativePss); pw.print(',');
1623 pw.print(memInfo.dalvikPss); pw.print(',');
1624 pw.print(memInfo.otherPss); pw.print(',');
1625 pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
1626
1627 // Heap info - shared
1628 pw.print(nativeShared); pw.print(',');
1629 pw.print(dalvikShared); pw.print(',');
1630 pw.print(otherShared); pw.print(',');
1631 pw.print(nativeShared + dalvikShared + otherShared); pw.print(',');
1632
1633 // Heap info - private
1634 pw.print(nativePrivate); pw.print(',');
1635 pw.print(dalvikPrivate); pw.print(',');
1636 pw.print(otherPrivate); pw.print(',');
1637 pw.print(nativePrivate + dalvikPrivate + otherPrivate); pw.print(',');
1638
1639 // Object counts
1640 pw.print(viewInstanceCount); pw.print(',');
1641 pw.print(viewRootInstanceCount); pw.print(',');
1642 pw.print(appContextInstanceCount); pw.print(',');
1643 pw.print(activityInstanceCount); pw.print(',');
1644
1645 pw.print(globalAssetCount); pw.print(',');
1646 pw.print(globalAssetManagerCount); pw.print(',');
1647 pw.print(binderLocalObjectCount); pw.print(',');
1648 pw.print(binderProxyObjectCount); pw.print(',');
1649
1650 pw.print(binderDeathObjectCount); pw.print(',');
1651 pw.print(openSslSocketCount); pw.print(',');
1652
1653 // SQL
1654 pw.print(sqliteAllocated); pw.print(',');
1655 pw.print(stats.databaseBytes / 1024); pw.print(',');
1656 pw.print(stats.numPagers); pw.print(',');
1657 pw.print((stats.totalBytes - stats.referencedBytes) / 1024); pw.print(',');
1658 pw.print(stats.referencedBytes / 1024); pw.print('\n');
1659
1660 return;
1661 }
1662
1663 // otherwise, show human-readable format
1664 printRow(pw, HEAP_COLUMN, "", "native", "dalvik", "other", "total");
1665 printRow(pw, HEAP_COLUMN, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
1666 printRow(pw, HEAP_COLUMN, "allocated:", nativeAllocated, dalvikAllocated, "N/A",
1667 nativeAllocated + dalvikAllocated);
1668 printRow(pw, HEAP_COLUMN, "free:", nativeFree, dalvikFree, "N/A",
1669 nativeFree + dalvikFree);
1670
1671 printRow(pw, HEAP_COLUMN, "(Pss):", memInfo.nativePss, memInfo.dalvikPss,
1672 memInfo.otherPss, memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss);
1673
1674 printRow(pw, HEAP_COLUMN, "(shared dirty):", nativeShared, dalvikShared, otherShared,
1675 nativeShared + dalvikShared + otherShared);
1676 printRow(pw, HEAP_COLUMN, "(priv dirty):", nativePrivate, dalvikPrivate, otherPrivate,
1677 nativePrivate + dalvikPrivate + otherPrivate);
1678
1679 pw.println(" ");
1680 pw.println(" Objects");
1681 printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRoots:",
1682 viewRootInstanceCount);
1683
1684 printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount,
1685 "Activities:", activityInstanceCount);
1686
1687 printRow(pw, TWO_COUNT_COLUMNS, "Assets:", globalAssetCount,
1688 "AssetManagers:", globalAssetManagerCount);
1689
1690 printRow(pw, TWO_COUNT_COLUMNS, "Local Binders:", binderLocalObjectCount,
1691 "Proxy Binders:", binderProxyObjectCount);
1692 printRow(pw, ONE_COUNT_COLUMN, "Death Recipients:", binderDeathObjectCount);
1693
1694 printRow(pw, ONE_COUNT_COLUMN, "OpenSSL Sockets:", openSslSocketCount);
1695
1696 // SQLite mem info
1697 pw.println(" ");
1698 pw.println(" SQL");
1699 printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "dbFiles:",
1700 stats.databaseBytes / 1024);
1701 printRow(pw, TWO_COUNT_COLUMNS, "numPagers:", stats.numPagers, "inactivePageKB:",
1702 (stats.totalBytes - stats.referencedBytes) / 1024);
1703 printRow(pw, ONE_COUNT_COLUMN, "activePageKB:", stats.referencedBytes / 1024);
1704 }
1705
1706 private void printRow(PrintWriter pw, String format, Object...objs) {
1707 pw.println(String.format(format, objs));
1708 }
1709 }
1710
1711 private final class H extends Handler {
1712 public static final int LAUNCH_ACTIVITY = 100;
1713 public static final int PAUSE_ACTIVITY = 101;
1714 public static final int PAUSE_ACTIVITY_FINISHING= 102;
1715 public static final int STOP_ACTIVITY_SHOW = 103;
1716 public static final int STOP_ACTIVITY_HIDE = 104;
1717 public static final int SHOW_WINDOW = 105;
1718 public static final int HIDE_WINDOW = 106;
1719 public static final int RESUME_ACTIVITY = 107;
1720 public static final int SEND_RESULT = 108;
1721 public static final int DESTROY_ACTIVITY = 109;
1722 public static final int BIND_APPLICATION = 110;
1723 public static final int EXIT_APPLICATION = 111;
1724 public static final int NEW_INTENT = 112;
1725 public static final int RECEIVER = 113;
1726 public static final int CREATE_SERVICE = 114;
1727 public static final int SERVICE_ARGS = 115;
1728 public static final int STOP_SERVICE = 116;
1729 public static final int REQUEST_THUMBNAIL = 117;
1730 public static final int CONFIGURATION_CHANGED = 118;
1731 public static final int CLEAN_UP_CONTEXT = 119;
1732 public static final int GC_WHEN_IDLE = 120;
1733 public static final int BIND_SERVICE = 121;
1734 public static final int UNBIND_SERVICE = 122;
1735 public static final int DUMP_SERVICE = 123;
1736 public static final int LOW_MEMORY = 124;
1737 public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
1738 public static final int RELAUNCH_ACTIVITY = 126;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08001739 public static final int PROFILER_CONTROL = 127;
Christopher Tate181fafa2009-05-14 11:12:14 -07001740 public static final int CREATE_BACKUP_AGENT = 128;
1741 public static final int DESTROY_BACKUP_AGENT = 129;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 String codeToString(int code) {
1743 if (localLOGV) {
1744 switch (code) {
1745 case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
1746 case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY";
1747 case PAUSE_ACTIVITY_FINISHING: return "PAUSE_ACTIVITY_FINISHING";
1748 case STOP_ACTIVITY_SHOW: return "STOP_ACTIVITY_SHOW";
1749 case STOP_ACTIVITY_HIDE: return "STOP_ACTIVITY_HIDE";
1750 case SHOW_WINDOW: return "SHOW_WINDOW";
1751 case HIDE_WINDOW: return "HIDE_WINDOW";
1752 case RESUME_ACTIVITY: return "RESUME_ACTIVITY";
1753 case SEND_RESULT: return "SEND_RESULT";
1754 case DESTROY_ACTIVITY: return "DESTROY_ACTIVITY";
1755 case BIND_APPLICATION: return "BIND_APPLICATION";
1756 case EXIT_APPLICATION: return "EXIT_APPLICATION";
1757 case NEW_INTENT: return "NEW_INTENT";
1758 case RECEIVER: return "RECEIVER";
1759 case CREATE_SERVICE: return "CREATE_SERVICE";
1760 case SERVICE_ARGS: return "SERVICE_ARGS";
1761 case STOP_SERVICE: return "STOP_SERVICE";
1762 case REQUEST_THUMBNAIL: return "REQUEST_THUMBNAIL";
1763 case CONFIGURATION_CHANGED: return "CONFIGURATION_CHANGED";
1764 case CLEAN_UP_CONTEXT: return "CLEAN_UP_CONTEXT";
1765 case GC_WHEN_IDLE: return "GC_WHEN_IDLE";
1766 case BIND_SERVICE: return "BIND_SERVICE";
1767 case UNBIND_SERVICE: return "UNBIND_SERVICE";
1768 case DUMP_SERVICE: return "DUMP_SERVICE";
1769 case LOW_MEMORY: return "LOW_MEMORY";
1770 case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED";
1771 case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08001772 case PROFILER_CONTROL: return "PROFILER_CONTROL";
Christopher Tate181fafa2009-05-14 11:12:14 -07001773 case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
1774 case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 }
1776 }
1777 return "(unknown)";
1778 }
1779 public void handleMessage(Message msg) {
1780 switch (msg.what) {
1781 case LAUNCH_ACTIVITY: {
1782 ActivityRecord r = (ActivityRecord)msg.obj;
1783
1784 r.packageInfo = getPackageInfoNoCheck(
1785 r.activityInfo.applicationInfo);
Christopher Tateb70f3df2009-04-07 16:07:59 -07001786 handleLaunchActivity(r, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 } break;
1788 case RELAUNCH_ACTIVITY: {
1789 ActivityRecord r = (ActivityRecord)msg.obj;
1790 handleRelaunchActivity(r, msg.arg1);
1791 } break;
1792 case PAUSE_ACTIVITY:
1793 handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
1794 break;
1795 case PAUSE_ACTIVITY_FINISHING:
1796 handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
1797 break;
1798 case STOP_ACTIVITY_SHOW:
1799 handleStopActivity((IBinder)msg.obj, true, msg.arg2);
1800 break;
1801 case STOP_ACTIVITY_HIDE:
1802 handleStopActivity((IBinder)msg.obj, false, msg.arg2);
1803 break;
1804 case SHOW_WINDOW:
1805 handleWindowVisibility((IBinder)msg.obj, true);
1806 break;
1807 case HIDE_WINDOW:
1808 handleWindowVisibility((IBinder)msg.obj, false);
1809 break;
1810 case RESUME_ACTIVITY:
1811 handleResumeActivity((IBinder)msg.obj, true,
1812 msg.arg1 != 0);
1813 break;
1814 case SEND_RESULT:
1815 handleSendResult((ResultData)msg.obj);
1816 break;
1817 case DESTROY_ACTIVITY:
1818 handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
1819 msg.arg2, false);
1820 break;
1821 case BIND_APPLICATION:
1822 AppBindData data = (AppBindData)msg.obj;
1823 handleBindApplication(data);
1824 break;
1825 case EXIT_APPLICATION:
1826 if (mInitialApplication != null) {
1827 mInitialApplication.onTerminate();
1828 }
1829 Looper.myLooper().quit();
1830 break;
1831 case NEW_INTENT:
1832 handleNewIntent((NewIntentData)msg.obj);
1833 break;
1834 case RECEIVER:
1835 handleReceiver((ReceiverData)msg.obj);
1836 break;
1837 case CREATE_SERVICE:
1838 handleCreateService((CreateServiceData)msg.obj);
1839 break;
1840 case BIND_SERVICE:
1841 handleBindService((BindServiceData)msg.obj);
1842 break;
1843 case UNBIND_SERVICE:
1844 handleUnbindService((BindServiceData)msg.obj);
1845 break;
1846 case SERVICE_ARGS:
1847 handleServiceArgs((ServiceArgsData)msg.obj);
1848 break;
1849 case STOP_SERVICE:
1850 handleStopService((IBinder)msg.obj);
1851 break;
1852 case REQUEST_THUMBNAIL:
1853 handleRequestThumbnail((IBinder)msg.obj);
1854 break;
1855 case CONFIGURATION_CHANGED:
1856 handleConfigurationChanged((Configuration)msg.obj);
1857 break;
1858 case CLEAN_UP_CONTEXT:
1859 ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
1860 cci.context.performFinalCleanup(cci.who, cci.what);
1861 break;
1862 case GC_WHEN_IDLE:
1863 scheduleGcIdler();
1864 break;
1865 case DUMP_SERVICE:
1866 handleDumpService((DumpServiceInfo)msg.obj);
1867 break;
1868 case LOW_MEMORY:
1869 handleLowMemory();
1870 break;
1871 case ACTIVITY_CONFIGURATION_CHANGED:
1872 handleActivityConfigurationChanged((IBinder)msg.obj);
1873 break;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08001874 case PROFILER_CONTROL:
Dianne Hackborn9c8dd552009-06-23 19:22:52 -07001875 handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08001876 break;
Christopher Tate181fafa2009-05-14 11:12:14 -07001877 case CREATE_BACKUP_AGENT:
1878 handleCreateBackupAgent((CreateBackupAgentData)msg.obj);
1879 break;
1880 case DESTROY_BACKUP_AGENT:
1881 handleDestroyBackupAgent((CreateBackupAgentData)msg.obj);
1882 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 }
1884 }
1885 }
1886
1887 private final class Idler implements MessageQueue.IdleHandler {
1888 public final boolean queueIdle() {
1889 ActivityRecord a = mNewActivities;
1890 if (a != null) {
1891 mNewActivities = null;
1892 IActivityManager am = ActivityManagerNative.getDefault();
1893 ActivityRecord prev;
1894 do {
1895 if (localLOGV) Log.v(
1896 TAG, "Reporting idle of " + a +
1897 " finished=" +
1898 (a.activity != null ? a.activity.mFinished : false));
1899 if (a.activity != null && !a.activity.mFinished) {
1900 try {
1901 am.activityIdle(a.token);
1902 } catch (RemoteException ex) {
1903 }
1904 }
1905 prev = a;
1906 a = a.nextIdle;
1907 prev.nextIdle = null;
1908 } while (a != null);
1909 }
1910 return false;
1911 }
1912 }
1913
1914 final class GcIdler implements MessageQueue.IdleHandler {
1915 public final boolean queueIdle() {
1916 doGcIfNeeded();
1917 return false;
1918 }
1919 }
1920
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001921 private final static class ResourcesKey {
1922 final private String mResDir;
1923 final private float mScale;
1924 final private int mHash;
1925
1926 ResourcesKey(String resDir, float scale) {
1927 mResDir = resDir;
1928 mScale = scale;
1929 mHash = mResDir.hashCode() << 2 + (int) (mScale * 2);
1930 }
1931
1932 @Override
1933 public int hashCode() {
1934 return mHash;
1935 }
1936
1937 @Override
1938 public boolean equals(Object obj) {
1939 if (!(obj instanceof ResourcesKey)) {
1940 return false;
1941 }
1942 ResourcesKey peer = (ResourcesKey) obj;
1943 return mResDir.equals(peer.mResDir) && mScale == peer.mScale;
1944 }
1945 }
1946
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 static IPackageManager sPackageManager;
1948
1949 final ApplicationThread mAppThread = new ApplicationThread();
1950 final Looper mLooper = Looper.myLooper();
1951 final H mH = new H();
1952 final HashMap<IBinder, ActivityRecord> mActivities
1953 = new HashMap<IBinder, ActivityRecord>();
1954 // List of new activities (via ActivityRecord.nextIdle) that should
1955 // be reported when next we idle.
1956 ActivityRecord mNewActivities = null;
1957 // Number of activities that are currently visible on-screen.
1958 int mNumVisibleActivities = 0;
1959 final HashMap<IBinder, Service> mServices
1960 = new HashMap<IBinder, Service>();
1961 AppBindData mBoundApplication;
1962 Configuration mConfiguration;
1963 Application mInitialApplication;
1964 final ArrayList<Application> mAllApplications
1965 = new ArrayList<Application>();
Christopher Tate181fafa2009-05-14 11:12:14 -07001966 // set of instantiated backup agents, keyed by package name
1967 final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 static final ThreadLocal sThreadLocal = new ThreadLocal();
1969 Instrumentation mInstrumentation;
1970 String mInstrumentationAppDir = null;
1971 String mInstrumentationAppPackage = null;
1972 String mInstrumentedAppDir = null;
1973 boolean mSystemThread = false;
1974
1975 /**
1976 * Activities that are enqueued to be relaunched. This list is accessed
1977 * by multiple threads, so you must synchronize on it when accessing it.
1978 */
1979 final ArrayList<ActivityRecord> mRelaunchingActivities
1980 = new ArrayList<ActivityRecord>();
1981 Configuration mPendingConfiguration = null;
1982
1983 // These can be accessed by multiple threads; mPackages is the lock.
1984 // XXX For now we keep around information about all packages we have
1985 // seen, not removing entries from this map.
1986 final HashMap<String, WeakReference<PackageInfo>> mPackages
1987 = new HashMap<String, WeakReference<PackageInfo>>();
1988 final HashMap<String, WeakReference<PackageInfo>> mResourcePackages
1989 = new HashMap<String, WeakReference<PackageInfo>>();
1990 Display mDisplay = null;
1991 DisplayMetrics mDisplayMetrics = null;
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001992 HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
1993 = new HashMap<ResourcesKey, WeakReference<Resources> >();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994
1995 // The lock of mProviderMap protects the following variables.
1996 final HashMap<String, ProviderRecord> mProviderMap
1997 = new HashMap<String, ProviderRecord>();
1998 final HashMap<IBinder, ProviderRefCount> mProviderRefCountMap
1999 = new HashMap<IBinder, ProviderRefCount>();
2000 final HashMap<IBinder, ProviderRecord> mLocalProviders
2001 = new HashMap<IBinder, ProviderRecord>();
2002
2003 final GcIdler mGcIdler = new GcIdler();
2004 boolean mGcIdlerScheduled = false;
2005
2006 public final PackageInfo getPackageInfo(String packageName, int flags) {
2007 synchronized (mPackages) {
2008 WeakReference<PackageInfo> ref;
2009 if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) {
2010 ref = mPackages.get(packageName);
2011 } else {
2012 ref = mResourcePackages.get(packageName);
2013 }
2014 PackageInfo packageInfo = ref != null ? ref.get() : null;
2015 //Log.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo);
2016 if (packageInfo != null && (packageInfo.mResources == null
2017 || packageInfo.mResources.getAssets().isUpToDate())) {
2018 if (packageInfo.isSecurityViolation()
2019 && (flags&Context.CONTEXT_IGNORE_SECURITY) == 0) {
2020 throw new SecurityException(
2021 "Requesting code from " + packageName
2022 + " to be run in process "
2023 + mBoundApplication.processName
2024 + "/" + mBoundApplication.appInfo.uid);
2025 }
2026 return packageInfo;
2027 }
2028 }
2029
2030 ApplicationInfo ai = null;
2031 try {
2032 ai = getPackageManager().getApplicationInfo(packageName,
2033 PackageManager.GET_SHARED_LIBRARY_FILES);
2034 } catch (RemoteException e) {
2035 }
2036
2037 if (ai != null) {
2038 return getPackageInfo(ai, flags);
2039 }
2040
2041 return null;
2042 }
2043
2044 public final PackageInfo getPackageInfo(ApplicationInfo ai, int flags) {
2045 boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
2046 boolean securityViolation = includeCode && ai.uid != 0
2047 && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
2048 ? ai.uid != mBoundApplication.appInfo.uid : true);
2049 if ((flags&(Context.CONTEXT_INCLUDE_CODE
2050 |Context.CONTEXT_IGNORE_SECURITY))
2051 == Context.CONTEXT_INCLUDE_CODE) {
2052 if (securityViolation) {
2053 String msg = "Requesting code from " + ai.packageName
2054 + " (with uid " + ai.uid + ")";
2055 if (mBoundApplication != null) {
2056 msg = msg + " to be run in process "
2057 + mBoundApplication.processName + " (with uid "
2058 + mBoundApplication.appInfo.uid + ")";
2059 }
2060 throw new SecurityException(msg);
2061 }
2062 }
2063 return getPackageInfo(ai, null, securityViolation, includeCode);
2064 }
2065
2066 public final PackageInfo getPackageInfoNoCheck(ApplicationInfo ai) {
2067 return getPackageInfo(ai, null, false, true);
2068 }
2069
2070 private final PackageInfo getPackageInfo(ApplicationInfo aInfo,
2071 ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
2072 synchronized (mPackages) {
2073 WeakReference<PackageInfo> ref;
2074 if (includeCode) {
2075 ref = mPackages.get(aInfo.packageName);
2076 } else {
2077 ref = mResourcePackages.get(aInfo.packageName);
2078 }
2079 PackageInfo packageInfo = ref != null ? ref.get() : null;
2080 if (packageInfo == null || (packageInfo.mResources != null
2081 && !packageInfo.mResources.getAssets().isUpToDate())) {
2082 if (localLOGV) Log.v(TAG, (includeCode ? "Loading code package "
2083 : "Loading resource-only package ") + aInfo.packageName
2084 + " (in " + (mBoundApplication != null
2085 ? mBoundApplication.processName : null)
2086 + ")");
2087 packageInfo =
2088 new PackageInfo(this, aInfo, this, baseLoader,
2089 securityViolation, includeCode &&
2090 (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);
2091 if (includeCode) {
2092 mPackages.put(aInfo.packageName,
2093 new WeakReference<PackageInfo>(packageInfo));
2094 } else {
2095 mResourcePackages.put(aInfo.packageName,
2096 new WeakReference<PackageInfo>(packageInfo));
2097 }
2098 }
2099 return packageInfo;
2100 }
2101 }
2102
2103 public final boolean hasPackageInfo(String packageName) {
2104 synchronized (mPackages) {
2105 WeakReference<PackageInfo> ref;
2106 ref = mPackages.get(packageName);
2107 if (ref != null && ref.get() != null) {
2108 return true;
2109 }
2110 ref = mResourcePackages.get(packageName);
2111 if (ref != null && ref.get() != null) {
2112 return true;
2113 }
2114 return false;
2115 }
2116 }
2117
2118 ActivityThread() {
2119 }
2120
2121 public ApplicationThread getApplicationThread()
2122 {
2123 return mAppThread;
2124 }
2125
2126 public Instrumentation getInstrumentation()
2127 {
2128 return mInstrumentation;
2129 }
2130
2131 public Configuration getConfiguration() {
2132 return mConfiguration;
2133 }
2134
2135 public boolean isProfiling() {
2136 return mBoundApplication != null && mBoundApplication.profileFile != null;
2137 }
2138
2139 public String getProfileFilePath() {
2140 return mBoundApplication.profileFile;
2141 }
2142
2143 public Looper getLooper() {
2144 return mLooper;
2145 }
2146
2147 public Application getApplication() {
2148 return mInitialApplication;
2149 }
2150
Dianne Hackbornd97c7ad2009-06-19 11:37:35 -07002151 public String getProcessName() {
2152 return mBoundApplication.processName;
2153 }
2154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 public ApplicationContext getSystemContext() {
2156 synchronized (this) {
2157 if (mSystemContext == null) {
2158 ApplicationContext context =
2159 ApplicationContext.createSystemContext(this);
2160 PackageInfo info = new PackageInfo(this, "android", context);
2161 context.init(info, null, this);
2162 context.getResources().updateConfiguration(
2163 getConfiguration(), getDisplayMetricsLocked(false));
2164 mSystemContext = context;
2165 //Log.i(TAG, "Created system resources " + context.getResources()
2166 // + ": " + context.getResources().getConfiguration());
2167 }
2168 }
2169 return mSystemContext;
2170 }
2171
2172 void scheduleGcIdler() {
2173 if (!mGcIdlerScheduled) {
2174 mGcIdlerScheduled = true;
2175 Looper.myQueue().addIdleHandler(mGcIdler);
2176 }
2177 mH.removeMessages(H.GC_WHEN_IDLE);
2178 }
2179
2180 void unscheduleGcIdler() {
2181 if (mGcIdlerScheduled) {
2182 mGcIdlerScheduled = false;
2183 Looper.myQueue().removeIdleHandler(mGcIdler);
2184 }
2185 mH.removeMessages(H.GC_WHEN_IDLE);
2186 }
2187
2188 void doGcIfNeeded() {
2189 mGcIdlerScheduled = false;
2190 final long now = SystemClock.uptimeMillis();
2191 //Log.i(TAG, "**** WE MIGHT WANT TO GC: then=" + Binder.getLastGcTime()
2192 // + "m now=" + now);
2193 if ((BinderInternal.getLastGcTime()+MIN_TIME_BETWEEN_GCS) < now) {
2194 //Log.i(TAG, "**** WE DO, WE DO WANT TO GC!");
2195 BinderInternal.forceGc("bg");
2196 }
2197 }
2198
2199 public final ActivityInfo resolveActivityInfo(Intent intent) {
2200 ActivityInfo aInfo = intent.resolveActivityInfo(
2201 mInitialApplication.getPackageManager(), PackageManager.GET_SHARED_LIBRARY_FILES);
2202 if (aInfo == null) {
2203 // Throw an exception.
2204 Instrumentation.checkStartActivityResult(
2205 IActivityManager.START_CLASS_NOT_FOUND, intent);
2206 }
2207 return aInfo;
2208 }
2209
2210 public final Activity startActivityNow(Activity parent, String id,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
2212 Object lastNonConfigurationInstance) {
2213 ActivityRecord r = new ActivityRecord();
2214 r.token = token;
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002215 r.ident = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 r.intent = intent;
2217 r.state = state;
2218 r.parent = parent;
2219 r.embeddedID = id;
2220 r.activityInfo = activityInfo;
2221 r.lastNonConfigurationInstance = lastNonConfigurationInstance;
2222 if (localLOGV) {
2223 ComponentName compname = intent.getComponent();
2224 String name;
2225 if (compname != null) {
2226 name = compname.toShortString();
2227 } else {
2228 name = "(Intent " + intent + ").getComponent() returned null";
2229 }
2230 Log.v(TAG, "Performing launch: action=" + intent.getAction()
2231 + ", comp=" + name
2232 + ", token=" + token);
2233 }
Christopher Tateb70f3df2009-04-07 16:07:59 -07002234 return performLaunchActivity(r, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002235 }
2236
2237 public final Activity getActivity(IBinder token) {
2238 return mActivities.get(token).activity;
2239 }
2240
2241 public final void sendActivityResult(
2242 IBinder token, String id, int requestCode,
2243 int resultCode, Intent data) {
Chris Tate8a7dc172009-03-24 20:11:42 -07002244 if (DEBUG_RESULTS) Log.v(TAG, "sendActivityResult: id=" + id
2245 + " req=" + requestCode + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
2247 list.add(new ResultInfo(id, requestCode, resultCode, data));
2248 mAppThread.scheduleSendResult(token, list);
2249 }
2250
2251 // if the thread hasn't started yet, we don't have the handler, so just
2252 // save the messages until we're ready.
2253 private final void queueOrSendMessage(int what, Object obj) {
2254 queueOrSendMessage(what, obj, 0, 0);
2255 }
2256
2257 private final void queueOrSendMessage(int what, Object obj, int arg1) {
2258 queueOrSendMessage(what, obj, arg1, 0);
2259 }
2260
2261 private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
2262 synchronized (this) {
2263 if (localLOGV) Log.v(
2264 TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
2265 + ": " + arg1 + " / " + obj);
2266 Message msg = Message.obtain();
2267 msg.what = what;
2268 msg.obj = obj;
2269 msg.arg1 = arg1;
2270 msg.arg2 = arg2;
2271 mH.sendMessage(msg);
2272 }
2273 }
2274
2275 final void scheduleContextCleanup(ApplicationContext context, String who,
2276 String what) {
2277 ContextCleanupInfo cci = new ContextCleanupInfo();
2278 cci.context = context;
2279 cci.who = who;
2280 cci.what = what;
2281 queueOrSendMessage(H.CLEAN_UP_CONTEXT, cci);
2282 }
2283
Christopher Tateb70f3df2009-04-07 16:07:59 -07002284 private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002285 // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
2286
2287 ActivityInfo aInfo = r.activityInfo;
2288 if (r.packageInfo == null) {
2289 r.packageInfo = getPackageInfo(aInfo.applicationInfo,
2290 Context.CONTEXT_INCLUDE_CODE);
2291 }
2292
2293 ComponentName component = r.intent.getComponent();
2294 if (component == null) {
2295 component = r.intent.resolveActivity(
2296 mInitialApplication.getPackageManager());
2297 r.intent.setComponent(component);
2298 }
2299
2300 if (r.activityInfo.targetActivity != null) {
2301 component = new ComponentName(r.activityInfo.packageName,
2302 r.activityInfo.targetActivity);
2303 }
2304
2305 Activity activity = null;
2306 try {
2307 java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
2308 activity = mInstrumentation.newActivity(
2309 cl, component.getClassName(), r.intent);
2310 r.intent.setExtrasClassLoader(cl);
2311 if (r.state != null) {
2312 r.state.setClassLoader(cl);
2313 }
2314 } catch (Exception e) {
2315 if (!mInstrumentation.onException(activity, e)) {
2316 throw new RuntimeException(
2317 "Unable to instantiate activity " + component
2318 + ": " + e.toString(), e);
2319 }
2320 }
2321
2322 try {
Christopher Tate181fafa2009-05-14 11:12:14 -07002323 Application app = r.packageInfo.makeApplication(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324
2325 if (localLOGV) Log.v(TAG, "Performing launch of " + r);
2326 if (localLOGV) Log.v(
2327 TAG, r + ": app=" + app
2328 + ", appName=" + app.getPackageName()
2329 + ", pkg=" + r.packageInfo.getPackageName()
2330 + ", comp=" + r.intent.getComponent().toShortString()
2331 + ", dir=" + r.packageInfo.getAppDir());
2332
2333 if (activity != null) {
2334 ApplicationContext appContext = new ApplicationContext();
2335 appContext.init(r.packageInfo, r.token, this);
2336 appContext.setOuterContext(activity);
2337 CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
2338 Configuration config = new Configuration(mConfiguration);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002339 activity.attach(appContext, this, getInstrumentation(), r.token,
2340 r.ident, app, r.intent, r.activityInfo, title, r.parent,
2341 r.embeddedID, r.lastNonConfigurationInstance,
2342 r.lastNonConfigurationChildInstances, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002343
Christopher Tateb70f3df2009-04-07 16:07:59 -07002344 if (customIntent != null) {
2345 activity.mIntent = customIntent;
2346 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002347 r.lastNonConfigurationInstance = null;
2348 r.lastNonConfigurationChildInstances = null;
2349 activity.mStartedActivity = false;
2350 int theme = r.activityInfo.getThemeResource();
2351 if (theme != 0) {
2352 activity.setTheme(theme);
2353 }
2354
2355 activity.mCalled = false;
2356 mInstrumentation.callActivityOnCreate(activity, r.state);
2357 if (!activity.mCalled) {
2358 throw new SuperNotCalledException(
2359 "Activity " + r.intent.getComponent().toShortString() +
2360 " did not call through to super.onCreate()");
2361 }
2362 r.activity = activity;
2363 r.stopped = true;
2364 if (!r.activity.mFinished) {
2365 activity.performStart();
2366 r.stopped = false;
2367 }
2368 if (!r.activity.mFinished) {
2369 if (r.state != null) {
2370 mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
2371 }
2372 }
2373 if (!r.activity.mFinished) {
2374 activity.mCalled = false;
2375 mInstrumentation.callActivityOnPostCreate(activity, r.state);
2376 if (!activity.mCalled) {
2377 throw new SuperNotCalledException(
2378 "Activity " + r.intent.getComponent().toShortString() +
2379 " did not call through to super.onPostCreate()");
2380 }
2381 }
2382 r.state = null;
2383 }
2384 r.paused = true;
2385
2386 mActivities.put(r.token, r);
2387
2388 } catch (SuperNotCalledException e) {
2389 throw e;
2390
2391 } catch (Exception e) {
2392 if (!mInstrumentation.onException(activity, e)) {
2393 throw new RuntimeException(
2394 "Unable to start activity " + component
2395 + ": " + e.toString(), e);
2396 }
2397 }
2398
2399 return activity;
2400 }
2401
Christopher Tateb70f3df2009-04-07 16:07:59 -07002402 private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002403 // If we are getting ready to gc after going to the background, well
2404 // we are back active so skip it.
2405 unscheduleGcIdler();
2406
2407 if (localLOGV) Log.v(
2408 TAG, "Handling launch of " + r);
Christopher Tateb70f3df2009-04-07 16:07:59 -07002409 Activity a = performLaunchActivity(r, customIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002410
2411 if (a != null) {
2412 handleResumeActivity(r.token, false, r.isForward);
2413
2414 if (!r.activity.mFinished && r.startsNotResumed) {
2415 // The activity manager actually wants this one to start out
2416 // paused, because it needs to be visible but isn't in the
2417 // foreground. We accomplish this by going through the
2418 // normal startup (because activities expect to go through
2419 // onResume() the first time they run, before their window
2420 // is displayed), and then pausing it. However, in this case
2421 // we do -not- need to do the full pause cycle (of freezing
2422 // and such) because the activity manager assumes it can just
2423 // retain the current state it has.
2424 try {
2425 r.activity.mCalled = false;
2426 mInstrumentation.callActivityOnPause(r.activity);
2427 if (!r.activity.mCalled) {
2428 throw new SuperNotCalledException(
2429 "Activity " + r.intent.getComponent().toShortString() +
2430 " did not call through to super.onPause()");
2431 }
2432
2433 } catch (SuperNotCalledException e) {
2434 throw e;
2435
2436 } catch (Exception e) {
2437 if (!mInstrumentation.onException(r.activity, e)) {
2438 throw new RuntimeException(
2439 "Unable to pause activity "
2440 + r.intent.getComponent().toShortString()
2441 + ": " + e.toString(), e);
2442 }
2443 }
2444 r.paused = true;
2445 }
2446 } else {
2447 // If there was an error, for any reason, tell the activity
2448 // manager to stop us.
2449 try {
2450 ActivityManagerNative.getDefault()
2451 .finishActivity(r.token, Activity.RESULT_CANCELED, null);
2452 } catch (RemoteException ex) {
2453 }
2454 }
2455 }
2456
2457 private final void deliverNewIntents(ActivityRecord r,
2458 List<Intent> intents) {
2459 final int N = intents.size();
2460 for (int i=0; i<N; i++) {
2461 Intent intent = intents.get(i);
2462 intent.setExtrasClassLoader(r.activity.getClassLoader());
2463 mInstrumentation.callActivityOnNewIntent(r.activity, intent);
2464 }
2465 }
2466
2467 public final void performNewIntents(IBinder token,
2468 List<Intent> intents) {
2469 ActivityRecord r = mActivities.get(token);
2470 if (r != null) {
2471 final boolean resumed = !r.paused;
2472 if (resumed) {
2473 mInstrumentation.callActivityOnPause(r.activity);
2474 }
2475 deliverNewIntents(r, intents);
2476 if (resumed) {
2477 mInstrumentation.callActivityOnResume(r.activity);
2478 }
2479 }
2480 }
2481
2482 private final void handleNewIntent(NewIntentData data) {
2483 performNewIntents(data.token, data.intents);
2484 }
2485
2486 private final void handleReceiver(ReceiverData data) {
2487 // If we are getting ready to gc after going to the background, well
2488 // we are back active so skip it.
2489 unscheduleGcIdler();
2490
2491 String component = data.intent.getComponent().getClassName();
2492
2493 PackageInfo packageInfo = getPackageInfoNoCheck(
2494 data.info.applicationInfo);
2495
2496 IActivityManager mgr = ActivityManagerNative.getDefault();
2497
2498 BroadcastReceiver receiver = null;
2499 try {
2500 java.lang.ClassLoader cl = packageInfo.getClassLoader();
2501 data.intent.setExtrasClassLoader(cl);
2502 if (data.resultExtras != null) {
2503 data.resultExtras.setClassLoader(cl);
2504 }
2505 receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
2506 } catch (Exception e) {
2507 try {
2508 mgr.finishReceiver(mAppThread.asBinder(), data.resultCode,
2509 data.resultData, data.resultExtras, data.resultAbort);
2510 } catch (RemoteException ex) {
2511 }
2512 throw new RuntimeException(
2513 "Unable to instantiate receiver " + component
2514 + ": " + e.toString(), e);
2515 }
2516
2517 try {
Christopher Tate181fafa2009-05-14 11:12:14 -07002518 Application app = packageInfo.makeApplication(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002519
2520 if (localLOGV) Log.v(
2521 TAG, "Performing receive of " + data.intent
2522 + ": app=" + app
2523 + ", appName=" + app.getPackageName()
2524 + ", pkg=" + packageInfo.getPackageName()
2525 + ", comp=" + data.intent.getComponent().toShortString()
2526 + ", dir=" + packageInfo.getAppDir());
2527
2528 ApplicationContext context = (ApplicationContext)app.getBaseContext();
2529 receiver.setOrderedHint(true);
2530 receiver.setResult(data.resultCode, data.resultData,
2531 data.resultExtras);
2532 receiver.setOrderedHint(data.sync);
2533 receiver.onReceive(context.getReceiverRestrictedContext(),
2534 data.intent);
2535 } catch (Exception e) {
2536 try {
2537 mgr.finishReceiver(mAppThread.asBinder(), data.resultCode,
2538 data.resultData, data.resultExtras, data.resultAbort);
2539 } catch (RemoteException ex) {
2540 }
2541 if (!mInstrumentation.onException(receiver, e)) {
2542 throw new RuntimeException(
2543 "Unable to start receiver " + component
2544 + ": " + e.toString(), e);
2545 }
2546 }
2547
2548 try {
2549 if (data.sync) {
2550 mgr.finishReceiver(
2551 mAppThread.asBinder(), receiver.getResultCode(),
2552 receiver.getResultData(), receiver.getResultExtras(false),
2553 receiver.getAbortBroadcast());
2554 } else {
2555 mgr.finishReceiver(mAppThread.asBinder(), 0, null, null, false);
2556 }
2557 } catch (RemoteException ex) {
2558 }
2559 }
2560
Christopher Tate181fafa2009-05-14 11:12:14 -07002561 // Instantiate a BackupAgent and tell it that it's alive
2562 private final void handleCreateBackupAgent(CreateBackupAgentData data) {
2563 if (DEBUG_BACKUP) Log.v(TAG, "handleCreateBackupAgent: " + data);
2564
2565 // no longer idle; we have backup work to do
2566 unscheduleGcIdler();
2567
2568 // instantiate the BackupAgent class named in the manifest
2569 PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo);
2570 String packageName = packageInfo.mPackageName;
2571 if (mBackupAgents.get(packageName) != null) {
2572 Log.d(TAG, "BackupAgent " + " for " + packageName
2573 + " already exists");
2574 return;
2575 }
2576
2577 BackupAgent agent = null;
2578 String classname = data.appInfo.backupAgentName;
2579 if (classname == null) {
2580 if (data.backupMode == IApplicationThread.BACKUP_MODE_INCREMENTAL) {
2581 Log.e(TAG, "Attempted incremental backup but no defined agent for "
2582 + packageName);
2583 return;
2584 }
2585 classname = "android.app.FullBackupAgent";
2586 }
2587 try {
Christopher Tated1475e02009-07-09 15:36:17 -07002588 IBinder binder = null;
2589 try {
2590 java.lang.ClassLoader cl = packageInfo.getClassLoader();
2591 agent = (BackupAgent) cl.loadClass(data.appInfo.backupAgentName).newInstance();
2592
2593 // set up the agent's context
2594 if (DEBUG_BACKUP) Log.v(TAG, "Initializing BackupAgent "
2595 + data.appInfo.backupAgentName);
2596
2597 ApplicationContext context = new ApplicationContext();
2598 context.init(packageInfo, null, this);
2599 context.setOuterContext(agent);
2600 agent.attach(context);
2601
2602 agent.onCreate();
2603 binder = agent.onBind();
2604 mBackupAgents.put(packageName, agent);
2605 } catch (Exception e) {
2606 // If this is during restore, fail silently; otherwise go
2607 // ahead and let the user see the crash.
2608 Log.e(TAG, "Agent threw during creation: " + e);
2609 if (data.backupMode != IApplicationThread.BACKUP_MODE_RESTORE) {
2610 throw e;
2611 }
2612 // falling through with 'binder' still null
2613 }
Christopher Tate181fafa2009-05-14 11:12:14 -07002614
2615 // tell the OS that we're live now
Christopher Tate181fafa2009-05-14 11:12:14 -07002616 try {
2617 ActivityManagerNative.getDefault().backupAgentCreated(packageName, binder);
2618 } catch (RemoteException e) {
2619 // nothing to do.
2620 }
Christopher Tate181fafa2009-05-14 11:12:14 -07002621 } catch (Exception e) {
2622 throw new RuntimeException("Unable to create BackupAgent "
2623 + data.appInfo.backupAgentName + ": " + e.toString(), e);
2624 }
2625 }
2626
2627 // Tear down a BackupAgent
2628 private final void handleDestroyBackupAgent(CreateBackupAgentData data) {
2629 if (DEBUG_BACKUP) Log.v(TAG, "handleDestroyBackupAgent: " + data);
2630
2631 PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo);
2632 String packageName = packageInfo.mPackageName;
2633 BackupAgent agent = mBackupAgents.get(packageName);
2634 if (agent != null) {
2635 try {
2636 agent.onDestroy();
2637 } catch (Exception e) {
2638 Log.w(TAG, "Exception thrown in onDestroy by backup agent of " + data.appInfo);
2639 e.printStackTrace();
2640 }
2641 mBackupAgents.remove(packageName);
2642 } else {
2643 Log.w(TAG, "Attempt to destroy unknown backup agent " + data);
2644 }
2645 }
2646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 private final void handleCreateService(CreateServiceData data) {
2648 // If we are getting ready to gc after going to the background, well
2649 // we are back active so skip it.
2650 unscheduleGcIdler();
2651
2652 PackageInfo packageInfo = getPackageInfoNoCheck(
2653 data.info.applicationInfo);
2654 Service service = null;
2655 try {
2656 java.lang.ClassLoader cl = packageInfo.getClassLoader();
2657 service = (Service) cl.loadClass(data.info.name).newInstance();
2658 } catch (Exception e) {
2659 if (!mInstrumentation.onException(service, e)) {
2660 throw new RuntimeException(
2661 "Unable to instantiate service " + data.info.name
2662 + ": " + e.toString(), e);
2663 }
2664 }
2665
2666 try {
2667 if (localLOGV) Log.v(TAG, "Creating service " + data.info.name);
2668
2669 ApplicationContext context = new ApplicationContext();
2670 context.init(packageInfo, null, this);
2671
Christopher Tate181fafa2009-05-14 11:12:14 -07002672 Application app = packageInfo.makeApplication(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002673 context.setOuterContext(service);
2674 service.attach(context, this, data.info.name, data.token, app,
2675 ActivityManagerNative.getDefault());
2676 service.onCreate();
2677 mServices.put(data.token, service);
2678 try {
2679 ActivityManagerNative.getDefault().serviceDoneExecuting(data.token);
2680 } catch (RemoteException e) {
2681 // nothing to do.
2682 }
2683 } catch (Exception e) {
2684 if (!mInstrumentation.onException(service, e)) {
2685 throw new RuntimeException(
2686 "Unable to create service " + data.info.name
2687 + ": " + e.toString(), e);
2688 }
2689 }
2690 }
2691
2692 private final void handleBindService(BindServiceData data) {
2693 Service s = mServices.get(data.token);
2694 if (s != null) {
2695 try {
2696 data.intent.setExtrasClassLoader(s.getClassLoader());
2697 try {
2698 if (!data.rebind) {
2699 IBinder binder = s.onBind(data.intent);
2700 ActivityManagerNative.getDefault().publishService(
2701 data.token, data.intent, binder);
2702 } else {
2703 s.onRebind(data.intent);
2704 ActivityManagerNative.getDefault().serviceDoneExecuting(
2705 data.token);
2706 }
2707 } catch (RemoteException ex) {
2708 }
2709 } catch (Exception e) {
2710 if (!mInstrumentation.onException(s, e)) {
2711 throw new RuntimeException(
2712 "Unable to bind to service " + s
2713 + " with " + data.intent + ": " + e.toString(), e);
2714 }
2715 }
2716 }
2717 }
2718
2719 private final void handleUnbindService(BindServiceData data) {
2720 Service s = mServices.get(data.token);
2721 if (s != null) {
2722 try {
2723 data.intent.setExtrasClassLoader(s.getClassLoader());
2724 boolean doRebind = s.onUnbind(data.intent);
2725 try {
2726 if (doRebind) {
2727 ActivityManagerNative.getDefault().unbindFinished(
2728 data.token, data.intent, doRebind);
2729 } else {
2730 ActivityManagerNative.getDefault().serviceDoneExecuting(
2731 data.token);
2732 }
2733 } catch (RemoteException ex) {
2734 }
2735 } catch (Exception e) {
2736 if (!mInstrumentation.onException(s, e)) {
2737 throw new RuntimeException(
2738 "Unable to unbind to service " + s
2739 + " with " + data.intent + ": " + e.toString(), e);
2740 }
2741 }
2742 }
2743 }
2744
2745 private void handleDumpService(DumpServiceInfo info) {
2746 try {
2747 Service s = mServices.get(info.service);
2748 if (s != null) {
2749 PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd));
2750 s.dump(info.fd, pw, info.args);
2751 pw.close();
2752 }
2753 } finally {
2754 synchronized (info) {
2755 info.dumped = true;
2756 info.notifyAll();
2757 }
2758 }
2759 }
2760
2761 private final void handleServiceArgs(ServiceArgsData data) {
2762 Service s = mServices.get(data.token);
2763 if (s != null) {
2764 try {
2765 if (data.args != null) {
2766 data.args.setExtrasClassLoader(s.getClassLoader());
2767 }
2768 s.onStart(data.args, data.startId);
2769 try {
2770 ActivityManagerNative.getDefault().serviceDoneExecuting(data.token);
2771 } catch (RemoteException e) {
2772 // nothing to do.
2773 }
2774 } catch (Exception e) {
2775 if (!mInstrumentation.onException(s, e)) {
2776 throw new RuntimeException(
2777 "Unable to start service " + s
2778 + " with " + data.args + ": " + e.toString(), e);
2779 }
2780 }
2781 }
2782 }
2783
2784 private final void handleStopService(IBinder token) {
2785 Service s = mServices.remove(token);
2786 if (s != null) {
2787 try {
2788 if (localLOGV) Log.v(TAG, "Destroying service " + s);
2789 s.onDestroy();
2790 Context context = s.getBaseContext();
2791 if (context instanceof ApplicationContext) {
2792 final String who = s.getClassName();
2793 ((ApplicationContext) context).scheduleFinalCleanup(who, "Service");
2794 }
2795 try {
2796 ActivityManagerNative.getDefault().serviceDoneExecuting(token);
2797 } catch (RemoteException e) {
2798 // nothing to do.
2799 }
2800 } catch (Exception e) {
2801 if (!mInstrumentation.onException(s, e)) {
2802 throw new RuntimeException(
2803 "Unable to stop service " + s
2804 + ": " + e.toString(), e);
2805 }
2806 }
2807 }
2808 //Log.i(TAG, "Running services: " + mServices);
2809 }
2810
2811 public final ActivityRecord performResumeActivity(IBinder token,
2812 boolean clearHide) {
2813 ActivityRecord r = mActivities.get(token);
2814 if (localLOGV) Log.v(TAG, "Performing resume of " + r
2815 + " finished=" + r.activity.mFinished);
2816 if (r != null && !r.activity.mFinished) {
2817 if (clearHide) {
2818 r.hideForNow = false;
2819 r.activity.mStartedActivity = false;
2820 }
2821 try {
2822 if (r.pendingIntents != null) {
2823 deliverNewIntents(r, r.pendingIntents);
2824 r.pendingIntents = null;
2825 }
2826 if (r.pendingResults != null) {
2827 deliverResults(r, r.pendingResults);
2828 r.pendingResults = null;
2829 }
2830 r.activity.performResume();
2831
2832 EventLog.writeEvent(LOG_ON_RESUME_CALLED,
2833 r.activity.getComponentName().getClassName());
2834
2835 r.paused = false;
2836 r.stopped = false;
2837 if (r.activity.mStartedActivity) {
2838 r.hideForNow = true;
2839 }
2840 r.state = null;
2841 } catch (Exception e) {
2842 if (!mInstrumentation.onException(r.activity, e)) {
2843 throw new RuntimeException(
2844 "Unable to resume activity "
2845 + r.intent.getComponent().toShortString()
2846 + ": " + e.toString(), e);
2847 }
2848 }
2849 }
2850 return r;
2851 }
2852
2853 final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
2854 // If we are getting ready to gc after going to the background, well
2855 // we are back active so skip it.
2856 unscheduleGcIdler();
2857
2858 ActivityRecord r = performResumeActivity(token, clearHide);
2859
2860 if (r != null) {
2861 final Activity a = r.activity;
2862
2863 if (localLOGV) Log.v(
2864 TAG, "Resume " + r + " started activity: " +
2865 a.mStartedActivity + ", hideForNow: " + r.hideForNow
2866 + ", finished: " + a.mFinished);
2867
2868 final int forwardBit = isForward ?
2869 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
2870
2871 // If the window hasn't yet been added to the window manager,
2872 // and this guy didn't finish itself or start another activity,
2873 // then go ahead and add the window.
2874 if (r.window == null && !a.mFinished && !a.mStartedActivity) {
2875 r.window = r.activity.getWindow();
2876 View decor = r.window.getDecorView();
2877 decor.setVisibility(View.INVISIBLE);
2878 ViewManager wm = a.getWindowManager();
2879 WindowManager.LayoutParams l = r.window.getAttributes();
2880 a.mDecor = decor;
2881 l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
2882 l.softInputMode |= forwardBit;
2883 if (a.mVisibleFromClient) {
2884 a.mWindowAdded = true;
2885 wm.addView(decor, l);
2886 }
2887
2888 // If the window has already been added, but during resume
2889 // we started another activity, then don't yet make the
2890 // window visisble.
2891 } else if (a.mStartedActivity) {
2892 if (localLOGV) Log.v(
2893 TAG, "Launch " + r + " mStartedActivity set");
2894 r.hideForNow = true;
2895 }
2896
2897 // The window is now visible if it has been added, we are not
2898 // simply finishing, and we are not starting another activity.
2899 if (!r.activity.mFinished && r.activity.mDecor != null
2900 && !r.hideForNow) {
2901 if (r.newConfig != null) {
2902 performConfigurationChanged(r.activity, r.newConfig);
2903 r.newConfig = null;
2904 }
2905 if (localLOGV) Log.v(TAG, "Resuming " + r + " with isForward="
2906 + isForward);
2907 WindowManager.LayoutParams l = r.window.getAttributes();
2908 if ((l.softInputMode
2909 & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
2910 != forwardBit) {
2911 l.softInputMode = (l.softInputMode
2912 & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
2913 | forwardBit;
2914 ViewManager wm = a.getWindowManager();
2915 View decor = r.window.getDecorView();
2916 wm.updateViewLayout(decor, l);
2917 }
2918 r.activity.mVisibleFromServer = true;
2919 mNumVisibleActivities++;
2920 if (r.activity.mVisibleFromClient) {
2921 r.activity.makeVisible();
2922 }
2923 }
2924
2925 r.nextIdle = mNewActivities;
2926 mNewActivities = r;
2927 if (localLOGV) Log.v(
2928 TAG, "Scheduling idle handler for " + r);
2929 Looper.myQueue().addIdleHandler(new Idler());
2930
2931 } else {
2932 // If an exception was thrown when trying to resume, then
2933 // just end this activity.
2934 try {
2935 ActivityManagerNative.getDefault()
2936 .finishActivity(token, Activity.RESULT_CANCELED, null);
2937 } catch (RemoteException ex) {
2938 }
2939 }
2940 }
2941
2942 private int mThumbnailWidth = -1;
2943 private int mThumbnailHeight = -1;
2944
2945 private final Bitmap createThumbnailBitmap(ActivityRecord r) {
2946 Bitmap thumbnail = null;
2947 try {
2948 int w = mThumbnailWidth;
2949 int h;
2950 if (w < 0) {
2951 Resources res = r.activity.getResources();
2952 mThumbnailHeight = h =
2953 res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
2954
2955 mThumbnailWidth = w =
2956 res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
2957 } else {
2958 h = mThumbnailHeight;
2959 }
2960
2961 // XXX Only set hasAlpha if needed?
2962 thumbnail = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
2963 thumbnail.eraseColor(0);
2964 Canvas cv = new Canvas(thumbnail);
2965 if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
2966 thumbnail = null;
2967 }
2968 } catch (Exception e) {
2969 if (!mInstrumentation.onException(r.activity, e)) {
2970 throw new RuntimeException(
2971 "Unable to create thumbnail of "
2972 + r.intent.getComponent().toShortString()
2973 + ": " + e.toString(), e);
2974 }
2975 thumbnail = null;
2976 }
2977
2978 return thumbnail;
2979 }
2980
2981 private final void handlePauseActivity(IBinder token, boolean finished,
2982 boolean userLeaving, int configChanges) {
2983 ActivityRecord r = mActivities.get(token);
2984 if (r != null) {
2985 //Log.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
2986 if (userLeaving) {
2987 performUserLeavingActivity(r);
2988 }
2989
2990 r.activity.mConfigChangeFlags |= configChanges;
2991 Bundle state = performPauseActivity(token, finished, true);
2992
2993 // Tell the activity manager we have paused.
2994 try {
2995 ActivityManagerNative.getDefault().activityPaused(token, state);
2996 } catch (RemoteException ex) {
2997 }
2998 }
2999 }
3000
3001 final void performUserLeavingActivity(ActivityRecord r) {
3002 mInstrumentation.callActivityOnUserLeaving(r.activity);
3003 }
3004
3005 final Bundle performPauseActivity(IBinder token, boolean finished,
3006 boolean saveState) {
3007 ActivityRecord r = mActivities.get(token);
3008 return r != null ? performPauseActivity(r, finished, saveState) : null;
3009 }
3010
3011 final Bundle performPauseActivity(ActivityRecord r, boolean finished,
3012 boolean saveState) {
3013 if (r.paused) {
3014 if (r.activity.mFinished) {
3015 // If we are finishing, we won't call onResume() in certain cases.
3016 // So here we likewise don't want to call onPause() if the activity
3017 // isn't resumed.
3018 return null;
3019 }
3020 RuntimeException e = new RuntimeException(
3021 "Performing pause of activity that is not resumed: "
3022 + r.intent.getComponent().toShortString());
3023 Log.e(TAG, e.getMessage(), e);
3024 }
3025 Bundle state = null;
3026 if (finished) {
3027 r.activity.mFinished = true;
3028 }
3029 try {
3030 // Next have the activity save its current state and managed dialogs...
3031 if (!r.activity.mFinished && saveState) {
3032 state = new Bundle();
3033 mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
3034 r.state = state;
3035 }
3036 // Now we are idle.
3037 r.activity.mCalled = false;
3038 mInstrumentation.callActivityOnPause(r.activity);
3039 EventLog.writeEvent(LOG_ON_PAUSE_CALLED, r.activity.getComponentName().getClassName());
3040 if (!r.activity.mCalled) {
3041 throw new SuperNotCalledException(
3042 "Activity " + r.intent.getComponent().toShortString() +
3043 " did not call through to super.onPause()");
3044 }
3045
3046 } catch (SuperNotCalledException e) {
3047 throw e;
3048
3049 } catch (Exception e) {
3050 if (!mInstrumentation.onException(r.activity, e)) {
3051 throw new RuntimeException(
3052 "Unable to pause activity "
3053 + r.intent.getComponent().toShortString()
3054 + ": " + e.toString(), e);
3055 }
3056 }
3057 r.paused = true;
3058 return state;
3059 }
3060
3061 final void performStopActivity(IBinder token) {
3062 ActivityRecord r = mActivities.get(token);
3063 performStopActivityInner(r, null, false);
3064 }
3065
3066 private static class StopInfo {
3067 Bitmap thumbnail;
3068 CharSequence description;
3069 }
3070
3071 private final class ProviderRefCount {
3072 public int count;
3073 ProviderRefCount(int pCount) {
3074 count = pCount;
3075 }
3076 }
3077
3078 private final void performStopActivityInner(ActivityRecord r,
3079 StopInfo info, boolean keepShown) {
3080 if (localLOGV) Log.v(TAG, "Performing stop of " + r);
3081 if (r != null) {
3082 if (!keepShown && r.stopped) {
3083 if (r.activity.mFinished) {
3084 // If we are finishing, we won't call onResume() in certain
3085 // cases. So here we likewise don't want to call onStop()
3086 // if the activity isn't resumed.
3087 return;
3088 }
3089 RuntimeException e = new RuntimeException(
3090 "Performing stop of activity that is not resumed: "
3091 + r.intent.getComponent().toShortString());
3092 Log.e(TAG, e.getMessage(), e);
3093 }
3094
3095 if (info != null) {
3096 try {
3097 // First create a thumbnail for the activity...
3098 //info.thumbnail = createThumbnailBitmap(r);
3099 info.description = r.activity.onCreateDescription();
3100 } catch (Exception e) {
3101 if (!mInstrumentation.onException(r.activity, e)) {
3102 throw new RuntimeException(
3103 "Unable to save state of activity "
3104 + r.intent.getComponent().toShortString()
3105 + ": " + e.toString(), e);
3106 }
3107 }
3108 }
3109
3110 if (!keepShown) {
3111 try {
3112 // Now we are idle.
3113 r.activity.performStop();
3114 } catch (Exception e) {
3115 if (!mInstrumentation.onException(r.activity, e)) {
3116 throw new RuntimeException(
3117 "Unable to stop activity "
3118 + r.intent.getComponent().toShortString()
3119 + ": " + e.toString(), e);
3120 }
3121 }
3122 r.stopped = true;
3123 }
3124
3125 r.paused = true;
3126 }
3127 }
3128
3129 private final void updateVisibility(ActivityRecord r, boolean show) {
3130 View v = r.activity.mDecor;
3131 if (v != null) {
3132 if (show) {
3133 if (!r.activity.mVisibleFromServer) {
3134 r.activity.mVisibleFromServer = true;
3135 mNumVisibleActivities++;
3136 if (r.activity.mVisibleFromClient) {
3137 r.activity.makeVisible();
3138 }
3139 }
3140 if (r.newConfig != null) {
3141 performConfigurationChanged(r.activity, r.newConfig);
3142 r.newConfig = null;
3143 }
3144 } else {
3145 if (r.activity.mVisibleFromServer) {
3146 r.activity.mVisibleFromServer = false;
3147 mNumVisibleActivities--;
3148 v.setVisibility(View.INVISIBLE);
3149 }
3150 }
3151 }
3152 }
3153
3154 private final void handleStopActivity(IBinder token, boolean show, int configChanges) {
3155 ActivityRecord r = mActivities.get(token);
3156 r.activity.mConfigChangeFlags |= configChanges;
3157
3158 StopInfo info = new StopInfo();
3159 performStopActivityInner(r, info, show);
3160
3161 if (localLOGV) Log.v(
3162 TAG, "Finishing stop of " + r + ": show=" + show
3163 + " win=" + r.window);
3164
3165 updateVisibility(r, show);
3166
3167 // Tell activity manager we have been stopped.
3168 try {
3169 ActivityManagerNative.getDefault().activityStopped(
3170 r.token, info.thumbnail, info.description);
3171 } catch (RemoteException ex) {
3172 }
3173 }
3174
3175 final void performRestartActivity(IBinder token) {
3176 ActivityRecord r = mActivities.get(token);
3177 if (r.stopped) {
3178 r.activity.performRestart();
3179 r.stopped = false;
3180 }
3181 }
3182
3183 private final void handleWindowVisibility(IBinder token, boolean show) {
3184 ActivityRecord r = mActivities.get(token);
3185 if (!show && !r.stopped) {
3186 performStopActivityInner(r, null, show);
3187 } else if (show && r.stopped) {
3188 // If we are getting ready to gc after going to the background, well
3189 // we are back active so skip it.
3190 unscheduleGcIdler();
3191
3192 r.activity.performRestart();
3193 r.stopped = false;
3194 }
3195 if (r.activity.mDecor != null) {
3196 if (Config.LOGV) Log.v(
3197 TAG, "Handle window " + r + " visibility: " + show);
3198 updateVisibility(r, show);
3199 }
3200 }
3201
3202 private final void deliverResults(ActivityRecord r, List<ResultInfo> results) {
3203 final int N = results.size();
3204 for (int i=0; i<N; i++) {
3205 ResultInfo ri = results.get(i);
3206 try {
3207 if (ri.mData != null) {
3208 ri.mData.setExtrasClassLoader(r.activity.getClassLoader());
3209 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003210 if (DEBUG_RESULTS) Log.v(TAG,
3211 "Delivering result to activity " + r + " : " + ri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 r.activity.dispatchActivityResult(ri.mResultWho,
3213 ri.mRequestCode, ri.mResultCode, ri.mData);
3214 } catch (Exception e) {
3215 if (!mInstrumentation.onException(r.activity, e)) {
3216 throw new RuntimeException(
3217 "Failure delivering result " + ri + " to activity "
3218 + r.intent.getComponent().toShortString()
3219 + ": " + e.toString(), e);
3220 }
3221 }
3222 }
3223 }
3224
3225 private final void handleSendResult(ResultData res) {
3226 ActivityRecord r = mActivities.get(res.token);
Chris Tate8a7dc172009-03-24 20:11:42 -07003227 if (DEBUG_RESULTS) Log.v(TAG, "Handling send result to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003228 if (r != null) {
3229 final boolean resumed = !r.paused;
3230 if (!r.activity.mFinished && r.activity.mDecor != null
3231 && r.hideForNow && resumed) {
3232 // We had hidden the activity because it started another
3233 // one... we have gotten a result back and we are not
3234 // paused, so make sure our window is visible.
3235 updateVisibility(r, true);
3236 }
3237 if (resumed) {
3238 try {
3239 // Now we are idle.
3240 r.activity.mCalled = false;
3241 mInstrumentation.callActivityOnPause(r.activity);
3242 if (!r.activity.mCalled) {
3243 throw new SuperNotCalledException(
3244 "Activity " + r.intent.getComponent().toShortString()
3245 + " did not call through to super.onPause()");
3246 }
3247 } catch (SuperNotCalledException e) {
3248 throw e;
3249 } catch (Exception e) {
3250 if (!mInstrumentation.onException(r.activity, e)) {
3251 throw new RuntimeException(
3252 "Unable to pause activity "
3253 + r.intent.getComponent().toShortString()
3254 + ": " + e.toString(), e);
3255 }
3256 }
3257 }
3258 deliverResults(r, res.results);
3259 if (resumed) {
3260 mInstrumentation.callActivityOnResume(r.activity);
3261 }
3262 }
3263 }
3264
3265 public final ActivityRecord performDestroyActivity(IBinder token, boolean finishing) {
3266 return performDestroyActivity(token, finishing, 0, false);
3267 }
3268
3269 private final ActivityRecord performDestroyActivity(IBinder token, boolean finishing,
3270 int configChanges, boolean getNonConfigInstance) {
3271 ActivityRecord r = mActivities.get(token);
3272 if (localLOGV) Log.v(TAG, "Performing finish of " + r);
3273 if (r != null) {
3274 r.activity.mConfigChangeFlags |= configChanges;
3275 if (finishing) {
3276 r.activity.mFinished = true;
3277 }
3278 if (!r.paused) {
3279 try {
3280 r.activity.mCalled = false;
3281 mInstrumentation.callActivityOnPause(r.activity);
3282 EventLog.writeEvent(LOG_ON_PAUSE_CALLED,
3283 r.activity.getComponentName().getClassName());
3284 if (!r.activity.mCalled) {
3285 throw new SuperNotCalledException(
Mitsuru Oshimad9aef732009-06-16 20:20:50 -07003286 "Activity " + safeToComponentShortString(r.intent)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003287 + " did not call through to super.onPause()");
3288 }
3289 } catch (SuperNotCalledException e) {
3290 throw e;
3291 } catch (Exception e) {
3292 if (!mInstrumentation.onException(r.activity, e)) {
3293 throw new RuntimeException(
3294 "Unable to pause activity "
Mitsuru Oshimad9aef732009-06-16 20:20:50 -07003295 + safeToComponentShortString(r.intent)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 + ": " + e.toString(), e);
3297 }
3298 }
3299 r.paused = true;
3300 }
3301 if (!r.stopped) {
3302 try {
3303 r.activity.performStop();
3304 } catch (SuperNotCalledException e) {
3305 throw e;
3306 } catch (Exception e) {
3307 if (!mInstrumentation.onException(r.activity, e)) {
3308 throw new RuntimeException(
3309 "Unable to stop activity "
Mitsuru Oshimad9aef732009-06-16 20:20:50 -07003310 + safeToComponentShortString(r.intent)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003311 + ": " + e.toString(), e);
3312 }
3313 }
3314 r.stopped = true;
3315 }
3316 if (getNonConfigInstance) {
3317 try {
3318 r.lastNonConfigurationInstance
3319 = r.activity.onRetainNonConfigurationInstance();
3320 } catch (Exception e) {
3321 if (!mInstrumentation.onException(r.activity, e)) {
3322 throw new RuntimeException(
3323 "Unable to retain activity "
3324 + r.intent.getComponent().toShortString()
3325 + ": " + e.toString(), e);
3326 }
3327 }
3328 try {
3329 r.lastNonConfigurationChildInstances
3330 = r.activity.onRetainNonConfigurationChildInstances();
3331 } catch (Exception e) {
3332 if (!mInstrumentation.onException(r.activity, e)) {
3333 throw new RuntimeException(
3334 "Unable to retain child activities "
Mitsuru Oshimad9aef732009-06-16 20:20:50 -07003335 + safeToComponentShortString(r.intent)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 + ": " + e.toString(), e);
3337 }
3338 }
3339
3340 }
3341 try {
3342 r.activity.mCalled = false;
3343 r.activity.onDestroy();
3344 if (!r.activity.mCalled) {
3345 throw new SuperNotCalledException(
Mitsuru Oshimad9aef732009-06-16 20:20:50 -07003346 "Activity " + safeToComponentShortString(r.intent) +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 " did not call through to super.onDestroy()");
3348 }
3349 if (r.window != null) {
3350 r.window.closeAllPanels();
3351 }
3352 } catch (SuperNotCalledException e) {
3353 throw e;
3354 } catch (Exception e) {
3355 if (!mInstrumentation.onException(r.activity, e)) {
3356 throw new RuntimeException(
Mitsuru Oshimad9aef732009-06-16 20:20:50 -07003357 "Unable to destroy activity " + safeToComponentShortString(r.intent)
3358 + ": " + e.toString(), e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 }
3360 }
3361 }
3362 mActivities.remove(token);
3363
3364 return r;
3365 }
3366
Mitsuru Oshimad9aef732009-06-16 20:20:50 -07003367 private static String safeToComponentShortString(Intent intent) {
3368 ComponentName component = intent.getComponent();
3369 return component == null ? "[Unknown]" : component.toShortString();
3370 }
3371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003372 private final void handleDestroyActivity(IBinder token, boolean finishing,
3373 int configChanges, boolean getNonConfigInstance) {
3374 ActivityRecord r = performDestroyActivity(token, finishing,
3375 configChanges, getNonConfigInstance);
3376 if (r != null) {
3377 WindowManager wm = r.activity.getWindowManager();
3378 View v = r.activity.mDecor;
3379 if (v != null) {
3380 if (r.activity.mVisibleFromServer) {
3381 mNumVisibleActivities--;
3382 }
3383 IBinder wtoken = v.getWindowToken();
3384 if (r.activity.mWindowAdded) {
3385 wm.removeViewImmediate(v);
3386 }
3387 if (wtoken != null) {
3388 WindowManagerImpl.getDefault().closeAll(wtoken,
3389 r.activity.getClass().getName(), "Activity");
3390 }
3391 r.activity.mDecor = null;
3392 }
3393 WindowManagerImpl.getDefault().closeAll(token,
3394 r.activity.getClass().getName(), "Activity");
3395
3396 // Mocked out contexts won't be participating in the normal
3397 // process lifecycle, but if we're running with a proper
3398 // ApplicationContext we need to have it tear down things
3399 // cleanly.
3400 Context c = r.activity.getBaseContext();
3401 if (c instanceof ApplicationContext) {
3402 ((ApplicationContext) c).scheduleFinalCleanup(
3403 r.activity.getClass().getName(), "Activity");
3404 }
3405 }
3406 if (finishing) {
3407 try {
3408 ActivityManagerNative.getDefault().activityDestroyed(token);
3409 } catch (RemoteException ex) {
3410 // If the system process has died, it's game over for everyone.
3411 }
3412 }
3413 }
3414
3415 private final void handleRelaunchActivity(ActivityRecord tmp, int configChanges) {
3416 // If we are getting ready to gc after going to the background, well
3417 // we are back active so skip it.
3418 unscheduleGcIdler();
3419
3420 Configuration changedConfig = null;
3421
3422 // First: make sure we have the most recent configuration and most
3423 // recent version of the activity, or skip it if some previous call
3424 // had taken a more recent version.
3425 synchronized (mRelaunchingActivities) {
3426 int N = mRelaunchingActivities.size();
3427 IBinder token = tmp.token;
3428 tmp = null;
3429 for (int i=0; i<N; i++) {
3430 ActivityRecord r = mRelaunchingActivities.get(i);
3431 if (r.token == token) {
3432 tmp = r;
3433 mRelaunchingActivities.remove(i);
3434 i--;
3435 N--;
3436 }
3437 }
3438
3439 if (tmp == null) {
3440 return;
3441 }
3442
3443 if (mPendingConfiguration != null) {
3444 changedConfig = mPendingConfiguration;
3445 mPendingConfiguration = null;
3446 }
3447 }
3448
3449 // If there was a pending configuration change, execute it first.
3450 if (changedConfig != null) {
3451 handleConfigurationChanged(changedConfig);
3452 }
3453
3454 ActivityRecord r = mActivities.get(tmp.token);
3455 if (localLOGV) Log.v(TAG, "Handling relaunch of " + r);
3456 if (r == null) {
3457 return;
3458 }
3459
3460 r.activity.mConfigChangeFlags |= configChanges;
Christopher Tateb70f3df2009-04-07 16:07:59 -07003461 Intent currentIntent = r.activity.mIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462
3463 Bundle savedState = null;
3464 if (!r.paused) {
3465 savedState = performPauseActivity(r.token, false, true);
3466 }
3467
3468 handleDestroyActivity(r.token, false, configChanges, true);
3469
3470 r.activity = null;
3471 r.window = null;
3472 r.hideForNow = false;
3473 r.nextIdle = null;
The Android Open Source Project10592532009-03-18 17:39:46 -07003474 // Merge any pending results and pending intents; don't just replace them
3475 if (tmp.pendingResults != null) {
3476 if (r.pendingResults == null) {
3477 r.pendingResults = tmp.pendingResults;
3478 } else {
3479 r.pendingResults.addAll(tmp.pendingResults);
3480 }
3481 }
3482 if (tmp.pendingIntents != null) {
3483 if (r.pendingIntents == null) {
3484 r.pendingIntents = tmp.pendingIntents;
3485 } else {
3486 r.pendingIntents.addAll(tmp.pendingIntents);
3487 }
3488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 r.startsNotResumed = tmp.startsNotResumed;
3490 if (savedState != null) {
3491 r.state = savedState;
3492 }
3493
Christopher Tateb70f3df2009-04-07 16:07:59 -07003494 handleLaunchActivity(r, currentIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003495 }
3496
3497 private final void handleRequestThumbnail(IBinder token) {
3498 ActivityRecord r = mActivities.get(token);
3499 Bitmap thumbnail = createThumbnailBitmap(r);
3500 CharSequence description = null;
3501 try {
3502 description = r.activity.onCreateDescription();
3503 } catch (Exception e) {
3504 if (!mInstrumentation.onException(r.activity, e)) {
3505 throw new RuntimeException(
3506 "Unable to create description of activity "
3507 + r.intent.getComponent().toShortString()
3508 + ": " + e.toString(), e);
3509 }
3510 }
3511 //System.out.println("Reporting top thumbnail " + thumbnail);
3512 try {
3513 ActivityManagerNative.getDefault().reportThumbnail(
3514 token, thumbnail, description);
3515 } catch (RemoteException ex) {
3516 }
3517 }
3518
3519 ArrayList<ComponentCallbacks> collectComponentCallbacksLocked(
3520 boolean allActivities, Configuration newConfig) {
3521 ArrayList<ComponentCallbacks> callbacks
3522 = new ArrayList<ComponentCallbacks>();
3523
3524 if (mActivities.size() > 0) {
3525 Iterator<ActivityRecord> it = mActivities.values().iterator();
3526 while (it.hasNext()) {
3527 ActivityRecord ar = it.next();
3528 Activity a = ar.activity;
3529 if (a != null) {
3530 if (!ar.activity.mFinished && (allActivities ||
3531 (a != null && !ar.paused))) {
3532 // If the activity is currently resumed, its configuration
3533 // needs to change right now.
3534 callbacks.add(a);
3535 } else if (newConfig != null) {
3536 // Otherwise, we will tell it about the change
3537 // the next time it is resumed or shown. Note that
3538 // the activity manager may, before then, decide the
3539 // activity needs to be destroyed to handle its new
3540 // configuration.
3541 ar.newConfig = newConfig;
3542 }
3543 }
3544 }
3545 }
3546 if (mServices.size() > 0) {
3547 Iterator<Service> it = mServices.values().iterator();
3548 while (it.hasNext()) {
3549 callbacks.add(it.next());
3550 }
3551 }
3552 synchronized (mProviderMap) {
3553 if (mLocalProviders.size() > 0) {
3554 Iterator<ProviderRecord> it = mLocalProviders.values().iterator();
3555 while (it.hasNext()) {
3556 callbacks.add(it.next().mLocalProvider);
3557 }
3558 }
3559 }
3560 final int N = mAllApplications.size();
3561 for (int i=0; i<N; i++) {
3562 callbacks.add(mAllApplications.get(i));
3563 }
3564
3565 return callbacks;
3566 }
3567
3568 private final void performConfigurationChanged(
3569 ComponentCallbacks cb, Configuration config) {
3570 // Only for Activity objects, check that they actually call up to their
3571 // superclass implementation. ComponentCallbacks is an interface, so
3572 // we check the runtime type and act accordingly.
3573 Activity activity = (cb instanceof Activity) ? (Activity) cb : null;
3574 if (activity != null) {
3575 activity.mCalled = false;
3576 }
3577
3578 boolean shouldChangeConfig = false;
3579 if ((activity == null) || (activity.mCurrentConfig == null)) {
3580 shouldChangeConfig = true;
3581 } else {
3582
3583 // If the new config is the same as the config this Activity
3584 // is already running with then don't bother calling
3585 // onConfigurationChanged
3586 int diff = activity.mCurrentConfig.diff(config);
3587 if (diff != 0) {
3588
3589 // If this activity doesn't handle any of the config changes
3590 // then don't bother calling onConfigurationChanged as we're
3591 // going to destroy it.
3592 if ((~activity.mActivityInfo.configChanges & diff) == 0) {
3593 shouldChangeConfig = true;
3594 }
3595 }
3596 }
3597
3598 if (shouldChangeConfig) {
3599 cb.onConfigurationChanged(config);
3600
3601 if (activity != null) {
3602 if (!activity.mCalled) {
3603 throw new SuperNotCalledException(
3604 "Activity " + activity.getLocalClassName() +
3605 " did not call through to super.onConfigurationChanged()");
3606 }
3607 activity.mConfigChangeFlags = 0;
3608 activity.mCurrentConfig = new Configuration(config);
3609 }
3610 }
3611 }
3612
3613 final void handleConfigurationChanged(Configuration config) {
3614
3615 synchronized (mRelaunchingActivities) {
3616 if (mPendingConfiguration != null) {
3617 config = mPendingConfiguration;
3618 mPendingConfiguration = null;
3619 }
3620 }
3621
3622 ArrayList<ComponentCallbacks> callbacks
3623 = new ArrayList<ComponentCallbacks>();
3624
3625 synchronized(mPackages) {
3626 if (mConfiguration == null) {
3627 mConfiguration = new Configuration();
3628 }
3629 mConfiguration.updateFrom(config);
3630 DisplayMetrics dm = getDisplayMetricsLocked(true);
3631
3632 // set it for java, this also affects newly created Resources
3633 if (config.locale != null) {
3634 Locale.setDefault(config.locale);
3635 }
3636
3637 Resources.updateSystemConfiguration(config, null);
3638
3639 ApplicationContext.ApplicationPackageManager.configurationChanged();
3640 //Log.i(TAG, "Configuration changed in " + currentPackageName());
3641 {
3642 Iterator<WeakReference<Resources>> it =
3643 mActiveResources.values().iterator();
3644 //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
3645 // mActiveResources.entrySet().iterator();
3646 while (it.hasNext()) {
3647 WeakReference<Resources> v = it.next();
3648 Resources r = v.get();
3649 if (r != null) {
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003650 r.updateConfiguration(config, dm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003651 //Log.i(TAG, "Updated app resources " + v.getKey()
3652 // + " " + r + ": " + r.getConfiguration());
3653 } else {
3654 //Log.i(TAG, "Removing old resources " + v.getKey());
3655 it.remove();
3656 }
3657 }
3658 }
3659
3660 callbacks = collectComponentCallbacksLocked(false, config);
3661 }
3662
3663 final int N = callbacks.size();
3664 for (int i=0; i<N; i++) {
3665 performConfigurationChanged(callbacks.get(i), config);
3666 }
3667 }
3668
3669 final void handleActivityConfigurationChanged(IBinder token) {
3670 ActivityRecord r = mActivities.get(token);
3671 if (r == null || r.activity == null) {
3672 return;
3673 }
3674
3675 performConfigurationChanged(r.activity, mConfiguration);
3676 }
3677
Dianne Hackborn9c8dd552009-06-23 19:22:52 -07003678 final void handleProfilerControl(boolean start, ProfilerControlData pcd) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08003679 if (start) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08003680 try {
Dianne Hackborn9c8dd552009-06-23 19:22:52 -07003681 Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(),
3682 8 * 1024 * 1024, 0);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08003683 } catch (RuntimeException e) {
Dianne Hackborn9c8dd552009-06-23 19:22:52 -07003684 Log.w(TAG, "Profiling failed on path " + pcd.path
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08003685 + " -- can the process access this path?");
Dianne Hackborn9c8dd552009-06-23 19:22:52 -07003686 } finally {
3687 try {
3688 pcd.fd.close();
3689 } catch (IOException e) {
3690 Log.w(TAG, "Failure closing profile fd", e);
3691 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -08003692 }
3693 } else {
3694 Debug.stopMethodTracing();
3695 }
3696 }
3697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003698 final void handleLowMemory() {
3699 ArrayList<ComponentCallbacks> callbacks
3700 = new ArrayList<ComponentCallbacks>();
3701
3702 synchronized(mPackages) {
3703 callbacks = collectComponentCallbacksLocked(true, null);
3704 }
3705
3706 final int N = callbacks.size();
3707 for (int i=0; i<N; i++) {
3708 callbacks.get(i).onLowMemory();
3709 }
3710
Chris Tatece229052009-03-25 16:44:52 -07003711 // Ask SQLite to free up as much memory as it can, mostly from its page caches.
3712 if (Process.myUid() != Process.SYSTEM_UID) {
3713 int sqliteReleased = SQLiteDatabase.releaseMemory();
3714 EventLog.writeEvent(SQLITE_MEM_RELEASED_EVENT_LOG_TAG, sqliteReleased);
3715 }
Mike Reedcaf0df12009-04-27 14:32:05 -04003716
3717 // Ask graphics to free up as much as possible (font/image caches)
3718 Canvas.freeCaches();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003719
3720 BinderInternal.forceGc("mem");
3721 }
3722
3723 private final void handleBindApplication(AppBindData data) {
3724 mBoundApplication = data;
3725 mConfiguration = new Configuration(data.config);
3726
3727 // We now rely on this being set by zygote.
3728 //Process.setGid(data.appInfo.gid);
3729 //Process.setUid(data.appInfo.uid);
3730
3731 // send up app name; do this *before* waiting for debugger
3732 android.ddm.DdmHandleAppName.setAppName(data.processName);
3733
3734 /*
3735 * Before spawning a new process, reset the time zone to be the system time zone.
3736 * This needs to be done because the system time zone could have changed after the
3737 * the spawning of this process. Without doing this this process would have the incorrect
3738 * system time zone.
3739 */
3740 TimeZone.setDefault(null);
3741
3742 /*
3743 * Initialize the default locale in this process for the reasons we set the time zone.
3744 */
3745 Locale.setDefault(data.config.locale);
3746
Suchi Amalapurapuc9843292009-06-24 17:02:25 -07003747 /*
3748 * Update the system configuration since its preloaded and might not
3749 * reflect configuration changes. The configuration object passed
3750 * in AppBindData can be safely assumed to be up to date
3751 */
3752 Resources.getSystem().updateConfiguration(mConfiguration, null);
3753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 data.info = getPackageInfoNoCheck(data.appInfo);
3755
3756 if (data.debugMode != IApplicationThread.DEBUG_OFF) {
3757 // XXX should have option to change the port.
3758 Debug.changeDebugPort(8100);
3759 if (data.debugMode == IApplicationThread.DEBUG_WAIT) {
3760 Log.w(TAG, "Application " + data.info.getPackageName()
3761 + " is waiting for the debugger on port 8100...");
3762
3763 IActivityManager mgr = ActivityManagerNative.getDefault();
3764 try {
3765 mgr.showWaitingForDebugger(mAppThread, true);
3766 } catch (RemoteException ex) {
3767 }
3768
3769 Debug.waitForDebugger();
3770
3771 try {
3772 mgr.showWaitingForDebugger(mAppThread, false);
3773 } catch (RemoteException ex) {
3774 }
3775
3776 } else {
3777 Log.w(TAG, "Application " + data.info.getPackageName()
3778 + " can be debugged on port 8100...");
3779 }
3780 }
3781
3782 if (data.instrumentationName != null) {
3783 ApplicationContext appContext = new ApplicationContext();
3784 appContext.init(data.info, null, this);
3785 InstrumentationInfo ii = null;
3786 try {
3787 ii = appContext.getPackageManager().
3788 getInstrumentationInfo(data.instrumentationName, 0);
3789 } catch (PackageManager.NameNotFoundException e) {
3790 }
3791 if (ii == null) {
3792 throw new RuntimeException(
3793 "Unable to find instrumentation info for: "
3794 + data.instrumentationName);
3795 }
3796
3797 mInstrumentationAppDir = ii.sourceDir;
3798 mInstrumentationAppPackage = ii.packageName;
3799 mInstrumentedAppDir = data.info.getAppDir();
3800
3801 ApplicationInfo instrApp = new ApplicationInfo();
3802 instrApp.packageName = ii.packageName;
3803 instrApp.sourceDir = ii.sourceDir;
3804 instrApp.publicSourceDir = ii.publicSourceDir;
3805 instrApp.dataDir = ii.dataDir;
3806 PackageInfo pi = getPackageInfo(instrApp,
3807 appContext.getClassLoader(), false, true);
3808 ApplicationContext instrContext = new ApplicationContext();
3809 instrContext.init(pi, null, this);
3810
3811 try {
3812 java.lang.ClassLoader cl = instrContext.getClassLoader();
3813 mInstrumentation = (Instrumentation)
3814 cl.loadClass(data.instrumentationName.getClassName()).newInstance();
3815 } catch (Exception e) {
3816 throw new RuntimeException(
3817 "Unable to instantiate instrumentation "
3818 + data.instrumentationName + ": " + e.toString(), e);
3819 }
3820
3821 mInstrumentation.init(this, instrContext, appContext,
3822 new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher);
3823
3824 if (data.profileFile != null && !ii.handleProfiling) {
3825 data.handlingProfiling = true;
3826 File file = new File(data.profileFile);
3827 file.getParentFile().mkdirs();
3828 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
3829 }
3830
3831 try {
3832 mInstrumentation.onCreate(data.instrumentationArgs);
3833 }
3834 catch (Exception e) {
3835 throw new RuntimeException(
3836 "Exception thrown in onCreate() of "
3837 + data.instrumentationName + ": " + e.toString(), e);
3838 }
3839
3840 } else {
3841 mInstrumentation = new Instrumentation();
3842 }
3843
Christopher Tate181fafa2009-05-14 11:12:14 -07003844 // If the app is being launched for full backup or restore, bring it up in
3845 // a restricted environment with the base application class.
3846 Application app = data.info.makeApplication(data.restrictedBackupMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003847 mInitialApplication = app;
3848
3849 List<ProviderInfo> providers = data.providers;
3850 if (providers != null) {
3851 installContentProviders(app, providers);
3852 }
3853
3854 try {
3855 mInstrumentation.callApplicationOnCreate(app);
3856 } catch (Exception e) {
3857 if (!mInstrumentation.onException(app, e)) {
3858 throw new RuntimeException(
3859 "Unable to create application " + app.getClass().getName()
3860 + ": " + e.toString(), e);
3861 }
3862 }
3863 }
3864
3865 /*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
3866 IActivityManager am = ActivityManagerNative.getDefault();
3867 if (mBoundApplication.profileFile != null && mBoundApplication.handlingProfiling) {
3868 Debug.stopMethodTracing();
3869 }
3870 //Log.i(TAG, "am: " + ActivityManagerNative.getDefault()
3871 // + ", app thr: " + mAppThread);
3872 try {
3873 am.finishInstrumentation(mAppThread, resultCode, results);
3874 } catch (RemoteException ex) {
3875 }
3876 }
3877
3878 private final void installContentProviders(
3879 Context context, List<ProviderInfo> providers) {
3880 final ArrayList<IActivityManager.ContentProviderHolder> results =
3881 new ArrayList<IActivityManager.ContentProviderHolder>();
3882
3883 Iterator<ProviderInfo> i = providers.iterator();
3884 while (i.hasNext()) {
3885 ProviderInfo cpi = i.next();
3886 StringBuilder buf = new StringBuilder(128);
3887 buf.append("Publishing provider ");
3888 buf.append(cpi.authority);
3889 buf.append(": ");
3890 buf.append(cpi.name);
3891 Log.i(TAG, buf.toString());
3892 IContentProvider cp = installProvider(context, null, cpi, false);
3893 if (cp != null) {
3894 IActivityManager.ContentProviderHolder cph =
3895 new IActivityManager.ContentProviderHolder(cpi);
3896 cph.provider = cp;
3897 results.add(cph);
3898 // Don't ever unload this provider from the process.
3899 synchronized(mProviderMap) {
3900 mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000));
3901 }
3902 }
3903 }
3904
3905 try {
3906 ActivityManagerNative.getDefault().publishContentProviders(
3907 getApplicationThread(), results);
3908 } catch (RemoteException ex) {
3909 }
3910 }
3911
3912 private final IContentProvider getProvider(Context context, String name) {
3913 synchronized(mProviderMap) {
3914 final ProviderRecord pr = mProviderMap.get(name);
3915 if (pr != null) {
3916 return pr.mProvider;
3917 }
3918 }
3919
3920 IActivityManager.ContentProviderHolder holder = null;
3921 try {
3922 holder = ActivityManagerNative.getDefault().getContentProvider(
3923 getApplicationThread(), name);
3924 } catch (RemoteException ex) {
3925 }
3926 if (holder == null) {
3927 Log.e(TAG, "Failed to find provider info for " + name);
3928 return null;
3929 }
3930 if (holder.permissionFailure != null) {
3931 throw new SecurityException("Permission " + holder.permissionFailure
3932 + " required for provider " + name);
3933 }
3934
3935 IContentProvider prov = installProvider(context, holder.provider,
3936 holder.info, true);
3937 //Log.i(TAG, "noReleaseNeeded=" + holder.noReleaseNeeded);
3938 if (holder.noReleaseNeeded || holder.provider == null) {
3939 // We are not going to release the provider if it is an external
3940 // provider that doesn't care about being released, or if it is
3941 // a local provider running in this process.
3942 //Log.i(TAG, "*** NO RELEASE NEEDED");
3943 synchronized(mProviderMap) {
3944 mProviderRefCountMap.put(prov.asBinder(), new ProviderRefCount(10000));
3945 }
3946 }
3947 return prov;
3948 }
3949
3950 public final IContentProvider acquireProvider(Context c, String name) {
3951 IContentProvider provider = getProvider(c, name);
3952 if(provider == null)
3953 return null;
3954 IBinder jBinder = provider.asBinder();
3955 synchronized(mProviderMap) {
3956 ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
3957 if(prc == null) {
3958 mProviderRefCountMap.put(jBinder, new ProviderRefCount(1));
3959 } else {
3960 prc.count++;
3961 } //end else
3962 } //end synchronized
3963 return provider;
3964 }
3965
3966 public final boolean releaseProvider(IContentProvider provider) {
3967 if(provider == null) {
3968 return false;
3969 }
3970 IBinder jBinder = provider.asBinder();
3971 synchronized(mProviderMap) {
3972 ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
3973 if(prc == null) {
3974 if(localLOGV) Log.v(TAG, "releaseProvider::Weird shouldnt be here");
3975 return false;
3976 } else {
3977 prc.count--;
3978 if(prc.count == 0) {
3979 mProviderRefCountMap.remove(jBinder);
3980 //invoke removeProvider to dereference provider
3981 removeProviderLocked(provider);
3982 } //end if
3983 } //end else
3984 } //end synchronized
3985 return true;
3986 }
3987
3988 public final void removeProviderLocked(IContentProvider provider) {
3989 if (provider == null) {
3990 return;
3991 }
3992 IBinder providerBinder = provider.asBinder();
3993 boolean amRemoveFlag = false;
3994
3995 // remove the provider from mProviderMap
3996 Iterator<ProviderRecord> iter = mProviderMap.values().iterator();
3997 while (iter.hasNext()) {
3998 ProviderRecord pr = iter.next();
3999 IBinder myBinder = pr.mProvider.asBinder();
4000 if (myBinder == providerBinder) {
4001 //find if its published by this process itself
4002 if(pr.mLocalProvider != null) {
4003 if(localLOGV) Log.i(TAG, "removeProvider::found local provider returning");
4004 return;
4005 }
4006 if(localLOGV) Log.v(TAG, "removeProvider::Not local provider Unlinking " +
4007 "death recipient");
4008 //content provider is in another process
4009 myBinder.unlinkToDeath(pr, 0);
4010 iter.remove();
4011 //invoke remove only once for the very first name seen
4012 if(!amRemoveFlag) {
4013 try {
4014 if(localLOGV) Log.v(TAG, "removeProvider::Invoking " +
4015 "ActivityManagerNative.removeContentProvider("+pr.mName);
4016 ActivityManagerNative.getDefault().removeContentProvider(getApplicationThread(), pr.mName);
4017 amRemoveFlag = true;
4018 } catch (RemoteException e) {
4019 //do nothing content provider object is dead any way
4020 } //end catch
4021 }
4022 } //end if myBinder
4023 } //end while iter
4024 }
4025
4026 final void removeDeadProvider(String name, IContentProvider provider) {
4027 synchronized(mProviderMap) {
4028 ProviderRecord pr = mProviderMap.get(name);
4029 if (pr.mProvider.asBinder() == provider.asBinder()) {
4030 Log.i(TAG, "Removing dead content provider: " + name);
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07004031 ProviderRecord removed = mProviderMap.remove(name);
4032 if (removed != null) {
4033 removed.mProvider.asBinder().unlinkToDeath(removed, 0);
4034 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004035 }
4036 }
4037 }
4038
4039 final void removeDeadProviderLocked(String name, IContentProvider provider) {
4040 ProviderRecord pr = mProviderMap.get(name);
4041 if (pr.mProvider.asBinder() == provider.asBinder()) {
4042 Log.i(TAG, "Removing dead content provider: " + name);
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07004043 ProviderRecord removed = mProviderMap.remove(name);
4044 if (removed != null) {
4045 removed.mProvider.asBinder().unlinkToDeath(removed, 0);
4046 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004047 }
4048 }
4049
4050 private final IContentProvider installProvider(Context context,
4051 IContentProvider provider, ProviderInfo info, boolean noisy) {
4052 ContentProvider localProvider = null;
4053 if (provider == null) {
4054 if (noisy) {
4055 Log.d(TAG, "Loading provider " + info.authority + ": "
4056 + info.name);
4057 }
4058 Context c = null;
4059 ApplicationInfo ai = info.applicationInfo;
4060 if (context.getPackageName().equals(ai.packageName)) {
4061 c = context;
4062 } else if (mInitialApplication != null &&
4063 mInitialApplication.getPackageName().equals(ai.packageName)) {
4064 c = mInitialApplication;
4065 } else {
4066 try {
4067 c = context.createPackageContext(ai.packageName,
4068 Context.CONTEXT_INCLUDE_CODE);
4069 } catch (PackageManager.NameNotFoundException e) {
4070 }
4071 }
4072 if (c == null) {
4073 Log.w(TAG, "Unable to get context for package " +
4074 ai.packageName +
4075 " while loading content provider " +
4076 info.name);
4077 return null;
4078 }
4079 try {
4080 final java.lang.ClassLoader cl = c.getClassLoader();
4081 localProvider = (ContentProvider)cl.
4082 loadClass(info.name).newInstance();
4083 provider = localProvider.getIContentProvider();
4084 if (provider == null) {
4085 Log.e(TAG, "Failed to instantiate class " +
4086 info.name + " from sourceDir " +
4087 info.applicationInfo.sourceDir);
4088 return null;
4089 }
4090 if (Config.LOGV) Log.v(
4091 TAG, "Instantiating local provider " + info.name);
4092 // XXX Need to create the correct context for this provider.
4093 localProvider.attachInfo(c, info);
4094 } catch (java.lang.Exception e) {
4095 if (!mInstrumentation.onException(null, e)) {
4096 throw new RuntimeException(
4097 "Unable to get provider " + info.name
4098 + ": " + e.toString(), e);
4099 }
4100 return null;
4101 }
4102 } else if (localLOGV) {
4103 Log.v(TAG, "Installing external provider " + info.authority + ": "
4104 + info.name);
4105 }
4106
4107 synchronized (mProviderMap) {
4108 // Cache the pointer for the remote provider.
4109 String names[] = PATTERN_SEMICOLON.split(info.authority);
4110 for (int i=0; i<names.length; i++) {
4111 ProviderRecord pr = new ProviderRecord(names[i], provider,
4112 localProvider);
4113 try {
4114 provider.asBinder().linkToDeath(pr, 0);
4115 mProviderMap.put(names[i], pr);
4116 } catch (RemoteException e) {
4117 return null;
4118 }
4119 }
4120 if (localProvider != null) {
4121 mLocalProviders.put(provider.asBinder(),
4122 new ProviderRecord(null, provider, localProvider));
4123 }
4124 }
4125
4126 return provider;
4127 }
4128
4129 private final void attach(boolean system) {
4130 sThreadLocal.set(this);
4131 mSystemThread = system;
4132 AndroidHttpClient.setThreadBlocked(true);
4133 if (!system) {
4134 android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
4135 RuntimeInit.setApplicationObject(mAppThread.asBinder());
4136 IActivityManager mgr = ActivityManagerNative.getDefault();
4137 try {
4138 mgr.attachApplication(mAppThread);
4139 } catch (RemoteException ex) {
4140 }
4141 } else {
4142 // Don't set application object here -- if the system crashes,
4143 // we can't display an alert, we just want to die die die.
4144 android.ddm.DdmHandleAppName.setAppName("system_process");
4145 try {
4146 mInstrumentation = new Instrumentation();
4147 ApplicationContext context = new ApplicationContext();
4148 context.init(getSystemContext().mPackageInfo, null, this);
4149 Application app = Instrumentation.newApplication(Application.class, context);
4150 mAllApplications.add(app);
4151 mInitialApplication = app;
4152 app.onCreate();
4153 } catch (Exception e) {
4154 throw new RuntimeException(
4155 "Unable to instantiate Application():" + e.toString(), e);
4156 }
4157 }
4158 }
4159
4160 private final void detach()
4161 {
4162 AndroidHttpClient.setThreadBlocked(false);
4163 sThreadLocal.set(null);
4164 }
4165
4166 public static final ActivityThread systemMain() {
4167 ActivityThread thread = new ActivityThread();
4168 thread.attach(true);
4169 return thread;
4170 }
4171
4172 public final void installSystemProviders(List providers) {
4173 if (providers != null) {
4174 installContentProviders(mInitialApplication,
4175 (List<ProviderInfo>)providers);
4176 }
4177 }
4178
4179 public static final void main(String[] args) {
4180 Process.setArgV0("<pre-initialized>");
4181
4182 Looper.prepareMainLooper();
4183
4184 ActivityThread thread = new ActivityThread();
4185 thread.attach(false);
4186
4187 Looper.loop();
4188
4189 if (Process.supportsProcesses()) {
4190 throw new RuntimeException("Main thread loop unexpectedly exited");
4191 }
4192
4193 thread.detach();
4194 String name;
4195 if (thread.mInitialApplication != null) name = thread.mInitialApplication.getPackageName();
4196 else name = "<unknown>";
4197 Log.i(TAG, "Main thread of " + name + " is now exiting");
4198 }
4199}