blob: 47a58cf03880cf4554f36236ea3035012be15931 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 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 com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
Dianne Hackborndd71fc82009-12-16 19:24:32 -080028import dalvik.system.Zygote;
29
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.app.Activity;
31import android.app.ActivityManager;
32import android.app.ActivityManagerNative;
33import android.app.ActivityThread;
34import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020035import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070037import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.app.IActivityWatcher;
39import android.app.IApplicationThread;
40import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.app.IServiceConnection;
42import android.app.IThumbnailReceiver;
43import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070044import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.app.PendingIntent;
46import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070047import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070048import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020049import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.content.ComponentName;
51import android.content.ContentResolver;
52import android.content.Context;
53import android.content.Intent;
54import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070055import android.content.IIntentReceiver;
56import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070057import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.content.pm.ActivityInfo;
59import android.content.pm.ApplicationInfo;
60import android.content.pm.ConfigurationInfo;
61import android.content.pm.IPackageDataObserver;
62import android.content.pm.IPackageManager;
63import android.content.pm.InstrumentationInfo;
Dan Egnor66c40e72010-01-26 16:23:11 -080064import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070066import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.content.pm.ProviderInfo;
68import android.content.pm.ResolveInfo;
69import android.content.pm.ServiceInfo;
70import android.content.res.Configuration;
71import android.graphics.Bitmap;
72import android.net.Uri;
73import android.os.Binder;
Dan Egnor60d87622009-12-16 16:32:58 -080074import android.os.Build;
Dan Egnor42471dd2010-01-07 17:25:22 -080075import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070076import android.os.Debug;
Dan Egnor60d87622009-12-16 16:32:58 -080077import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.os.Environment;
Dan Egnor42471dd2010-01-07 17:25:22 -080079import android.os.FileObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.FileUtils;
81import android.os.Handler;
82import android.os.IBinder;
83import android.os.IPermissionController;
84import android.os.Looper;
85import android.os.Message;
86import android.os.Parcel;
87import android.os.ParcelFileDescriptor;
88import android.os.PowerManager;
89import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070090import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.os.RemoteException;
92import android.os.ServiceManager;
93import android.os.SystemClock;
94import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.provider.Settings;
96import android.text.TextUtils;
97import android.util.Config;
98import android.util.EventLog;
99import android.util.Log;
100import android.util.PrintWriterPrinter;
101import android.util.SparseArray;
102import android.view.Gravity;
103import android.view.LayoutInflater;
104import android.view.View;
105import android.view.WindowManager;
106import android.view.WindowManagerPolicy;
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.File;
109import java.io.FileDescriptor;
110import java.io.FileInputStream;
111import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200112import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import java.io.PrintWriter;
114import java.lang.IllegalStateException;
115import java.lang.ref.WeakReference;
116import java.util.ArrayList;
117import java.util.HashMap;
118import java.util.HashSet;
119import java.util.Iterator;
120import java.util.List;
121import java.util.Locale;
122import java.util.Map;
123
124public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
125 static final String TAG = "ActivityManager";
126 static final boolean DEBUG = false;
127 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
128 static final boolean DEBUG_SWITCH = localLOGV || false;
129 static final boolean DEBUG_TASKS = localLOGV || false;
130 static final boolean DEBUG_PAUSE = localLOGV || false;
131 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
132 static final boolean DEBUG_TRANSITION = localLOGV || false;
133 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700134 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 static final boolean DEBUG_SERVICE = localLOGV || false;
136 static final boolean DEBUG_VISBILITY = localLOGV || false;
137 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700138 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700140 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700141 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700142 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 static final boolean VALIDATE_TOKENS = false;
144 static final boolean SHOW_ACTIVITY_START_TIME = true;
145
146 // Control over CPU and battery monitoring.
147 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
148 static final boolean MONITOR_CPU_USAGE = true;
149 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
150 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
151 static final boolean MONITOR_THREAD_CPU_USAGE = false;
152
Dianne Hackborn1655be42009-05-08 14:29:01 -0700153 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700154 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 private static final String SYSTEM_SECURE = "ro.secure";
157
158 // This is the maximum number of application processes we would like
159 // to have running. Due to the asynchronous nature of things, we can
160 // temporarily go beyond this limit.
161 static final int MAX_PROCESSES = 2;
162
163 // Set to false to leave processes running indefinitely, relying on
164 // the kernel killing them as resources are required.
165 static final boolean ENFORCE_PROCESS_LIMIT = false;
166
167 // This is the maximum number of activities that we would like to have
168 // running at a given time.
169 static final int MAX_ACTIVITIES = 20;
170
171 // Maximum number of recent tasks that we can remember.
172 static final int MAX_RECENT_TASKS = 20;
173
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700174 // Amount of time after a call to stopAppSwitches() during which we will
175 // prevent further untrusted switches from happening.
176 static final long APP_SWITCH_DELAY_TIME = 5*1000;
177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 // How long until we reset a task when the user returns to it. Currently
179 // 30 minutes.
180 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
181
182 // Set to true to disable the icon that is shown while a new activity
183 // is being started.
184 static final boolean SHOW_APP_STARTING_ICON = true;
185
186 // How long we wait until giving up on the last activity to pause. This
187 // is short because it directly impacts the responsiveness of starting the
188 // next activity.
189 static final int PAUSE_TIMEOUT = 500;
190
191 /**
192 * How long we can hold the launch wake lock before giving up.
193 */
194 static final int LAUNCH_TIMEOUT = 10*1000;
195
196 // How long we wait for a launched process to attach to the activity manager
197 // before we decide it's never going to come up for real.
198 static final int PROC_START_TIMEOUT = 10*1000;
199
200 // How long we wait until giving up on the last activity telling us it
201 // is idle.
202 static final int IDLE_TIMEOUT = 10*1000;
203
204 // How long to wait after going idle before forcing apps to GC.
205 static final int GC_TIMEOUT = 5*1000;
206
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700207 // The minimum amount of time between successive GC requests for a process.
208 static final int GC_MIN_INTERVAL = 60*1000;
209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 // How long we wait until giving up on an activity telling us it has
211 // finished destroying itself.
212 static final int DESTROY_TIMEOUT = 10*1000;
213
214 // How long we allow a receiver to run before giving up on it.
215 static final int BROADCAST_TIMEOUT = 10*1000;
216
217 // How long we wait for a service to finish executing.
218 static final int SERVICE_TIMEOUT = 20*1000;
219
220 // How long a service needs to be running until restarting its process
221 // is no longer considered to be a relaunch of the service.
222 static final int SERVICE_RESTART_DURATION = 5*1000;
223
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700224 // How long a service needs to be running until it will start back at
225 // SERVICE_RESTART_DURATION after being killed.
226 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
227
228 // Multiplying factor to increase restart duration time by, for each time
229 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
230 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
231
232 // The minimum amount of time between restarting services that we allow.
233 // That is, when multiple services are restarting, we won't allow each
234 // to restart less than this amount of time from the last one.
235 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 // Maximum amount of time for there to be no activity on a service before
238 // we consider it non-essential and allow its process to go on the
239 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700240 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
242 // How long we wait until we timeout on key dispatching.
243 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
244
245 // The minimum time we allow between crashes, for us to consider this
246 // application to be bad and stop and its services and reject broadcasts.
247 static final int MIN_CRASH_INTERVAL = 60*1000;
248
249 // How long we wait until we timeout on key dispatching during instrumentation.
250 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
251
252 // OOM adjustments for processes in various states:
253
254 // This is a process without anything currently running in it. Definitely
255 // the first to go! Value set in system/rootdir/init.rc on startup.
256 // This value is initalized in the constructor, careful when refering to
257 // this static variable externally.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800258 static final int EMPTY_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
260 // This is a process only hosting activities that are not visible,
261 // so it can be killed without any disruption. Value set in
262 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800263 static final int HIDDEN_APP_MAX_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 static int HIDDEN_APP_MIN_ADJ;
265
The Android Open Source Project4df24232009-03-05 14:34:35 -0800266 // This is a process holding the home application -- we want to try
267 // avoiding killing it, even if it would normally be in the background,
268 // because the user interacts with it so much.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800269 static final int HOME_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800270
Christopher Tate6fa95972009-06-05 18:43:55 -0700271 // This is a process currently hosting a backup operation. Killing it
272 // is not entirely fatal but is generally a bad idea.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800273 static final int BACKUP_APP_ADJ;
Christopher Tate6fa95972009-06-05 18:43:55 -0700274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 // This is a process holding a secondary server -- killing it will not
276 // have much of an impact as far as the user is concerned. Value set in
277 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800278 static final int SECONDARY_SERVER_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 // This is a process only hosting activities that are visible to the
281 // user, so we'd prefer they don't disappear. Value set in
282 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800283 static final int VISIBLE_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284
285 // This is the process running the current foreground app. We'd really
286 // rather not kill it! Value set in system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800287 static final int FOREGROUND_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288
289 // This is a process running a core server, such as telephony. Definitely
290 // don't want to kill it, but doing so is not completely fatal.
291 static final int CORE_SERVER_ADJ = -12;
292
293 // The system process runs at the default adjustment.
294 static final int SYSTEM_ADJ = -16;
295
296 // Memory pages are 4K.
297 static final int PAGE_SIZE = 4*1024;
298
Jacek Surazski82a73df2009-06-17 14:33:18 +0200299 // System property defining error report receiver for system apps
300 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
301
302 // System property defining default error report receiver
303 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 // Corresponding memory levels for above adjustments.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800306 static final int EMPTY_APP_MEM;
307 static final int HIDDEN_APP_MEM;
308 static final int HOME_APP_MEM;
309 static final int BACKUP_APP_MEM;
310 static final int SECONDARY_SERVER_MEM;
311 static final int VISIBLE_APP_MEM;
312 static final int FOREGROUND_APP_MEM;
313
314 // The minimum number of hidden apps we want to be able to keep around,
315 // without empty apps being able to push them out of memory.
316 static final int MIN_HIDDEN_APPS = 2;
317
318 // We put empty content processes after any hidden processes that have
319 // been idle for less than 30 seconds.
320 static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
321
322 // We put empty content processes after any hidden processes that have
323 // been idle for less than 60 seconds.
324 static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
325
326 static {
327 // These values are set in system/rootdir/init.rc on startup.
328 FOREGROUND_APP_ADJ =
329 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
330 VISIBLE_APP_ADJ =
331 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
332 SECONDARY_SERVER_ADJ =
333 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
334 BACKUP_APP_ADJ =
335 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
336 HOME_APP_ADJ =
337 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
338 HIDDEN_APP_MIN_ADJ =
339 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
340 EMPTY_APP_ADJ =
341 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
342 HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
343 FOREGROUND_APP_MEM =
344 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
345 VISIBLE_APP_MEM =
346 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
347 SECONDARY_SERVER_MEM =
348 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
349 BACKUP_APP_MEM =
350 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
351 HOME_APP_MEM =
352 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
353 HIDDEN_APP_MEM =
354 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
355 EMPTY_APP_MEM =
356 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358
Dan Egnor42471dd2010-01-07 17:25:22 -0800359 static final int MY_PID = Process.myPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360
361 static final String[] EMPTY_STRING_ARRAY = new String[0];
362
363 enum ActivityState {
364 INITIALIZING,
365 RESUMED,
366 PAUSING,
367 PAUSED,
368 STOPPING,
369 STOPPED,
370 FINISHING,
371 DESTROYING,
372 DESTROYED
373 }
374
375 /**
376 * The back history of all previous (and possibly still
377 * running) activities. It contains HistoryRecord objects.
378 */
379 final ArrayList mHistory = new ArrayList();
380
381 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700382 * Description of a request to start a new activity, which has been held
383 * due to app switches being disabled.
384 */
385 class PendingActivityLaunch {
386 HistoryRecord r;
387 HistoryRecord sourceRecord;
388 Uri[] grantedUriPermissions;
389 int grantedMode;
390 boolean onlyIfNeeded;
391 }
392
393 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
394 = new ArrayList<PendingActivityLaunch>();
395
396 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 * List of all active broadcasts that are to be executed immediately
398 * (without waiting for another broadcast to finish). Currently this only
399 * contains broadcasts to registered receivers, to avoid spinning up
400 * a bunch of processes to execute IntentReceiver components.
401 */
402 final ArrayList<BroadcastRecord> mParallelBroadcasts
403 = new ArrayList<BroadcastRecord>();
404
405 /**
406 * List of all active broadcasts that are to be executed one at a time.
407 * The object at the top of the list is the currently activity broadcasts;
408 * those after it are waiting for the top to finish..
409 */
410 final ArrayList<BroadcastRecord> mOrderedBroadcasts
411 = new ArrayList<BroadcastRecord>();
412
413 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800414 * Historical data of past broadcasts, for debugging.
415 */
416 static final int MAX_BROADCAST_HISTORY = 100;
417 final BroadcastRecord[] mBroadcastHistory
418 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
419
420 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 * Set when we current have a BROADCAST_INTENT_MSG in flight.
422 */
423 boolean mBroadcastsScheduled = false;
424
425 /**
426 * Set to indicate whether to issue an onUserLeaving callback when a
427 * newly launched activity is being brought in front of us.
428 */
429 boolean mUserLeaving = false;
430
431 /**
432 * When we are in the process of pausing an activity, before starting the
433 * next one, this variable holds the activity that is currently being paused.
434 */
435 HistoryRecord mPausingActivity = null;
436
437 /**
438 * Current activity that is resumed, or null if there is none.
439 */
440 HistoryRecord mResumedActivity = null;
441
442 /**
443 * Activity we have told the window manager to have key focus.
444 */
445 HistoryRecord mFocusedActivity = null;
446
447 /**
448 * This is the last activity that we put into the paused state. This is
449 * used to determine if we need to do an activity transition while sleeping,
450 * when we normally hold the top activity paused.
451 */
452 HistoryRecord mLastPausedActivity = null;
453
454 /**
455 * List of activities that are waiting for a new activity
456 * to become visible before completing whatever operation they are
457 * supposed to do.
458 */
459 final ArrayList mWaitingVisibleActivities = new ArrayList();
460
461 /**
462 * List of activities that are ready to be stopped, but waiting
463 * for the next activity to settle down before doing so. It contains
464 * HistoryRecord objects.
465 */
466 final ArrayList<HistoryRecord> mStoppingActivities
467 = new ArrayList<HistoryRecord>();
468
469 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700470 * Animations that for the current transition have requested not to
471 * be considered for the transition animation.
472 */
473 final ArrayList<HistoryRecord> mNoAnimActivities
474 = new ArrayList<HistoryRecord>();
475
476 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 * List of intents that were used to start the most recent tasks.
478 */
479 final ArrayList<TaskRecord> mRecentTasks
480 = new ArrayList<TaskRecord>();
481
482 /**
483 * List of activities that are ready to be finished, but waiting
484 * for the previous activity to settle down before doing so. It contains
485 * HistoryRecord objects.
486 */
487 final ArrayList mFinishingActivities = new ArrayList();
488
489 /**
490 * All of the applications we currently have running organized by name.
491 * The keys are strings of the application package name (as
492 * returned by the package manager), and the keys are ApplicationRecord
493 * objects.
494 */
495 final ProcessMap<ProcessRecord> mProcessNames
496 = new ProcessMap<ProcessRecord>();
497
498 /**
499 * The last time that various processes have crashed.
500 */
501 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
502
503 /**
504 * Set of applications that we consider to be bad, and will reject
505 * incoming broadcasts from (which the user has no control over).
506 * Processes are added to this set when they have crashed twice within
507 * a minimum amount of time; they are removed from it when they are
508 * later restarted (hopefully due to some user action). The value is the
509 * time it was added to the list.
510 */
511 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
512
513 /**
514 * All of the processes we currently have running organized by pid.
515 * The keys are the pid running the application.
516 *
517 * <p>NOTE: This object is protected by its own lock, NOT the global
518 * activity manager lock!
519 */
520 final SparseArray<ProcessRecord> mPidsSelfLocked
521 = new SparseArray<ProcessRecord>();
522
523 /**
524 * All of the processes that have been forced to be foreground. The key
525 * is the pid of the caller who requested it (we hold a death
526 * link on it).
527 */
528 abstract class ForegroundToken implements IBinder.DeathRecipient {
529 int pid;
530 IBinder token;
531 }
532 final SparseArray<ForegroundToken> mForegroundProcesses
533 = new SparseArray<ForegroundToken>();
534
535 /**
536 * List of records for processes that someone had tried to start before the
537 * system was ready. We don't start them at that point, but ensure they
538 * are started by the time booting is complete.
539 */
540 final ArrayList<ProcessRecord> mProcessesOnHold
541 = new ArrayList<ProcessRecord>();
542
543 /**
544 * List of records for processes that we have started and are waiting
545 * for them to call back. This is really only needed when running in
546 * single processes mode, in which case we do not have a unique pid for
547 * each process.
548 */
549 final ArrayList<ProcessRecord> mStartingProcesses
550 = new ArrayList<ProcessRecord>();
551
552 /**
553 * List of persistent applications that are in the process
554 * of being started.
555 */
556 final ArrayList<ProcessRecord> mPersistentStartingProcesses
557 = new ArrayList<ProcessRecord>();
558
559 /**
560 * Processes that are being forcibly torn down.
561 */
562 final ArrayList<ProcessRecord> mRemovedProcesses
563 = new ArrayList<ProcessRecord>();
564
565 /**
566 * List of running applications, sorted by recent usage.
567 * The first entry in the list is the least recently used.
568 * It contains ApplicationRecord objects. This list does NOT include
569 * any persistent application records (since we never want to exit them).
570 */
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800571 final ArrayList<ProcessRecord> mLruProcesses
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 = new ArrayList<ProcessRecord>();
573
574 /**
575 * List of processes that should gc as soon as things are idle.
576 */
577 final ArrayList<ProcessRecord> mProcessesToGc
578 = new ArrayList<ProcessRecord>();
579
580 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800581 * This is the process holding what we currently consider to be
582 * the "home" activity.
583 */
584 private ProcessRecord mHomeProcess;
585
586 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 * List of running activities, sorted by recent usage.
588 * The first entry in the list is the least recently used.
589 * It contains HistoryRecord objects.
590 */
591 private final ArrayList mLRUActivities = new ArrayList();
592
593 /**
594 * Set of PendingResultRecord objects that are currently active.
595 */
596 final HashSet mPendingResultRecords = new HashSet();
597
598 /**
599 * Set of IntentSenderRecord objects that are currently active.
600 */
601 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
602 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
603
604 /**
605 * Intent broadcast that we have tried to start, but are
606 * waiting for its application's process to be created. We only
607 * need one (instead of a list) because we always process broadcasts
608 * one at a time, so no others can be started while waiting for this
609 * one.
610 */
611 BroadcastRecord mPendingBroadcast = null;
612
613 /**
614 * Keeps track of all IIntentReceivers that have been registered for
615 * broadcasts. Hash keys are the receiver IBinder, hash value is
616 * a ReceiverList.
617 */
618 final HashMap mRegisteredReceivers = new HashMap();
619
620 /**
621 * Resolver for broadcast intents to registered receivers.
622 * Holds BroadcastFilter (subclass of IntentFilter).
623 */
624 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
625 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
626 @Override
627 protected boolean allowFilterResult(
628 BroadcastFilter filter, List<BroadcastFilter> dest) {
629 IBinder target = filter.receiverList.receiver.asBinder();
630 for (int i=dest.size()-1; i>=0; i--) {
631 if (dest.get(i).receiverList.receiver.asBinder() == target) {
632 return false;
633 }
634 }
635 return true;
636 }
637 };
638
639 /**
640 * State of all active sticky broadcasts. Keys are the action of the
641 * sticky Intent, values are an ArrayList of all broadcasted intents with
642 * that action (which should usually be one).
643 */
644 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
645 new HashMap<String, ArrayList<Intent>>();
646
647 /**
648 * All currently running services.
649 */
650 final HashMap<ComponentName, ServiceRecord> mServices =
651 new HashMap<ComponentName, ServiceRecord>();
652
653 /**
654 * All currently running services indexed by the Intent used to start them.
655 */
656 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
657 new HashMap<Intent.FilterComparison, ServiceRecord>();
658
659 /**
660 * All currently bound service connections. Keys are the IBinder of
661 * the client's IServiceConnection.
662 */
663 final HashMap<IBinder, ConnectionRecord> mServiceConnections
664 = new HashMap<IBinder, ConnectionRecord>();
665
666 /**
667 * List of services that we have been asked to start,
668 * but haven't yet been able to. It is used to hold start requests
669 * while waiting for their corresponding application thread to get
670 * going.
671 */
672 final ArrayList<ServiceRecord> mPendingServices
673 = new ArrayList<ServiceRecord>();
674
675 /**
676 * List of services that are scheduled to restart following a crash.
677 */
678 final ArrayList<ServiceRecord> mRestartingServices
679 = new ArrayList<ServiceRecord>();
680
681 /**
682 * List of services that are in the process of being stopped.
683 */
684 final ArrayList<ServiceRecord> mStoppingServices
685 = new ArrayList<ServiceRecord>();
686
687 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700688 * Backup/restore process management
689 */
690 String mBackupAppName = null;
691 BackupRecord mBackupTarget = null;
692
693 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 * List of PendingThumbnailsRecord objects of clients who are still
695 * waiting to receive all of the thumbnails for a task.
696 */
697 final ArrayList mPendingThumbnails = new ArrayList();
698
699 /**
700 * List of HistoryRecord objects that have been finished and must
701 * still report back to a pending thumbnail receiver.
702 */
703 final ArrayList mCancelledThumbnails = new ArrayList();
704
705 /**
706 * All of the currently running global content providers. Keys are a
707 * string containing the provider name and values are a
708 * ContentProviderRecord object containing the data about it. Note
709 * that a single provider may be published under multiple names, so
710 * there may be multiple entries here for a single one in mProvidersByClass.
711 */
712 final HashMap mProvidersByName = new HashMap();
713
714 /**
715 * All of the currently running global content providers. Keys are a
716 * string containing the provider's implementation class and values are a
717 * ContentProviderRecord object containing the data about it.
718 */
719 final HashMap mProvidersByClass = new HashMap();
720
721 /**
722 * List of content providers who have clients waiting for them. The
723 * application is currently being launched and the provider will be
724 * removed from this list once it is published.
725 */
726 final ArrayList mLaunchingProviders = new ArrayList();
727
728 /**
729 * Global set of specific Uri permissions that have been granted.
730 */
731 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
732 = new SparseArray<HashMap<Uri, UriPermission>>();
733
734 /**
735 * Thread-local storage used to carry caller permissions over through
736 * indirect content-provider access.
737 * @see #ActivityManagerService.openContentUri()
738 */
739 private class Identity {
740 public int pid;
741 public int uid;
742
743 Identity(int _pid, int _uid) {
744 pid = _pid;
745 uid = _uid;
746 }
747 }
748 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
749
750 /**
751 * All information we have collected about the runtime performance of
752 * any user id that can impact battery performance.
753 */
754 final BatteryStatsService mBatteryStatsService;
755
756 /**
757 * information about component usage
758 */
759 final UsageStatsService mUsageStatsService;
760
761 /**
762 * Current configuration information. HistoryRecord objects are given
763 * a reference to this object to indicate which configuration they are
764 * currently running in, so this object must be kept immutable.
765 */
766 Configuration mConfiguration = new Configuration();
767
768 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700769 * Hardware-reported OpenGLES version.
770 */
771 final int GL_ES_VERSION;
772
773 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 * List of initialization arguments to pass to all processes when binding applications to them.
775 * For example, references to the commonly used services.
776 */
777 HashMap<String, IBinder> mAppBindArgs;
778
779 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700780 * Temporary to avoid allocations. Protected by main lock.
781 */
782 final StringBuilder mStringBuilder = new StringBuilder(256);
783
784 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 * Used to control how we initialize the service.
786 */
787 boolean mStartRunning = false;
788 ComponentName mTopComponent;
789 String mTopAction;
790 String mTopData;
791 boolean mSystemReady = false;
792 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700793 boolean mWaitingUpdate = false;
794 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795
796 Context mContext;
797
798 int mFactoryTest;
799
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700800 boolean mCheckedForSetup;
801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700803 * The time at which we will allow normal application switches again,
804 * after a call to {@link #stopAppSwitches()}.
805 */
806 long mAppSwitchesAllowedTime;
807
808 /**
809 * This is set to true after the first switch after mAppSwitchesAllowedTime
810 * is set; any switches after that will clear the time.
811 */
812 boolean mDidAppSwitch;
813
814 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 * Set while we are wanting to sleep, to prevent any
816 * activities from being started/resumed.
817 */
818 boolean mSleeping = false;
819
820 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700821 * Set if we are shutting down the system, similar to sleeping.
822 */
823 boolean mShuttingDown = false;
824
825 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 * Set when the system is going to sleep, until we have
827 * successfully paused the current activity and released our wake lock.
828 * At that point the system is allowed to actually sleep.
829 */
830 PowerManager.WakeLock mGoingToSleep;
831
832 /**
833 * We don't want to allow the device to go to sleep while in the process
834 * of launching an activity. This is primarily to allow alarm intent
835 * receivers to launch an activity and get that to run before the device
836 * goes back to sleep.
837 */
838 PowerManager.WakeLock mLaunchingActivity;
839
840 /**
841 * Task identifier that activities are currently being started
842 * in. Incremented each time a new task is created.
843 * todo: Replace this with a TokenSpace class that generates non-repeating
844 * integers that won't wrap.
845 */
846 int mCurTask = 1;
847
848 /**
849 * Current sequence id for oom_adj computation traversal.
850 */
851 int mAdjSeq = 0;
852
853 /**
854 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
855 * is set, indicating the user wants processes started in such a way
856 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
857 * running in each process (thus no pre-initialized process, etc).
858 */
859 boolean mSimpleProcessManagement = false;
860
861 /**
862 * System monitoring: number of processes that died since the last
863 * N procs were started.
864 */
865 int[] mProcDeaths = new int[20];
866
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700867 /**
868 * This is set if we had to do a delayed dexopt of an app before launching
869 * it, to increasing the ANR timeouts in that case.
870 */
871 boolean mDidDexOpt;
872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 String mDebugApp = null;
874 boolean mWaitForDebugger = false;
875 boolean mDebugTransient = false;
876 String mOrigDebugApp = null;
877 boolean mOrigWaitForDebugger = false;
878 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700879 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700881 final RemoteCallbackList<IActivityWatcher> mWatchers
882 = new RemoteCallbackList<IActivityWatcher>();
883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 /**
885 * Callback of last caller to {@link #requestPss}.
886 */
887 Runnable mRequestPssCallback;
888
889 /**
890 * Remaining processes for which we are waiting results from the last
891 * call to {@link #requestPss}.
892 */
893 final ArrayList<ProcessRecord> mRequestPssList
894 = new ArrayList<ProcessRecord>();
895
896 /**
897 * Runtime statistics collection thread. This object's lock is used to
898 * protect all related state.
899 */
900 final Thread mProcessStatsThread;
901
902 /**
903 * Used to collect process stats when showing not responding dialog.
904 * Protected by mProcessStatsThread.
905 */
906 final ProcessStats mProcessStats = new ProcessStats(
907 MONITOR_THREAD_CPU_USAGE);
908 long mLastCpuTime = 0;
909 long mLastWriteTime = 0;
910
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700911 long mInitialStartTime = 0;
912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 /**
914 * Set to true after the system has finished booting.
915 */
916 boolean mBooted = false;
917
918 int mProcessLimit = 0;
919
920 WindowManagerService mWindowManager;
921
922 static ActivityManagerService mSelf;
923 static ActivityThread mSystemThread;
924
925 private final class AppDeathRecipient implements IBinder.DeathRecipient {
926 final ProcessRecord mApp;
927 final int mPid;
928 final IApplicationThread mAppThread;
929
930 AppDeathRecipient(ProcessRecord app, int pid,
931 IApplicationThread thread) {
932 if (localLOGV) Log.v(
933 TAG, "New death recipient " + this
934 + " for thread " + thread.asBinder());
935 mApp = app;
936 mPid = pid;
937 mAppThread = thread;
938 }
939
940 public void binderDied() {
941 if (localLOGV) Log.v(
942 TAG, "Death received in " + this
943 + " for thread " + mAppThread.asBinder());
944 removeRequestedPss(mApp);
945 synchronized(ActivityManagerService.this) {
946 appDiedLocked(mApp, mPid, mAppThread);
947 }
948 }
949 }
950
951 static final int SHOW_ERROR_MSG = 1;
952 static final int SHOW_NOT_RESPONDING_MSG = 2;
953 static final int SHOW_FACTORY_ERROR_MSG = 3;
954 static final int UPDATE_CONFIGURATION_MSG = 4;
955 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
956 static final int WAIT_FOR_DEBUGGER_MSG = 6;
957 static final int BROADCAST_INTENT_MSG = 7;
958 static final int BROADCAST_TIMEOUT_MSG = 8;
959 static final int PAUSE_TIMEOUT_MSG = 9;
960 static final int IDLE_TIMEOUT_MSG = 10;
961 static final int IDLE_NOW_MSG = 11;
962 static final int SERVICE_TIMEOUT_MSG = 12;
963 static final int UPDATE_TIME_ZONE = 13;
964 static final int SHOW_UID_ERROR_MSG = 14;
965 static final int IM_FEELING_LUCKY_MSG = 15;
966 static final int LAUNCH_TIMEOUT_MSG = 16;
967 static final int DESTROY_TIMEOUT_MSG = 17;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 static final int RESUME_TOP_ACTIVITY_MSG = 19;
969 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700970 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700971 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972
973 AlertDialog mUidAlert;
974
975 final Handler mHandler = new Handler() {
976 //public Handler() {
977 // if (localLOGV) Log.v(TAG, "Handler started!");
978 //}
979
980 public void handleMessage(Message msg) {
981 switch (msg.what) {
982 case SHOW_ERROR_MSG: {
983 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 synchronized (ActivityManagerService.this) {
985 ProcessRecord proc = (ProcessRecord)data.get("app");
986 if (proc != null && proc.crashDialog != null) {
987 Log.e(TAG, "App already has crash dialog: " + proc);
988 return;
989 }
990 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700991 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -0800992 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 d.show();
994 proc.crashDialog = d;
995 } else {
996 // The device is asleep, so just pretend that the user
997 // saw a crash dialog and hit "force quit".
998 res.set(0);
999 }
1000 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001001
1002 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 } break;
1004 case SHOW_NOT_RESPONDING_MSG: {
1005 synchronized (ActivityManagerService.this) {
1006 HashMap data = (HashMap) msg.obj;
1007 ProcessRecord proc = (ProcessRecord)data.get("app");
1008 if (proc != null && proc.anrDialog != null) {
1009 Log.e(TAG, "App already has anr dialog: " + proc);
1010 return;
1011 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001012
1013 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1014 null, null, 0, null, null, null,
1015 false, false, MY_PID, Process.SYSTEM_UID);
1016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1018 mContext, proc, (HistoryRecord)data.get("activity"));
1019 d.show();
1020 proc.anrDialog = d;
1021 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001022
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001023 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 } break;
1025 case SHOW_FACTORY_ERROR_MSG: {
1026 Dialog d = new FactoryErrorDialog(
1027 mContext, msg.getData().getCharSequence("msg"));
1028 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001029 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 } break;
1031 case UPDATE_CONFIGURATION_MSG: {
1032 final ContentResolver resolver = mContext.getContentResolver();
1033 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1034 } break;
1035 case GC_BACKGROUND_PROCESSES_MSG: {
1036 synchronized (ActivityManagerService.this) {
1037 performAppGcsIfAppropriateLocked();
1038 }
1039 } break;
1040 case WAIT_FOR_DEBUGGER_MSG: {
1041 synchronized (ActivityManagerService.this) {
1042 ProcessRecord app = (ProcessRecord)msg.obj;
1043 if (msg.arg1 != 0) {
1044 if (!app.waitedForDebugger) {
1045 Dialog d = new AppWaitingForDebuggerDialog(
1046 ActivityManagerService.this,
1047 mContext, app);
1048 app.waitDialog = d;
1049 app.waitedForDebugger = true;
1050 d.show();
1051 }
1052 } else {
1053 if (app.waitDialog != null) {
1054 app.waitDialog.dismiss();
1055 app.waitDialog = null;
1056 }
1057 }
1058 }
1059 } break;
1060 case BROADCAST_INTENT_MSG: {
1061 if (DEBUG_BROADCAST) Log.v(
1062 TAG, "Received BROADCAST_INTENT_MSG");
1063 processNextBroadcast(true);
1064 } break;
1065 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001066 if (mDidDexOpt) {
1067 mDidDexOpt = false;
1068 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1069 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1070 return;
1071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 broadcastTimeout();
1073 } break;
1074 case PAUSE_TIMEOUT_MSG: {
1075 IBinder token = (IBinder)msg.obj;
1076 // We don't at this point know if the activity is fullscreen,
1077 // so we need to be conservative and assume it isn't.
1078 Log.w(TAG, "Activity pause timeout for " + token);
1079 activityPaused(token, null, true);
1080 } break;
1081 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001082 if (mDidDexOpt) {
1083 mDidDexOpt = false;
1084 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1085 nmsg.obj = msg.obj;
1086 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1087 return;
1088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 // We don't at this point know if the activity is fullscreen,
1090 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001091 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001093 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 } break;
1095 case DESTROY_TIMEOUT_MSG: {
1096 IBinder token = (IBinder)msg.obj;
1097 // We don't at this point know if the activity is fullscreen,
1098 // so we need to be conservative and assume it isn't.
1099 Log.w(TAG, "Activity destroy timeout for " + token);
1100 activityDestroyed(token);
1101 } break;
1102 case IDLE_NOW_MSG: {
1103 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001104 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 } break;
1106 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001107 if (mDidDexOpt) {
1108 mDidDexOpt = false;
1109 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1110 nmsg.obj = msg.obj;
1111 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1112 return;
1113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 serviceTimeout((ProcessRecord)msg.obj);
1115 } break;
1116 case UPDATE_TIME_ZONE: {
1117 synchronized (ActivityManagerService.this) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001118 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
1119 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 if (r.thread != null) {
1121 try {
1122 r.thread.updateTimeZone();
1123 } catch (RemoteException ex) {
1124 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1125 }
1126 }
1127 }
1128 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001129 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 case SHOW_UID_ERROR_MSG: {
1131 // XXX This is a temporary dialog, no need to localize.
1132 AlertDialog d = new BaseErrorDialog(mContext);
1133 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1134 d.setCancelable(false);
1135 d.setTitle("System UIDs Inconsistent");
1136 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1137 d.setButton("I'm Feeling Lucky",
1138 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1139 mUidAlert = d;
1140 d.show();
1141 } break;
1142 case IM_FEELING_LUCKY_MSG: {
1143 if (mUidAlert != null) {
1144 mUidAlert.dismiss();
1145 mUidAlert = null;
1146 }
1147 } break;
1148 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001149 if (mDidDexOpt) {
1150 mDidDexOpt = false;
1151 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1152 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1153 return;
1154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 synchronized (ActivityManagerService.this) {
1156 if (mLaunchingActivity.isHeld()) {
1157 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1158 mLaunchingActivity.release();
1159 }
1160 }
1161 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 case RESUME_TOP_ACTIVITY_MSG: {
1163 synchronized (ActivityManagerService.this) {
1164 resumeTopActivityLocked(null);
1165 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001166 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001168 if (mDidDexOpt) {
1169 mDidDexOpt = false;
1170 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1171 nmsg.obj = msg.obj;
1172 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1173 return;
1174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 ProcessRecord app = (ProcessRecord)msg.obj;
1176 synchronized (ActivityManagerService.this) {
1177 processStartTimedOutLocked(app);
1178 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001179 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001180 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1181 synchronized (ActivityManagerService.this) {
1182 doPendingActivityLaunchesLocked(true);
1183 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001184 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001185 case KILL_APPLICATION_MSG: {
1186 synchronized (ActivityManagerService.this) {
1187 int uid = msg.arg1;
1188 boolean restart = (msg.arg2 == 1);
1189 String pkg = (String) msg.obj;
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001190 forceStopPackageLocked(pkg, uid, restart, false);
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001191 }
1192 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
1194 }
1195 };
1196
1197 public static void setSystemProcess() {
1198 try {
1199 ActivityManagerService m = mSelf;
1200
1201 ServiceManager.addService("activity", m);
1202 ServiceManager.addService("meminfo", new MemBinder(m));
1203 if (MONITOR_CPU_USAGE) {
1204 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 ServiceManager.addService("permission", new PermissionController(m));
1207
1208 ApplicationInfo info =
1209 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001210 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001211 mSystemThread.installSystemApplicationInfo(info);
1212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 synchronized (mSelf) {
1214 ProcessRecord app = mSelf.newProcessRecordLocked(
1215 mSystemThread.getApplicationThread(), info,
1216 info.processName);
1217 app.persistent = true;
Dan Egnor42471dd2010-01-07 17:25:22 -08001218 app.pid = MY_PID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 app.maxAdj = SYSTEM_ADJ;
1220 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1221 synchronized (mSelf.mPidsSelfLocked) {
1222 mSelf.mPidsSelfLocked.put(app.pid, app);
1223 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001224 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 }
1226 } catch (PackageManager.NameNotFoundException e) {
1227 throw new RuntimeException(
1228 "Unable to find android system package", e);
1229 }
1230 }
1231
1232 public void setWindowManager(WindowManagerService wm) {
1233 mWindowManager = wm;
1234 }
1235
1236 public static final Context main(int factoryTest) {
1237 AThread thr = new AThread();
1238 thr.start();
1239
1240 synchronized (thr) {
1241 while (thr.mService == null) {
1242 try {
1243 thr.wait();
1244 } catch (InterruptedException e) {
1245 }
1246 }
1247 }
1248
1249 ActivityManagerService m = thr.mService;
1250 mSelf = m;
1251 ActivityThread at = ActivityThread.systemMain();
1252 mSystemThread = at;
1253 Context context = at.getSystemContext();
1254 m.mContext = context;
1255 m.mFactoryTest = factoryTest;
1256 PowerManager pm =
1257 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1258 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1259 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1260 m.mLaunchingActivity.setReferenceCounted(false);
1261
1262 m.mBatteryStatsService.publish(context);
1263 m.mUsageStatsService.publish(context);
1264
1265 synchronized (thr) {
1266 thr.mReady = true;
1267 thr.notifyAll();
1268 }
1269
1270 m.startRunning(null, null, null, null);
1271
1272 return context;
1273 }
1274
1275 public static ActivityManagerService self() {
1276 return mSelf;
1277 }
1278
1279 static class AThread extends Thread {
1280 ActivityManagerService mService;
1281 boolean mReady = false;
1282
1283 public AThread() {
1284 super("ActivityManager");
1285 }
1286
1287 public void run() {
1288 Looper.prepare();
1289
1290 android.os.Process.setThreadPriority(
1291 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1292
1293 ActivityManagerService m = new ActivityManagerService();
1294
1295 synchronized (this) {
1296 mService = m;
1297 notifyAll();
1298 }
1299
1300 synchronized (this) {
1301 while (!mReady) {
1302 try {
1303 wait();
1304 } catch (InterruptedException e) {
1305 }
1306 }
1307 }
1308
1309 Looper.loop();
1310 }
1311 }
1312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 static class MemBinder extends Binder {
1314 ActivityManagerService mActivityManagerService;
1315 MemBinder(ActivityManagerService activityManagerService) {
1316 mActivityManagerService = activityManagerService;
1317 }
1318
1319 @Override
1320 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1321 ActivityManagerService service = mActivityManagerService;
1322 ArrayList<ProcessRecord> procs;
1323 synchronized (mActivityManagerService) {
1324 if (args != null && args.length > 0
1325 && args[0].charAt(0) != '-') {
1326 procs = new ArrayList<ProcessRecord>();
1327 int pid = -1;
1328 try {
1329 pid = Integer.parseInt(args[0]);
1330 } catch (NumberFormatException e) {
1331
1332 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001333 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1334 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 if (proc.pid == pid) {
1336 procs.add(proc);
1337 } else if (proc.processName.equals(args[0])) {
1338 procs.add(proc);
1339 }
1340 }
1341 if (procs.size() <= 0) {
1342 pw.println("No process found for: " + args[0]);
1343 return;
1344 }
1345 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001346 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 }
1348 }
1349 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1350 }
1351 }
1352
1353 static class CpuBinder extends Binder {
1354 ActivityManagerService mActivityManagerService;
1355 CpuBinder(ActivityManagerService activityManagerService) {
1356 mActivityManagerService = activityManagerService;
1357 }
1358
1359 @Override
1360 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1361 synchronized (mActivityManagerService.mProcessStatsThread) {
1362 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1363 }
1364 }
1365 }
1366
1367 private ActivityManagerService() {
1368 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1369 if (v != null && Integer.getInteger(v) != 0) {
1370 mSimpleProcessManagement = true;
1371 }
1372 v = System.getenv("ANDROID_DEBUG_APP");
1373 if (v != null) {
1374 mSimpleProcessManagement = true;
1375 }
1376
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001377 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 File dataDir = Environment.getDataDirectory();
1380 File systemDir = new File(dataDir, "system");
1381 systemDir.mkdirs();
1382 mBatteryStatsService = new BatteryStatsService(new File(
1383 systemDir, "batterystats.bin").toString());
1384 mBatteryStatsService.getActiveStatistics().readLocked();
1385 mBatteryStatsService.getActiveStatistics().writeLocked();
1386
1387 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001388 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389
Jack Palevichb90d28c2009-07-22 15:35:24 -07001390 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1391 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 mConfiguration.makeDefault();
1394 mProcessStats.init();
1395
1396 // Add ourself to the Watchdog monitors.
1397 Watchdog.getInstance().addMonitor(this);
1398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 mProcessStatsThread = new Thread("ProcessStats") {
1400 public void run() {
1401 while (true) {
1402 try {
1403 try {
1404 synchronized(this) {
1405 final long now = SystemClock.uptimeMillis();
1406 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1407 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1408 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1409 // + ", write delay=" + nextWriteDelay);
1410 if (nextWriteDelay < nextCpuDelay) {
1411 nextCpuDelay = nextWriteDelay;
1412 }
1413 if (nextCpuDelay > 0) {
1414 this.wait(nextCpuDelay);
1415 }
1416 }
1417 } catch (InterruptedException e) {
1418 }
1419
1420 updateCpuStatsNow();
1421 } catch (Exception e) {
1422 Log.e(TAG, "Unexpected exception collecting process stats", e);
1423 }
1424 }
1425 }
1426 };
1427 mProcessStatsThread.start();
1428 }
1429
1430 @Override
1431 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1432 throws RemoteException {
1433 try {
1434 return super.onTransact(code, data, reply, flags);
1435 } catch (RuntimeException e) {
1436 // The activity manager only throws security exceptions, so let's
1437 // log all others.
1438 if (!(e instanceof SecurityException)) {
1439 Log.e(TAG, "Activity Manager Crash", e);
1440 }
1441 throw e;
1442 }
1443 }
1444
1445 void updateCpuStats() {
1446 synchronized (mProcessStatsThread) {
1447 final long now = SystemClock.uptimeMillis();
1448 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1449 mProcessStatsThread.notify();
1450 }
1451 }
1452 }
1453
1454 void updateCpuStatsNow() {
1455 synchronized (mProcessStatsThread) {
1456 final long now = SystemClock.uptimeMillis();
1457 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 if (MONITOR_CPU_USAGE &&
1460 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1461 mLastCpuTime = now;
1462 haveNewCpuStats = true;
1463 mProcessStats.update();
1464 //Log.i(TAG, mProcessStats.printCurrentState());
1465 //Log.i(TAG, "Total CPU usage: "
1466 // + mProcessStats.getTotalCpuPercent() + "%");
1467
1468 // Log the cpu usage if the property is set.
1469 if ("true".equals(SystemProperties.get("events.cpu"))) {
1470 int user = mProcessStats.getLastUserTime();
1471 int system = mProcessStats.getLastSystemTime();
1472 int iowait = mProcessStats.getLastIoWaitTime();
1473 int irq = mProcessStats.getLastIrqTime();
1474 int softIrq = mProcessStats.getLastSoftIrqTime();
1475 int idle = mProcessStats.getLastIdleTime();
1476
1477 int total = user + system + iowait + irq + softIrq + idle;
1478 if (total == 0) total = 1;
1479
Doug Zongker2bec3d42009-12-04 12:52:44 -08001480 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 ((user+system+iowait+irq+softIrq) * 100) / total,
1482 (user * 100) / total,
1483 (system * 100) / total,
1484 (iowait * 100) / total,
1485 (irq * 100) / total,
1486 (softIrq * 100) / total);
1487 }
1488 }
1489
Amith Yamasanie43530a2009-08-21 13:11:37 -07001490 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001491 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001492 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 synchronized(mPidsSelfLocked) {
1494 if (haveNewCpuStats) {
1495 if (mBatteryStatsService.isOnBattery()) {
1496 final int N = mProcessStats.countWorkingStats();
1497 for (int i=0; i<N; i++) {
1498 ProcessStats.Stats st
1499 = mProcessStats.getWorkingStats(i);
1500 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1501 if (pr != null) {
1502 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1503 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001504 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001505 } else {
1506 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001507 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001508 if (ps != null) {
1509 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001510 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001511 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 }
1513 }
1514 }
1515 }
1516 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1519 mLastWriteTime = now;
1520 mBatteryStatsService.getActiveStatistics().writeLocked();
1521 }
1522 }
1523 }
1524 }
1525
1526 /**
1527 * Initialize the application bind args. These are passed to each
1528 * process when the bindApplication() IPC is sent to the process. They're
1529 * lazily setup to make sure the services are running when they're asked for.
1530 */
1531 private HashMap<String, IBinder> getCommonServicesLocked() {
1532 if (mAppBindArgs == null) {
1533 mAppBindArgs = new HashMap<String, IBinder>();
1534
1535 // Setup the application init args
1536 mAppBindArgs.put("package", ServiceManager.getService("package"));
1537 mAppBindArgs.put("window", ServiceManager.getService("window"));
1538 mAppBindArgs.put(Context.ALARM_SERVICE,
1539 ServiceManager.getService(Context.ALARM_SERVICE));
1540 }
1541 return mAppBindArgs;
1542 }
1543
1544 private final void setFocusedActivityLocked(HistoryRecord r) {
1545 if (mFocusedActivity != r) {
1546 mFocusedActivity = r;
1547 mWindowManager.setFocusedApp(r, true);
1548 }
1549 }
1550
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001551 private final void updateLruProcessLocked(ProcessRecord app,
1552 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001554 int lrui = mLruProcesses.indexOf(app);
1555 if (lrui >= 0) mLruProcesses.remove(lrui);
1556
1557 int i = mLruProcesses.size()-1;
1558 int skipTop = 0;
1559
1560 // compute the new weight for this process.
1561 if (updateActivityTime) {
1562 app.lastActivityTime = SystemClock.uptimeMillis();
1563 }
1564 if (app.activities.size() > 0) {
1565 // If this process has activities, we more strongly want to keep
1566 // it around.
1567 app.lruWeight = app.lastActivityTime;
1568 } else if (app.pubProviders.size() > 0) {
1569 // If this process contains content providers, we want to keep
1570 // it a little more strongly.
1571 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1572 // Also don't let it kick out the first few "real" hidden processes.
1573 skipTop = MIN_HIDDEN_APPS;
1574 } else {
1575 // If this process doesn't have activities, we less strongly
1576 // want to keep it around, and generally want to avoid getting
1577 // in front of any very recently used activities.
1578 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1579 // Also don't let it kick out the first few "real" hidden processes.
1580 skipTop = MIN_HIDDEN_APPS;
1581 }
1582 while (i >= 0) {
1583 ProcessRecord p = mLruProcesses.get(i);
1584 // If this app shouldn't be in front of the first N background
1585 // apps, then skip over that many that are currently hidden.
1586 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1587 skipTop--;
1588 }
1589 if (p.lruWeight <= app.lruWeight){
1590 mLruProcesses.add(i+1, app);
1591 break;
1592 }
1593 i--;
1594 }
1595 if (i < 0) {
1596 mLruProcesses.add(0, app);
1597 }
1598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 //Log.i(TAG, "Putting proc to front: " + app.processName);
1600 if (oomAdj) {
1601 updateOomAdjLocked();
1602 }
1603 }
1604
1605 private final boolean updateLRUListLocked(HistoryRecord r) {
1606 final boolean hadit = mLRUActivities.remove(r);
1607 mLRUActivities.add(r);
1608 return hadit;
1609 }
1610
1611 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1612 int i = mHistory.size()-1;
1613 while (i >= 0) {
1614 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1615 if (!r.finishing && r != notTop) {
1616 return r;
1617 }
1618 i--;
1619 }
1620 return null;
1621 }
1622
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001623 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1624 int i = mHistory.size()-1;
1625 while (i >= 0) {
1626 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1627 if (!r.finishing && !r.delayedResume && r != notTop) {
1628 return r;
1629 }
1630 i--;
1631 }
1632 return null;
1633 }
1634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 /**
1636 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001637 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638 *
1639 * @param token If non-null, any history records matching this token will be skipped.
1640 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1641 *
1642 * @return Returns the HistoryRecord of the next activity on the stack.
1643 */
1644 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1645 int i = mHistory.size()-1;
1646 while (i >= 0) {
1647 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1648 // Note: the taskId check depends on real taskId fields being non-zero
1649 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1650 return r;
1651 }
1652 i--;
1653 }
1654 return null;
1655 }
1656
1657 private final ProcessRecord getProcessRecordLocked(
1658 String processName, int uid) {
1659 if (uid == Process.SYSTEM_UID) {
1660 // The system gets to run in any process. If there are multiple
1661 // processes with the same uid, just pick the first (this
1662 // should never happen).
1663 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1664 processName);
1665 return procs != null ? procs.valueAt(0) : null;
1666 }
1667 ProcessRecord proc = mProcessNames.get(processName, uid);
1668 return proc;
1669 }
1670
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001671 private void ensurePackageDexOpt(String packageName) {
1672 IPackageManager pm = ActivityThread.getPackageManager();
1673 try {
1674 if (pm.performDexOpt(packageName)) {
1675 mDidDexOpt = true;
1676 }
1677 } catch (RemoteException e) {
1678 }
1679 }
1680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 private boolean isNextTransitionForward() {
1682 int transit = mWindowManager.getPendingAppTransition();
1683 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1684 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1685 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1686 }
1687
1688 private final boolean realStartActivityLocked(HistoryRecord r,
1689 ProcessRecord app, boolean andResume, boolean checkConfig)
1690 throws RemoteException {
1691
1692 r.startFreezingScreenLocked(app, 0);
1693 mWindowManager.setAppVisibility(r, true);
1694
1695 // Have the window manager re-evaluate the orientation of
1696 // the screen based on the new activity order. Note that
1697 // as a result of this, it can call back into the activity
1698 // manager with a new orientation. We don't care about that,
1699 // because the activity is not currently running so we are
1700 // just restarting it anyway.
1701 if (checkConfig) {
1702 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001703 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 r.mayFreezeScreenLocked(app) ? r : null);
1705 updateConfigurationLocked(config, r);
1706 }
1707
1708 r.app = app;
1709
1710 if (localLOGV) Log.v(TAG, "Launching: " + r);
1711
1712 int idx = app.activities.indexOf(r);
1713 if (idx < 0) {
1714 app.activities.add(r);
1715 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001716 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717
1718 try {
1719 if (app.thread == null) {
1720 throw new RemoteException();
1721 }
1722 List<ResultInfo> results = null;
1723 List<Intent> newIntents = null;
1724 if (andResume) {
1725 results = r.results;
1726 newIntents = r.newIntents;
1727 }
1728 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1729 + " icicle=" + r.icicle
1730 + " with results=" + results + " newIntents=" + newIntents
1731 + " andResume=" + andResume);
1732 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001733 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 System.identityHashCode(r),
1735 r.task.taskId, r.shortComponentName);
1736 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001737 if (r.isHomeActivity) {
1738 mHomeProcess = app;
1739 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001740 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001742 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 r.info, r.icicle, results, newIntents, !andResume,
1744 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 } catch (RemoteException e) {
1746 if (r.launchFailed) {
1747 // This is the second time we failed -- finish activity
1748 // and give up.
1749 Log.e(TAG, "Second failure launching "
1750 + r.intent.getComponent().flattenToShortString()
1751 + ", giving up", e);
1752 appDiedLocked(app, app.pid, app.thread);
1753 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1754 "2nd-crash");
1755 return false;
1756 }
1757
1758 // This is the first time we failed -- restart process and
1759 // retry.
1760 app.activities.remove(r);
1761 throw e;
1762 }
1763
1764 r.launchFailed = false;
1765 if (updateLRUListLocked(r)) {
1766 Log.w(TAG, "Activity " + r
1767 + " being launched, but already in LRU list");
1768 }
1769
1770 if (andResume) {
1771 // As part of the process of launching, ActivityThread also performs
1772 // a resume.
1773 r.state = ActivityState.RESUMED;
1774 r.icicle = null;
1775 r.haveState = false;
1776 r.stopped = false;
1777 mResumedActivity = r;
1778 r.task.touchActiveTime();
1779 completeResumeLocked(r);
1780 pauseIfSleepingLocked();
1781 } else {
1782 // This activity is not starting in the resumed state... which
1783 // should look like we asked it to pause+stop (but remain visible),
1784 // and it has done so and reported back the current icicle and
1785 // other state.
1786 r.state = ActivityState.STOPPED;
1787 r.stopped = true;
1788 }
1789
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001790 // Launch the new version setup screen if needed. We do this -after-
1791 // launching the initial activity (that is, home), so that it can have
1792 // a chance to initialize itself while in the background, making the
1793 // switch back to it faster and look better.
1794 startSetupActivityLocked();
1795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 return true;
1797 }
1798
1799 private final void startSpecificActivityLocked(HistoryRecord r,
1800 boolean andResume, boolean checkConfig) {
1801 // Is this activity's application already running?
1802 ProcessRecord app = getProcessRecordLocked(r.processName,
1803 r.info.applicationInfo.uid);
1804
1805 if (r.startTime == 0) {
1806 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001807 if (mInitialStartTime == 0) {
1808 mInitialStartTime = r.startTime;
1809 }
1810 } else if (mInitialStartTime == 0) {
1811 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 }
1813
1814 if (app != null && app.thread != null) {
1815 try {
1816 realStartActivityLocked(r, app, andResume, checkConfig);
1817 return;
1818 } catch (RemoteException e) {
1819 Log.w(TAG, "Exception when starting activity "
1820 + r.intent.getComponent().flattenToShortString(), e);
1821 }
1822
1823 // If a dead object exception was thrown -- fall through to
1824 // restart the application.
1825 }
1826
1827 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001828 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 }
1830
1831 private final ProcessRecord startProcessLocked(String processName,
1832 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001833 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1835 // We don't have to do anything more if:
1836 // (1) There is an existing application record; and
1837 // (2) The caller doesn't think it is dead, OR there is no thread
1838 // object attached to it so we know it couldn't have crashed; and
1839 // (3) There is a pid assigned to it, so it is either starting or
1840 // already running.
1841 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1842 + " app=" + app + " knownToBeDead=" + knownToBeDead
1843 + " thread=" + (app != null ? app.thread : null)
1844 + " pid=" + (app != null ? app.pid : -1));
1845 if (app != null &&
1846 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1847 return app;
1848 }
1849
1850 String hostingNameStr = hostingName != null
1851 ? hostingName.flattenToShortString() : null;
1852
1853 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1854 // If we are in the background, then check to see if this process
1855 // is bad. If so, we will just silently fail.
1856 if (mBadProcesses.get(info.processName, info.uid) != null) {
1857 return null;
1858 }
1859 } else {
1860 // When the user is explicitly starting a process, then clear its
1861 // crash count so that we won't make it bad until they see at
1862 // least one crash dialog again, and make the process good again
1863 // if it had been bad.
1864 mProcessCrashTimes.remove(info.processName, info.uid);
1865 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001866 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 info.processName);
1868 mBadProcesses.remove(info.processName, info.uid);
1869 if (app != null) {
1870 app.bad = false;
1871 }
1872 }
1873 }
1874
1875 if (app == null) {
1876 app = newProcessRecordLocked(null, info, processName);
1877 mProcessNames.put(processName, info.uid, app);
1878 } else {
1879 // If this is a new package in the process, add the package to the list
1880 app.addPackage(info.packageName);
1881 }
1882
1883 // If the system is not ready yet, then hold off on starting this
1884 // process until it is.
1885 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001886 && !isAllowedWhileBooting(info)
1887 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 if (!mProcessesOnHold.contains(app)) {
1889 mProcessesOnHold.add(app);
1890 }
1891 return app;
1892 }
1893
1894 startProcessLocked(app, hostingType, hostingNameStr);
1895 return (app.pid != 0) ? app : null;
1896 }
1897
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001898 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1899 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1900 }
1901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 private final void startProcessLocked(ProcessRecord app,
1903 String hostingType, String hostingNameStr) {
1904 if (app.pid > 0 && app.pid != MY_PID) {
1905 synchronized (mPidsSelfLocked) {
1906 mPidsSelfLocked.remove(app.pid);
1907 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1908 }
1909 app.pid = 0;
1910 }
1911
1912 mProcessesOnHold.remove(app);
1913
1914 updateCpuStats();
1915
1916 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1917 mProcDeaths[0] = 0;
1918
1919 try {
1920 int uid = app.info.uid;
1921 int[] gids = null;
1922 try {
1923 gids = mContext.getPackageManager().getPackageGids(
1924 app.info.packageName);
1925 } catch (PackageManager.NameNotFoundException e) {
1926 Log.w(TAG, "Unable to retrieve gids", e);
1927 }
1928 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1929 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1930 && mTopComponent != null
1931 && app.processName.equals(mTopComponent.getPackageName())) {
1932 uid = 0;
1933 }
1934 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1935 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1936 uid = 0;
1937 }
1938 }
1939 int debugFlags = 0;
1940 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1941 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1942 }
Ben Cheng6c0afff2010-02-14 16:18:56 -08001943 // Run the app in safe mode if its manifest requests so or the
1944 // system is booted in safe mode.
1945 if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
1946 Zygote.systemInSafeMode == true) {
Ben Cheng23085b72010-02-08 16:06:32 -08001947 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
1948 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001949 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1950 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1951 }
1952 if ("1".equals(SystemProperties.get("debug.assert"))) {
1953 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1954 }
1955 int pid = Process.start("android.app.ActivityThread",
1956 mSimpleProcessManagement ? app.processName : null, uid, uid,
1957 gids, debugFlags, null);
1958 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1959 synchronized (bs) {
1960 if (bs.isOnBattery()) {
1961 app.batteryStats.incStartsLocked();
1962 }
1963 }
1964
Doug Zongker2bec3d42009-12-04 12:52:44 -08001965 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 app.processName, hostingType,
1967 hostingNameStr != null ? hostingNameStr : "");
1968
1969 if (app.persistent) {
1970 Watchdog.getInstance().processStarted(app, app.processName, pid);
1971 }
1972
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001973 StringBuilder buf = mStringBuilder;
1974 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 buf.append("Start proc ");
1976 buf.append(app.processName);
1977 buf.append(" for ");
1978 buf.append(hostingType);
1979 if (hostingNameStr != null) {
1980 buf.append(" ");
1981 buf.append(hostingNameStr);
1982 }
1983 buf.append(": pid=");
1984 buf.append(pid);
1985 buf.append(" uid=");
1986 buf.append(uid);
1987 buf.append(" gids={");
1988 if (gids != null) {
1989 for (int gi=0; gi<gids.length; gi++) {
1990 if (gi != 0) buf.append(", ");
1991 buf.append(gids[gi]);
1992
1993 }
1994 }
1995 buf.append("}");
1996 Log.i(TAG, buf.toString());
1997 if (pid == 0 || pid == MY_PID) {
1998 // Processes are being emulated with threads.
1999 app.pid = MY_PID;
2000 app.removed = false;
2001 mStartingProcesses.add(app);
2002 } else if (pid > 0) {
2003 app.pid = pid;
2004 app.removed = false;
2005 synchronized (mPidsSelfLocked) {
2006 this.mPidsSelfLocked.put(pid, app);
2007 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2008 msg.obj = app;
2009 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2010 }
2011 } else {
2012 app.pid = 0;
2013 RuntimeException e = new RuntimeException(
2014 "Failure starting process " + app.processName
2015 + ": returned pid=" + pid);
2016 Log.e(TAG, e.getMessage(), e);
2017 }
2018 } catch (RuntimeException e) {
2019 // XXX do better error recovery.
2020 app.pid = 0;
2021 Log.e(TAG, "Failure starting process " + app.processName, e);
2022 }
2023 }
2024
2025 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2026 if (mPausingActivity != null) {
2027 RuntimeException e = new RuntimeException();
2028 Log.e(TAG, "Trying to pause when pause is already pending for "
2029 + mPausingActivity, e);
2030 }
2031 HistoryRecord prev = mResumedActivity;
2032 if (prev == null) {
2033 RuntimeException e = new RuntimeException();
2034 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2035 resumeTopActivityLocked(null);
2036 return;
2037 }
2038 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2039 mResumedActivity = null;
2040 mPausingActivity = prev;
2041 mLastPausedActivity = prev;
2042 prev.state = ActivityState.PAUSING;
2043 prev.task.touchActiveTime();
2044
2045 updateCpuStats();
2046
2047 if (prev.app != null && prev.app.thread != null) {
2048 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2049 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002050 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 System.identityHashCode(prev),
2052 prev.shortComponentName);
2053 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2054 prev.configChangeFlags);
2055 updateUsageStats(prev, false);
2056 } catch (Exception e) {
2057 // Ignore exception, if process died other code will cleanup.
2058 Log.w(TAG, "Exception thrown during pause", e);
2059 mPausingActivity = null;
2060 mLastPausedActivity = null;
2061 }
2062 } else {
2063 mPausingActivity = null;
2064 mLastPausedActivity = null;
2065 }
2066
2067 // If we are not going to sleep, we want to ensure the device is
2068 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002069 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070 mLaunchingActivity.acquire();
2071 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2072 // To be safe, don't allow the wake lock to be held for too long.
2073 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2074 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2075 }
2076 }
2077
2078
2079 if (mPausingActivity != null) {
2080 // Have the window manager pause its key dispatching until the new
2081 // activity has started. If we're pausing the activity just because
2082 // the screen is being turned off and the UI is sleeping, don't interrupt
2083 // key dispatch; the same activity will pick it up again on wakeup.
2084 if (!uiSleeping) {
2085 prev.pauseKeyDispatchingLocked();
2086 } else {
2087 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2088 }
2089
2090 // Schedule a pause timeout in case the app doesn't respond.
2091 // We don't give it much time because this directly impacts the
2092 // responsiveness seen by the user.
2093 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2094 msg.obj = prev;
2095 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2096 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2097 } else {
2098 // This activity failed to schedule the
2099 // pause, so just treat it as being paused now.
2100 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2101 resumeTopActivityLocked(null);
2102 }
2103 }
2104
2105 private final void completePauseLocked() {
2106 HistoryRecord prev = mPausingActivity;
2107 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2108
2109 if (prev != null) {
2110 if (prev.finishing) {
2111 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2112 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2113 } else if (prev.app != null) {
2114 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2115 if (prev.waitingVisible) {
2116 prev.waitingVisible = false;
2117 mWaitingVisibleActivities.remove(prev);
2118 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2119 TAG, "Complete pause, no longer waiting: " + prev);
2120 }
2121 if (prev.configDestroy) {
2122 // The previous is being paused because the configuration
2123 // is changing, which means it is actually stopping...
2124 // To juggle the fact that we are also starting a new
2125 // instance right now, we need to first completely stop
2126 // the current instance before starting the new one.
2127 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2128 destroyActivityLocked(prev, true);
2129 } else {
2130 mStoppingActivities.add(prev);
2131 if (mStoppingActivities.size() > 3) {
2132 // If we already have a few activities waiting to stop,
2133 // then give up on things going idle and start clearing
2134 // them out.
2135 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2136 Message msg = Message.obtain();
2137 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2138 mHandler.sendMessage(msg);
2139 }
2140 }
2141 } else {
2142 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2143 prev = null;
2144 }
2145 mPausingActivity = null;
2146 }
2147
Dianne Hackborn55280a92009-05-07 15:53:46 -07002148 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002149 resumeTopActivityLocked(prev);
2150 } else {
2151 if (mGoingToSleep.isHeld()) {
2152 mGoingToSleep.release();
2153 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002154 if (mShuttingDown) {
2155 notifyAll();
2156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002157 }
2158
2159 if (prev != null) {
2160 prev.resumeKeyDispatchingLocked();
2161 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002162
2163 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2164 long diff = 0;
2165 synchronized (mProcessStatsThread) {
2166 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2167 }
2168 if (diff > 0) {
2169 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2170 synchronized (bsi) {
2171 BatteryStatsImpl.Uid.Proc ps =
2172 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2173 prev.info.packageName);
2174 if (ps != null) {
2175 ps.addForegroundTimeLocked(diff);
2176 }
2177 }
2178 }
2179 }
2180 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181 }
2182
2183 /**
2184 * Once we know that we have asked an application to put an activity in
2185 * the resumed state (either by launching it or explicitly telling it),
2186 * this function updates the rest of our state to match that fact.
2187 */
2188 private final void completeResumeLocked(HistoryRecord next) {
2189 next.idle = false;
2190 next.results = null;
2191 next.newIntents = null;
2192
2193 // schedule an idle timeout in case the app doesn't do it for us.
2194 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2195 msg.obj = next;
2196 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2197
2198 if (false) {
2199 // The activity was never told to pause, so just keep
2200 // things going as-is. To maintain our own state,
2201 // we need to emulate it coming back and saying it is
2202 // idle.
2203 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2204 msg.obj = next;
2205 mHandler.sendMessage(msg);
2206 }
2207
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002208 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 next.thumbnail = null;
2211 setFocusedActivityLocked(next);
2212 next.resumeKeyDispatchingLocked();
2213 ensureActivitiesVisibleLocked(null, 0);
2214 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002215 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002216
2217 // Mark the point when the activity is resuming
2218 // TODO: To be more accurate, the mark should be before the onCreate,
2219 // not after the onResume. But for subsequent starts, onResume is fine.
2220 if (next.app != null) {
2221 synchronized (mProcessStatsThread) {
2222 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2223 }
2224 } else {
2225 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2226 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 }
2228
2229 /**
2230 * Make sure that all activities that need to be visible (that is, they
2231 * currently can be seen by the user) actually are.
2232 */
2233 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2234 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2235 if (DEBUG_VISBILITY) Log.v(
2236 TAG, "ensureActivitiesVisible behind " + top
2237 + " configChanges=0x" + Integer.toHexString(configChanges));
2238
2239 // If the top activity is not fullscreen, then we need to
2240 // make sure any activities under it are now visible.
2241 final int count = mHistory.size();
2242 int i = count-1;
2243 while (mHistory.get(i) != top) {
2244 i--;
2245 }
2246 HistoryRecord r;
2247 boolean behindFullscreen = false;
2248 for (; i>=0; i--) {
2249 r = (HistoryRecord)mHistory.get(i);
2250 if (DEBUG_VISBILITY) Log.v(
2251 TAG, "Make visible? " + r + " finishing=" + r.finishing
2252 + " state=" + r.state);
2253 if (r.finishing) {
2254 continue;
2255 }
2256
2257 final boolean doThisProcess = onlyThisProcess == null
2258 || onlyThisProcess.equals(r.processName);
2259
2260 // First: if this is not the current activity being started, make
2261 // sure it matches the current configuration.
2262 if (r != starting && doThisProcess) {
2263 ensureActivityConfigurationLocked(r, 0);
2264 }
2265
2266 if (r.app == null || r.app.thread == null) {
2267 if (onlyThisProcess == null
2268 || onlyThisProcess.equals(r.processName)) {
2269 // This activity needs to be visible, but isn't even
2270 // running... get it started, but don't resume it
2271 // at this point.
2272 if (DEBUG_VISBILITY) Log.v(
2273 TAG, "Start and freeze screen for " + r);
2274 if (r != starting) {
2275 r.startFreezingScreenLocked(r.app, configChanges);
2276 }
2277 if (!r.visible) {
2278 if (DEBUG_VISBILITY) Log.v(
2279 TAG, "Starting and making visible: " + r);
2280 mWindowManager.setAppVisibility(r, true);
2281 }
2282 if (r != starting) {
2283 startSpecificActivityLocked(r, false, false);
2284 }
2285 }
2286
2287 } else if (r.visible) {
2288 // If this activity is already visible, then there is nothing
2289 // else to do here.
2290 if (DEBUG_VISBILITY) Log.v(
2291 TAG, "Skipping: already visible at " + r);
2292 r.stopFreezingScreenLocked(false);
2293
2294 } else if (onlyThisProcess == null) {
2295 // This activity is not currently visible, but is running.
2296 // Tell it to become visible.
2297 r.visible = true;
2298 if (r.state != ActivityState.RESUMED && r != starting) {
2299 // If this activity is paused, tell it
2300 // to now show its window.
2301 if (DEBUG_VISBILITY) Log.v(
2302 TAG, "Making visible and scheduling visibility: " + r);
2303 try {
2304 mWindowManager.setAppVisibility(r, true);
2305 r.app.thread.scheduleWindowVisibility(r, true);
2306 r.stopFreezingScreenLocked(false);
2307 } catch (Exception e) {
2308 // Just skip on any failure; we'll make it
2309 // visible when it next restarts.
2310 Log.w(TAG, "Exception thrown making visibile: "
2311 + r.intent.getComponent(), e);
2312 }
2313 }
2314 }
2315
2316 // Aggregate current change flags.
2317 configChanges |= r.configChangeFlags;
2318
2319 if (r.fullscreen) {
2320 // At this point, nothing else needs to be shown
2321 if (DEBUG_VISBILITY) Log.v(
2322 TAG, "Stopping: fullscreen at " + r);
2323 behindFullscreen = true;
2324 i--;
2325 break;
2326 }
2327 }
2328
2329 // Now for any activities that aren't visible to the user, make
2330 // sure they no longer are keeping the screen frozen.
2331 while (i >= 0) {
2332 r = (HistoryRecord)mHistory.get(i);
2333 if (DEBUG_VISBILITY) Log.v(
2334 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2335 + " state=" + r.state
2336 + " behindFullscreen=" + behindFullscreen);
2337 if (!r.finishing) {
2338 if (behindFullscreen) {
2339 if (r.visible) {
2340 if (DEBUG_VISBILITY) Log.v(
2341 TAG, "Making invisible: " + r);
2342 r.visible = false;
2343 try {
2344 mWindowManager.setAppVisibility(r, false);
2345 if ((r.state == ActivityState.STOPPING
2346 || r.state == ActivityState.STOPPED)
2347 && r.app != null && r.app.thread != null) {
2348 if (DEBUG_VISBILITY) Log.v(
2349 TAG, "Scheduling invisibility: " + r);
2350 r.app.thread.scheduleWindowVisibility(r, false);
2351 }
2352 } catch (Exception e) {
2353 // Just skip on any failure; we'll make it
2354 // visible when it next restarts.
2355 Log.w(TAG, "Exception thrown making hidden: "
2356 + r.intent.getComponent(), e);
2357 }
2358 } else {
2359 if (DEBUG_VISBILITY) Log.v(
2360 TAG, "Already invisible: " + r);
2361 }
2362 } else if (r.fullscreen) {
2363 if (DEBUG_VISBILITY) Log.v(
2364 TAG, "Now behindFullscreen: " + r);
2365 behindFullscreen = true;
2366 }
2367 }
2368 i--;
2369 }
2370 }
2371
2372 /**
2373 * Version of ensureActivitiesVisible that can easily be called anywhere.
2374 */
2375 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2376 int configChanges) {
2377 HistoryRecord r = topRunningActivityLocked(null);
2378 if (r != null) {
2379 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2380 }
2381 }
2382
2383 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2384 if (resumed) {
2385 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2386 } else {
2387 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2388 }
2389 }
2390
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002391 private boolean startHomeActivityLocked() {
2392 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2393 && mTopAction == null) {
2394 // We are running in factory test mode, but unable to find
2395 // the factory test app, so just sit around displaying the
2396 // error message and don't try to start anything.
2397 return false;
2398 }
2399 Intent intent = new Intent(
2400 mTopAction,
2401 mTopData != null ? Uri.parse(mTopData) : null);
2402 intent.setComponent(mTopComponent);
2403 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2404 intent.addCategory(Intent.CATEGORY_HOME);
2405 }
2406 ActivityInfo aInfo =
2407 intent.resolveActivityInfo(mContext.getPackageManager(),
2408 STOCK_PM_FLAGS);
2409 if (aInfo != null) {
2410 intent.setComponent(new ComponentName(
2411 aInfo.applicationInfo.packageName, aInfo.name));
2412 // Don't do this if the home app is currently being
2413 // instrumented.
2414 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2415 aInfo.applicationInfo.uid);
2416 if (app == null || app.instrumentationClass == null) {
2417 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2418 startActivityLocked(null, intent, null, null, 0, aInfo,
2419 null, null, 0, 0, 0, false, false);
2420 }
2421 }
2422
2423
2424 return true;
2425 }
2426
2427 /**
2428 * Starts the "new version setup screen" if appropriate.
2429 */
2430 private void startSetupActivityLocked() {
2431 // Only do this once per boot.
2432 if (mCheckedForSetup) {
2433 return;
2434 }
2435
2436 // We will show this screen if the current one is a different
2437 // version than the last one shown, and we are not running in
2438 // low-level factory test mode.
2439 final ContentResolver resolver = mContext.getContentResolver();
2440 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2441 Settings.Secure.getInt(resolver,
2442 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2443 mCheckedForSetup = true;
2444
2445 // See if we should be showing the platform update setup UI.
2446 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2447 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2448 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2449
2450 // We don't allow third party apps to replace this.
2451 ResolveInfo ri = null;
2452 for (int i=0; ris != null && i<ris.size(); i++) {
2453 if ((ris.get(i).activityInfo.applicationInfo.flags
2454 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2455 ri = ris.get(i);
2456 break;
2457 }
2458 }
2459
2460 if (ri != null) {
2461 String vers = ri.activityInfo.metaData != null
2462 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2463 : null;
2464 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2465 vers = ri.activityInfo.applicationInfo.metaData.getString(
2466 Intent.METADATA_SETUP_VERSION);
2467 }
2468 String lastVers = Settings.Secure.getString(
2469 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2470 if (vers != null && !vers.equals(lastVers)) {
2471 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2472 intent.setComponent(new ComponentName(
2473 ri.activityInfo.packageName, ri.activityInfo.name));
2474 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2475 null, null, 0, 0, 0, false, false);
2476 }
2477 }
2478 }
2479 }
2480
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002481 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002482 //Log.i(TAG, "**** REPORT RESUME: " + r);
2483
2484 final int identHash = System.identityHashCode(r);
2485 updateUsageStats(r, true);
2486
2487 int i = mWatchers.beginBroadcast();
2488 while (i > 0) {
2489 i--;
2490 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2491 if (w != null) {
2492 try {
2493 w.activityResuming(identHash);
2494 } catch (RemoteException e) {
2495 }
2496 }
2497 }
2498 mWatchers.finishBroadcast();
2499 }
2500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002501 /**
2502 * Ensure that the top activity in the stack is resumed.
2503 *
2504 * @param prev The previously resumed activity, for when in the process
2505 * of pausing; can be null to call from elsewhere.
2506 *
2507 * @return Returns true if something is being resumed, or false if
2508 * nothing happened.
2509 */
2510 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2511 // Find the first activity that is not finishing.
2512 HistoryRecord next = topRunningActivityLocked(null);
2513
2514 // Remember how we'll process this pause/resume situation, and ensure
2515 // that the state is reset however we wind up proceeding.
2516 final boolean userLeaving = mUserLeaving;
2517 mUserLeaving = false;
2518
2519 if (next == null) {
2520 // There are no more activities! Let's just start up the
2521 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002522 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002523 }
2524
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002525 next.delayedResume = false;
2526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002527 // If the top activity is the resumed one, nothing to do.
2528 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2529 // Make sure we have executed any pending transitions, since there
2530 // should be nothing left to do at this point.
2531 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002532 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002533 return false;
2534 }
2535
2536 // If we are sleeping, and there is no resumed activity, and the top
2537 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002538 if ((mSleeping || mShuttingDown)
2539 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 // Make sure we have executed any pending transitions, since there
2541 // should be nothing left to do at this point.
2542 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002543 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002544 return false;
2545 }
2546
2547 // The activity may be waiting for stop, but that is no longer
2548 // appropriate for it.
2549 mStoppingActivities.remove(next);
2550 mWaitingVisibleActivities.remove(next);
2551
2552 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2553
2554 // If we are currently pausing an activity, then don't do anything
2555 // until that is done.
2556 if (mPausingActivity != null) {
2557 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2558 return false;
2559 }
2560
2561 // We need to start pausing the current activity so the top one
2562 // can be resumed...
2563 if (mResumedActivity != null) {
2564 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2565 startPausingLocked(userLeaving, false);
2566 return true;
2567 }
2568
2569 if (prev != null && prev != next) {
2570 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2571 prev.waitingVisible = true;
2572 mWaitingVisibleActivities.add(prev);
2573 if (DEBUG_SWITCH) Log.v(
2574 TAG, "Resuming top, waiting visible to hide: " + prev);
2575 } else {
2576 // The next activity is already visible, so hide the previous
2577 // activity's windows right now so we can show the new one ASAP.
2578 // We only do this if the previous is finishing, which should mean
2579 // it is on top of the one being resumed so hiding it quickly
2580 // is good. Otherwise, we want to do the normal route of allowing
2581 // the resumed activity to be shown so we can decide if the
2582 // previous should actually be hidden depending on whether the
2583 // new one is found to be full-screen or not.
2584 if (prev.finishing) {
2585 mWindowManager.setAppVisibility(prev, false);
2586 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2587 + prev + ", waitingVisible="
2588 + (prev != null ? prev.waitingVisible : null)
2589 + ", nowVisible=" + next.nowVisible);
2590 } else {
2591 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2592 + prev + ", waitingVisible="
2593 + (prev != null ? prev.waitingVisible : null)
2594 + ", nowVisible=" + next.nowVisible);
2595 }
2596 }
2597 }
2598
2599 // We are starting up the next activity, so tell the window manager
2600 // that the previous one will be hidden soon. This way it can know
2601 // to ignore it when computing the desired screen orientation.
2602 if (prev != null) {
2603 if (prev.finishing) {
2604 if (DEBUG_TRANSITION) Log.v(TAG,
2605 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002606 if (mNoAnimActivities.contains(prev)) {
2607 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2608 } else {
2609 mWindowManager.prepareAppTransition(prev.task == next.task
2610 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2611 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002613 mWindowManager.setAppWillBeHidden(prev);
2614 mWindowManager.setAppVisibility(prev, false);
2615 } else {
2616 if (DEBUG_TRANSITION) Log.v(TAG,
2617 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002618 if (mNoAnimActivities.contains(next)) {
2619 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2620 } else {
2621 mWindowManager.prepareAppTransition(prev.task == next.task
2622 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2623 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2624 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002625 }
2626 if (false) {
2627 mWindowManager.setAppWillBeHidden(prev);
2628 mWindowManager.setAppVisibility(prev, false);
2629 }
2630 } else if (mHistory.size() > 1) {
2631 if (DEBUG_TRANSITION) Log.v(TAG,
2632 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002633 if (mNoAnimActivities.contains(next)) {
2634 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2635 } else {
2636 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2637 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002638 }
2639
2640 if (next.app != null && next.app.thread != null) {
2641 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2642
2643 // This activity is now becoming visible.
2644 mWindowManager.setAppVisibility(next, true);
2645
2646 HistoryRecord lastResumedActivity = mResumedActivity;
2647 ActivityState lastState = next.state;
2648
2649 updateCpuStats();
2650
2651 next.state = ActivityState.RESUMED;
2652 mResumedActivity = next;
2653 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002654 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002655 updateLRUListLocked(next);
2656
2657 // Have the window manager re-evaluate the orientation of
2658 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002659 boolean updated;
2660 synchronized (this) {
2661 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2662 mConfiguration,
2663 next.mayFreezeScreenLocked(next.app) ? next : null);
2664 if (config != null) {
2665 /*
2666 * Explicitly restore the locale to the one from the
2667 * old configuration, since the one that comes back from
2668 * the window manager has the default (boot) locale.
2669 *
2670 * It looks like previously the locale picker only worked
2671 * by coincidence: usually it would do its setting of
2672 * the locale after the activity transition, so it didn't
2673 * matter that this lost it. With the synchronized
2674 * block now keeping them from happening at the same time,
2675 * this one always would happen second and undo what the
2676 * locale picker had just done.
2677 */
2678 config.locale = mConfiguration.locale;
2679 next.frozenBeforeDestroy = true;
2680 }
2681 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002682 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002683 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002684 // The configuration update wasn't able to keep the existing
2685 // instance of the activity, and instead started a new one.
2686 // We should be all done, but let's just make sure our activity
2687 // is still at the top and schedule another run if something
2688 // weird happened.
2689 HistoryRecord nextNext = topRunningActivityLocked(null);
2690 if (DEBUG_SWITCH) Log.i(TAG,
2691 "Activity config changed during resume: " + next
2692 + ", new next: " + nextNext);
2693 if (nextNext != next) {
2694 // Do over!
2695 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2696 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002697 setFocusedActivityLocked(next);
2698 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002699 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002700 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002701 return true;
2702 }
2703
2704 try {
2705 // Deliver all pending results.
2706 ArrayList a = next.results;
2707 if (a != null) {
2708 final int N = a.size();
2709 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002710 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002711 TAG, "Delivering results to " + next
2712 + ": " + a);
2713 next.app.thread.scheduleSendResult(next, a);
2714 }
2715 }
2716
2717 if (next.newIntents != null) {
2718 next.app.thread.scheduleNewIntent(next.newIntents, next);
2719 }
2720
Doug Zongker2bec3d42009-12-04 12:52:44 -08002721 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002722 System.identityHashCode(next),
2723 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724
2725 next.app.thread.scheduleResumeActivity(next,
2726 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002728 pauseIfSleepingLocked();
2729
2730 } catch (Exception e) {
2731 // Whoops, need to restart this activity!
2732 next.state = lastState;
2733 mResumedActivity = lastResumedActivity;
Dianne Hackborn03abb812010-01-04 18:43:19 -08002734 Log.i(TAG, "Restarting because process died: " + next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002735 if (!next.hasBeenLaunched) {
2736 next.hasBeenLaunched = true;
2737 } else {
2738 if (SHOW_APP_STARTING_ICON) {
2739 mWindowManager.setAppStartingWindow(
2740 next, next.packageName, next.theme,
2741 next.nonLocalizedLabel,
2742 next.labelRes, next.icon, null, true);
2743 }
2744 }
2745 startSpecificActivityLocked(next, true, false);
2746 return true;
2747 }
2748
2749 // From this point on, if something goes wrong there is no way
2750 // to recover the activity.
2751 try {
2752 next.visible = true;
2753 completeResumeLocked(next);
2754 } catch (Exception e) {
2755 // If any exception gets thrown, toss away this
2756 // activity and try the next one.
2757 Log.w(TAG, "Exception thrown during resume of " + next, e);
2758 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2759 "resume-exception");
2760 return true;
2761 }
2762
2763 // Didn't need to use the icicle, and it is now out of date.
2764 next.icicle = null;
2765 next.haveState = false;
2766 next.stopped = false;
2767
2768 } else {
2769 // Whoops, need to restart this activity!
2770 if (!next.hasBeenLaunched) {
2771 next.hasBeenLaunched = true;
2772 } else {
2773 if (SHOW_APP_STARTING_ICON) {
2774 mWindowManager.setAppStartingWindow(
2775 next, next.packageName, next.theme,
2776 next.nonLocalizedLabel,
2777 next.labelRes, next.icon, null, true);
2778 }
2779 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2780 }
2781 startSpecificActivityLocked(next, true, true);
2782 }
2783
2784 return true;
2785 }
2786
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002787 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2788 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 final int NH = mHistory.size();
2790
2791 int addPos = -1;
2792
2793 if (!newTask) {
2794 // If starting in an existing task, find where that is...
2795 HistoryRecord next = null;
2796 boolean startIt = true;
2797 for (int i = NH-1; i >= 0; i--) {
2798 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2799 if (p.finishing) {
2800 continue;
2801 }
2802 if (p.task == r.task) {
2803 // Here it is! Now, if this is not yet visible to the
2804 // user, then just add it without starting; it will
2805 // get started when the user navigates back to it.
2806 addPos = i+1;
2807 if (!startIt) {
2808 mHistory.add(addPos, r);
2809 r.inHistory = true;
2810 r.task.numActivities++;
2811 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2812 r.info.screenOrientation, r.fullscreen);
2813 if (VALIDATE_TOKENS) {
2814 mWindowManager.validateAppTokens(mHistory);
2815 }
2816 return;
2817 }
2818 break;
2819 }
2820 if (p.fullscreen) {
2821 startIt = false;
2822 }
2823 next = p;
2824 }
2825 }
2826
2827 // Place a new activity at top of stack, so it is next to interact
2828 // with the user.
2829 if (addPos < 0) {
2830 addPos = mHistory.size();
2831 }
2832
2833 // If we are not placing the new activity frontmost, we do not want
2834 // to deliver the onUserLeaving callback to the actual frontmost
2835 // activity
2836 if (addPos < NH) {
2837 mUserLeaving = false;
2838 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2839 }
2840
2841 // Slot the activity into the history stack and proceed
2842 mHistory.add(addPos, r);
2843 r.inHistory = true;
2844 r.frontOfTask = newTask;
2845 r.task.numActivities++;
2846 if (NH > 0) {
2847 // We want to show the starting preview window if we are
2848 // switching to a new task, or the next activity's process is
2849 // not currently running.
2850 boolean showStartingIcon = newTask;
2851 ProcessRecord proc = r.app;
2852 if (proc == null) {
2853 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2854 }
2855 if (proc == null || proc.thread == null) {
2856 showStartingIcon = true;
2857 }
2858 if (DEBUG_TRANSITION) Log.v(TAG,
2859 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002860 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2861 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2862 mNoAnimActivities.add(r);
2863 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2864 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2865 mNoAnimActivities.remove(r);
2866 } else {
2867 mWindowManager.prepareAppTransition(newTask
2868 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2869 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2870 mNoAnimActivities.remove(r);
2871 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002872 mWindowManager.addAppToken(
2873 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2874 boolean doShow = true;
2875 if (newTask) {
2876 // Even though this activity is starting fresh, we still need
2877 // to reset it to make sure we apply affinities to move any
2878 // existing activities from other tasks in to it.
2879 // If the caller has requested that the target task be
2880 // reset, then do so.
2881 if ((r.intent.getFlags()
2882 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2883 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002884 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002885 }
2886 }
2887 if (SHOW_APP_STARTING_ICON && doShow) {
2888 // Figure out if we are transitioning from another activity that is
2889 // "has the same starting icon" as the next one. This allows the
2890 // window manager to keep the previous window it had previously
2891 // created, if it still had one.
2892 HistoryRecord prev = mResumedActivity;
2893 if (prev != null) {
2894 // We don't want to reuse the previous starting preview if:
2895 // (1) The current activity is in a different task.
2896 if (prev.task != r.task) prev = null;
2897 // (2) The current activity is already displayed.
2898 else if (prev.nowVisible) prev = null;
2899 }
2900 mWindowManager.setAppStartingWindow(
2901 r, r.packageName, r.theme, r.nonLocalizedLabel,
2902 r.labelRes, r.icon, prev, showStartingIcon);
2903 }
2904 } else {
2905 // If this is the first activity, don't do any fancy animations,
2906 // because there is nothing for it to animate on top of.
2907 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2908 r.info.screenOrientation, r.fullscreen);
2909 }
2910 if (VALIDATE_TOKENS) {
2911 mWindowManager.validateAppTokens(mHistory);
2912 }
2913
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002914 if (doResume) {
2915 resumeTopActivityLocked(null);
2916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002917 }
2918
2919 /**
2920 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002921 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2922 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 * an instance of that activity in the stack and, if found, finish all
2924 * activities on top of it and return the instance.
2925 *
2926 * @param newR Description of the new activity being started.
2927 * @return Returns the old activity that should be continue to be used,
2928 * or null if none was found.
2929 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002930 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002931 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002932 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002933
2934 // First find the requested task.
2935 while (i > 0) {
2936 i--;
2937 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2938 if (r.task.taskId == taskId) {
2939 i++;
2940 break;
2941 }
2942 }
2943
2944 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002945 while (i > 0) {
2946 i--;
2947 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2948 if (r.finishing) {
2949 continue;
2950 }
2951 if (r.task.taskId != taskId) {
2952 return null;
2953 }
2954 if (r.realActivity.equals(newR.realActivity)) {
2955 // Here it is! Now finish everything in front...
2956 HistoryRecord ret = r;
2957 if (doClear) {
2958 while (i < (mHistory.size()-1)) {
2959 i++;
2960 r = (HistoryRecord)mHistory.get(i);
2961 if (r.finishing) {
2962 continue;
2963 }
2964 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2965 null, "clear")) {
2966 i--;
2967 }
2968 }
2969 }
2970
2971 // Finally, if this is a normal launch mode (that is, not
2972 // expecting onNewIntent()), then we will finish the current
2973 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002974 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2975 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002976 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002977 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002978 if (index >= 0) {
2979 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2980 null, "clear");
2981 }
2982 return null;
2983 }
2984 }
2985
2986 return ret;
2987 }
2988 }
2989
2990 return null;
2991 }
2992
2993 /**
2994 * Find the activity in the history stack within the given task. Returns
2995 * the index within the history at which it's found, or < 0 if not found.
2996 */
2997 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2998 int i = mHistory.size();
2999 while (i > 0) {
3000 i--;
3001 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3002 if (candidate.task.taskId != task) {
3003 break;
3004 }
3005 if (candidate.realActivity.equals(r.realActivity)) {
3006 return i;
3007 }
3008 }
3009
3010 return -1;
3011 }
3012
3013 /**
3014 * Reorder the history stack so that the activity at the given index is
3015 * brought to the front.
3016 */
3017 private final HistoryRecord moveActivityToFrontLocked(int where) {
3018 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3019 int top = mHistory.size();
3020 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3021 mHistory.add(top, newTop);
3022 oldTop.frontOfTask = false;
3023 newTop.frontOfTask = true;
3024 return newTop;
3025 }
3026
3027 /**
3028 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3029 * method will be called at the proper time.
3030 */
3031 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3032 boolean sent = false;
3033 if (r.state == ActivityState.RESUMED
3034 && r.app != null && r.app.thread != null) {
3035 try {
3036 ArrayList<Intent> ar = new ArrayList<Intent>();
3037 ar.add(new Intent(intent));
3038 r.app.thread.scheduleNewIntent(ar, r);
3039 sent = true;
3040 } catch (Exception e) {
3041 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3042 }
3043 }
3044 if (!sent) {
3045 r.addNewIntentLocked(new Intent(intent));
3046 }
3047 }
3048
3049 private final void logStartActivity(int tag, HistoryRecord r,
3050 TaskRecord task) {
3051 EventLog.writeEvent(tag,
3052 System.identityHashCode(r), task.taskId,
3053 r.shortComponentName, r.intent.getAction(),
3054 r.intent.getType(), r.intent.getDataString(),
3055 r.intent.getFlags());
3056 }
3057
3058 private final int startActivityLocked(IApplicationThread caller,
3059 Intent intent, String resolvedType,
3060 Uri[] grantedUriPermissions,
3061 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3062 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003063 int callingPid, int callingUid, boolean onlyIfNeeded,
3064 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003065 Log.i(TAG, "Starting activity: " + intent);
3066
3067 HistoryRecord sourceRecord = null;
3068 HistoryRecord resultRecord = null;
3069 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003070 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003071 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003072 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3073 if (index >= 0) {
3074 sourceRecord = (HistoryRecord)mHistory.get(index);
3075 if (requestCode >= 0 && !sourceRecord.finishing) {
3076 resultRecord = sourceRecord;
3077 }
3078 }
3079 }
3080
3081 int launchFlags = intent.getFlags();
3082
3083 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3084 && sourceRecord != null) {
3085 // Transfer the result target from the source activity to the new
3086 // one being started, including any failures.
3087 if (requestCode >= 0) {
3088 return START_FORWARD_AND_REQUEST_CONFLICT;
3089 }
3090 resultRecord = sourceRecord.resultTo;
3091 resultWho = sourceRecord.resultWho;
3092 requestCode = sourceRecord.requestCode;
3093 sourceRecord.resultTo = null;
3094 if (resultRecord != null) {
3095 resultRecord.removeResultsLocked(
3096 sourceRecord, resultWho, requestCode);
3097 }
3098 }
3099
3100 int err = START_SUCCESS;
3101
3102 if (intent.getComponent() == null) {
3103 // We couldn't find a class that can handle the given Intent.
3104 // That's the end of that!
3105 err = START_INTENT_NOT_RESOLVED;
3106 }
3107
3108 if (err == START_SUCCESS && aInfo == null) {
3109 // We couldn't find the specific class specified in the Intent.
3110 // Also the end of the line.
3111 err = START_CLASS_NOT_FOUND;
3112 }
3113
3114 ProcessRecord callerApp = null;
3115 if (err == START_SUCCESS && caller != null) {
3116 callerApp = getRecordForAppLocked(caller);
3117 if (callerApp != null) {
3118 callingPid = callerApp.pid;
3119 callingUid = callerApp.info.uid;
3120 } else {
3121 Log.w(TAG, "Unable to find app for caller " + caller
3122 + " (pid=" + callingPid + ") when starting: "
3123 + intent.toString());
3124 err = START_PERMISSION_DENIED;
3125 }
3126 }
3127
3128 if (err != START_SUCCESS) {
3129 if (resultRecord != null) {
3130 sendActivityResultLocked(-1,
3131 resultRecord, resultWho, requestCode,
3132 Activity.RESULT_CANCELED, null);
3133 }
3134 return err;
3135 }
3136
3137 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3138 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3139 if (perm != PackageManager.PERMISSION_GRANTED) {
3140 if (resultRecord != null) {
3141 sendActivityResultLocked(-1,
3142 resultRecord, resultWho, requestCode,
3143 Activity.RESULT_CANCELED, null);
3144 }
3145 String msg = "Permission Denial: starting " + intent.toString()
3146 + " from " + callerApp + " (pid=" + callingPid
3147 + ", uid=" + callingUid + ")"
3148 + " requires " + aInfo.permission;
3149 Log.w(TAG, msg);
3150 throw new SecurityException(msg);
3151 }
3152
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003153 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003154 boolean abort = false;
3155 try {
3156 // The Intent we give to the watcher has the extra data
3157 // stripped off, since it can contain private information.
3158 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003159 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 aInfo.applicationInfo.packageName);
3161 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003162 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 }
3164
3165 if (abort) {
3166 if (resultRecord != null) {
3167 sendActivityResultLocked(-1,
3168 resultRecord, resultWho, requestCode,
3169 Activity.RESULT_CANCELED, null);
3170 }
3171 // We pretend to the caller that it was really started, but
3172 // they will just get a cancel result.
3173 return START_SUCCESS;
3174 }
3175 }
3176
3177 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3178 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003179 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003180
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003181 if (mResumedActivity == null
3182 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3183 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3184 PendingActivityLaunch pal = new PendingActivityLaunch();
3185 pal.r = r;
3186 pal.sourceRecord = sourceRecord;
3187 pal.grantedUriPermissions = grantedUriPermissions;
3188 pal.grantedMode = grantedMode;
3189 pal.onlyIfNeeded = onlyIfNeeded;
3190 mPendingActivityLaunches.add(pal);
3191 return START_SWITCHES_CANCELED;
3192 }
3193 }
3194
3195 if (mDidAppSwitch) {
3196 // This is the second allowed switch since we stopped switches,
3197 // so now just generally allow switches. Use case: user presses
3198 // home (switches disabled, switch to home, mDidAppSwitch now true);
3199 // user taps a home icon (coming from home so allowed, we hit here
3200 // and now allow anyone to switch again).
3201 mAppSwitchesAllowedTime = 0;
3202 } else {
3203 mDidAppSwitch = true;
3204 }
3205
3206 doPendingActivityLaunchesLocked(false);
3207
3208 return startActivityUncheckedLocked(r, sourceRecord,
3209 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3210 }
3211
3212 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3213 final int N = mPendingActivityLaunches.size();
3214 if (N <= 0) {
3215 return;
3216 }
3217 for (int i=0; i<N; i++) {
3218 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3219 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3220 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3221 doResume && i == (N-1));
3222 }
3223 mPendingActivityLaunches.clear();
3224 }
3225
3226 private final int startActivityUncheckedLocked(HistoryRecord r,
3227 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3228 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3229 final Intent intent = r.intent;
3230 final int callingUid = r.launchedFromUid;
3231
3232 int launchFlags = intent.getFlags();
3233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003234 // We'll invoke onUserLeaving before onPause only if the launching
3235 // activity did not explicitly state that this is an automated launch.
3236 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3237 if (DEBUG_USER_LEAVING) Log.v(TAG,
3238 "startActivity() => mUserLeaving=" + mUserLeaving);
3239
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003240 // If the caller has asked not to resume at this point, we make note
3241 // of this in the record so that we can skip it when trying to find
3242 // the top running activity.
3243 if (!doResume) {
3244 r.delayedResume = true;
3245 }
3246
3247 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3248 != 0 ? r : null;
3249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003250 // If the onlyIfNeeded flag is set, then we can do this if the activity
3251 // being launched is the same as the one making the call... or, as
3252 // a special case, if we do not know the caller then we count the
3253 // current top activity as the caller.
3254 if (onlyIfNeeded) {
3255 HistoryRecord checkedCaller = sourceRecord;
3256 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003257 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003258 }
3259 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3260 // Caller is not the same as launcher, so always needed.
3261 onlyIfNeeded = false;
3262 }
3263 }
3264
3265 if (grantedUriPermissions != null && callingUid > 0) {
3266 for (int i=0; i<grantedUriPermissions.length; i++) {
3267 grantUriPermissionLocked(callingUid, r.packageName,
3268 grantedUriPermissions[i], grantedMode, r);
3269 }
3270 }
3271
3272 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3273 intent, r);
3274
3275 if (sourceRecord == null) {
3276 // This activity is not being started from another... in this
3277 // case we -always- start a new task.
3278 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3279 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3280 + intent);
3281 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3282 }
3283 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3284 // The original activity who is starting us is running as a single
3285 // instance... this new activity it is starting must go on its
3286 // own task.
3287 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3288 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3289 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3290 // The activity being started is a single instance... it always
3291 // gets launched into its own task.
3292 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3293 }
3294
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003295 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 // For whatever reason this activity is being launched into a new
3297 // task... yet the caller has requested a result back. Well, that
3298 // is pretty messed up, so instead immediately send back a cancel
3299 // and let the new task continue launched as normal without a
3300 // dependency on its originator.
3301 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3302 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003303 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003304 Activity.RESULT_CANCELED, null);
3305 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003306 }
3307
3308 boolean addingToTask = false;
3309 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3310 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3311 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3312 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3313 // If bring to front is requested, and no result is requested, and
3314 // we can find a task that was started with this same
3315 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003316 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003317 // See if there is a task to bring to the front. If this is
3318 // a SINGLE_INSTANCE activity, there can be one and only one
3319 // instance of it in the history, and it is always in its own
3320 // unique task, so we do a special search.
3321 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3322 ? findTaskLocked(intent, r.info)
3323 : findActivityLocked(intent, r.info);
3324 if (taskTop != null) {
3325 if (taskTop.task.intent == null) {
3326 // This task was started because of movement of
3327 // the activity based on affinity... now that we
3328 // are actually launching it, we can assign the
3329 // base intent.
3330 taskTop.task.setIntent(intent, r.info);
3331 }
3332 // If the target task is not in the front, then we need
3333 // to bring it to the front... except... well, with
3334 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3335 // to have the same behavior as if a new instance was
3336 // being started, which means not bringing it to the front
3337 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003338 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003339 if (curTop.task != taskTop.task) {
3340 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3341 boolean callerAtFront = sourceRecord == null
3342 || curTop.task == sourceRecord.task;
3343 if (callerAtFront) {
3344 // We really do want to push this one into the
3345 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003346 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 }
3348 }
3349 // If the caller has requested that the target task be
3350 // reset, then do so.
3351 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3352 taskTop = resetTaskIfNeededLocked(taskTop, r);
3353 }
3354 if (onlyIfNeeded) {
3355 // We don't need to start a new activity, and
3356 // the client said not to do anything if that
3357 // is the case, so this is it! And for paranoia, make
3358 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003359 if (doResume) {
3360 resumeTopActivityLocked(null);
3361 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 return START_RETURN_INTENT_TO_CALLER;
3363 }
3364 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3365 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3366 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3367 // In this situation we want to remove all activities
3368 // from the task up to the one being started. In most
3369 // cases this means we are resetting the task to its
3370 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003371 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003372 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003373 if (top != null) {
3374 if (top.frontOfTask) {
3375 // Activity aliases may mean we use different
3376 // intents for the top activity, so make sure
3377 // the task now has the identity of the new
3378 // intent.
3379 top.task.setIntent(r.intent, r.info);
3380 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003381 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003382 deliverNewIntentLocked(top, r.intent);
3383 } else {
3384 // A special case: we need to
3385 // start the activity because it is not currently
3386 // running, and the caller has asked to clear the
3387 // current task to have this activity at the top.
3388 addingToTask = true;
3389 // Now pretend like this activity is being started
3390 // by the top of its task, so it is put in the
3391 // right place.
3392 sourceRecord = taskTop;
3393 }
3394 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3395 // In this case the top activity on the task is the
3396 // same as the one being launched, so we take that
3397 // as a request to bring the task to the foreground.
3398 // If the top activity in the task is the root
3399 // activity, deliver this new intent to it if it
3400 // desires.
3401 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3402 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003403 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003404 if (taskTop.frontOfTask) {
3405 taskTop.task.setIntent(r.intent, r.info);
3406 }
3407 deliverNewIntentLocked(taskTop, r.intent);
3408 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3409 // In this case we are launching the root activity
3410 // of the task, but with a different intent. We
3411 // should start a new instance on top.
3412 addingToTask = true;
3413 sourceRecord = taskTop;
3414 }
3415 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3416 // In this case an activity is being launched in to an
3417 // existing task, without resetting that task. This
3418 // is typically the situation of launching an activity
3419 // from a notification or shortcut. We want to place
3420 // the new activity on top of the current task.
3421 addingToTask = true;
3422 sourceRecord = taskTop;
3423 } else if (!taskTop.task.rootWasReset) {
3424 // In this case we are launching in to an existing task
3425 // that has not yet been started from its front door.
3426 // The current task has been brought to the front.
3427 // Ideally, we'd probably like to place this new task
3428 // at the bottom of its stack, but that's a little hard
3429 // to do with the current organization of the code so
3430 // for now we'll just drop it.
3431 taskTop.task.setIntent(r.intent, r.info);
3432 }
3433 if (!addingToTask) {
3434 // We didn't do anything... but it was needed (a.k.a., client
3435 // don't use that intent!) And for paranoia, make
3436 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003437 if (doResume) {
3438 resumeTopActivityLocked(null);
3439 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 return START_TASK_TO_FRONT;
3441 }
3442 }
3443 }
3444 }
3445
3446 //String uri = r.intent.toURI();
3447 //Intent intent2 = new Intent(uri);
3448 //Log.i(TAG, "Given intent: " + r.intent);
3449 //Log.i(TAG, "URI is: " + uri);
3450 //Log.i(TAG, "To intent: " + intent2);
3451
3452 if (r.packageName != null) {
3453 // If the activity being launched is the same as the one currently
3454 // at the top, then we need to check if it should only be launched
3455 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003456 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3457 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003458 if (top.realActivity.equals(r.realActivity)) {
3459 if (top.app != null && top.app.thread != null) {
3460 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3461 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3462 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003463 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003464 // For paranoia, make sure we have correctly
3465 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003466 if (doResume) {
3467 resumeTopActivityLocked(null);
3468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 if (onlyIfNeeded) {
3470 // We don't need to start a new activity, and
3471 // the client said not to do anything if that
3472 // is the case, so this is it!
3473 return START_RETURN_INTENT_TO_CALLER;
3474 }
3475 deliverNewIntentLocked(top, r.intent);
3476 return START_DELIVERED_TO_TOP;
3477 }
3478 }
3479 }
3480 }
3481
3482 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003483 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003484 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003485 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 Activity.RESULT_CANCELED, null);
3487 }
3488 return START_CLASS_NOT_FOUND;
3489 }
3490
3491 boolean newTask = false;
3492
3493 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003494 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003495 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3496 // todo: should do better management of integers.
3497 mCurTask++;
3498 if (mCurTask <= 0) {
3499 mCurTask = 1;
3500 }
3501 r.task = new TaskRecord(mCurTask, r.info, intent,
3502 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3503 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3504 + " in new task " + r.task);
3505 newTask = true;
3506 addRecentTask(r.task);
3507
3508 } else if (sourceRecord != null) {
3509 if (!addingToTask &&
3510 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3511 // In this case, we are adding the activity to an existing
3512 // task, but the caller has asked to clear that task if the
3513 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003514 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003515 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003517 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003518 deliverNewIntentLocked(top, r.intent);
3519 // For paranoia, make sure we have correctly
3520 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003521 if (doResume) {
3522 resumeTopActivityLocked(null);
3523 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003524 return START_DELIVERED_TO_TOP;
3525 }
3526 } else if (!addingToTask &&
3527 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3528 // In this case, we are launching an activity in our own task
3529 // that may already be running somewhere in the history, and
3530 // we want to shuffle it to the front of the stack if so.
3531 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3532 if (where >= 0) {
3533 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003534 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003536 if (doResume) {
3537 resumeTopActivityLocked(null);
3538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 return START_DELIVERED_TO_TOP;
3540 }
3541 }
3542 // An existing activity is starting this new activity, so we want
3543 // to keep the new one in the same task as the one that is starting
3544 // it.
3545 r.task = sourceRecord.task;
3546 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3547 + " in existing task " + r.task);
3548
3549 } else {
3550 // This not being started from an existing activity, and not part
3551 // of a new task... just put it in the top task, though these days
3552 // this case should never happen.
3553 final int N = mHistory.size();
3554 HistoryRecord prev =
3555 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3556 r.task = prev != null
3557 ? prev.task
3558 : new TaskRecord(mCurTask, r.info, intent,
3559 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3560 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3561 + " in new guessed " + r.task);
3562 }
3563 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003564 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003565 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003566 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003567 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 return START_SUCCESS;
3569 }
3570
3571 public final int startActivity(IApplicationThread caller,
3572 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3573 int grantedMode, IBinder resultTo,
3574 String resultWho, int requestCode, boolean onlyIfNeeded,
3575 boolean debug) {
3576 // Refuse possible leaked file descriptors
3577 if (intent != null && intent.hasFileDescriptors()) {
3578 throw new IllegalArgumentException("File descriptors passed in Intent");
3579 }
3580
The Android Open Source Project4df24232009-03-05 14:34:35 -08003581 final boolean componentSpecified = intent.getComponent() != null;
3582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003583 // Don't modify the client's object!
3584 intent = new Intent(intent);
3585
3586 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003587 ActivityInfo aInfo;
3588 try {
3589 ResolveInfo rInfo =
3590 ActivityThread.getPackageManager().resolveIntent(
3591 intent, resolvedType,
3592 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003593 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003594 aInfo = rInfo != null ? rInfo.activityInfo : null;
3595 } catch (RemoteException e) {
3596 aInfo = null;
3597 }
3598
3599 if (aInfo != null) {
3600 // Store the found target back into the intent, because now that
3601 // we have it we never want to do this again. For example, if the
3602 // user navigates back to this point in the history, we should
3603 // always restart the exact same activity.
3604 intent.setComponent(new ComponentName(
3605 aInfo.applicationInfo.packageName, aInfo.name));
3606
3607 // Don't debug things in the system process
3608 if (debug) {
3609 if (!aInfo.processName.equals("system")) {
3610 setDebugApp(aInfo.processName, true, false);
3611 }
3612 }
3613 }
3614
3615 synchronized(this) {
3616 final long origId = Binder.clearCallingIdentity();
3617 int res = startActivityLocked(caller, intent, resolvedType,
3618 grantedUriPermissions, grantedMode, aInfo,
3619 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003620 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003621 Binder.restoreCallingIdentity(origId);
3622 return res;
3623 }
3624 }
3625
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003626 public int startActivityIntentSender(IApplicationThread caller,
3627 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003628 IBinder resultTo, String resultWho, int requestCode,
3629 int flagsMask, int flagsValues) {
3630 // Refuse possible leaked file descriptors
3631 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3632 throw new IllegalArgumentException("File descriptors passed in Intent");
3633 }
3634
3635 IIntentSender sender = intent.getTarget();
3636 if (!(sender instanceof PendingIntentRecord)) {
3637 throw new IllegalArgumentException("Bad PendingIntent object");
3638 }
3639
3640 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003641
3642 synchronized (this) {
3643 // If this is coming from the currently resumed activity, it is
3644 // effectively saying that app switches are allowed at this point.
3645 if (mResumedActivity != null
3646 && mResumedActivity.info.applicationInfo.uid ==
3647 Binder.getCallingUid()) {
3648 mAppSwitchesAllowedTime = 0;
3649 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003650 }
3651
3652 return pir.sendInner(0, fillInIntent, resolvedType,
3653 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3654 }
3655
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003656 public boolean startNextMatchingActivity(IBinder callingActivity,
3657 Intent intent) {
3658 // Refuse possible leaked file descriptors
3659 if (intent != null && intent.hasFileDescriptors() == true) {
3660 throw new IllegalArgumentException("File descriptors passed in Intent");
3661 }
3662
3663 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003664 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003665 if (index < 0) {
3666 return false;
3667 }
3668 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3669 if (r.app == null || r.app.thread == null) {
3670 // The caller is not running... d'oh!
3671 return false;
3672 }
3673 intent = new Intent(intent);
3674 // The caller is not allowed to change the data.
3675 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3676 // And we are resetting to find the next component...
3677 intent.setComponent(null);
3678
3679 ActivityInfo aInfo = null;
3680 try {
3681 List<ResolveInfo> resolves =
3682 ActivityThread.getPackageManager().queryIntentActivities(
3683 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003684 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003685
3686 // Look for the original activity in the list...
3687 final int N = resolves != null ? resolves.size() : 0;
3688 for (int i=0; i<N; i++) {
3689 ResolveInfo rInfo = resolves.get(i);
3690 if (rInfo.activityInfo.packageName.equals(r.packageName)
3691 && rInfo.activityInfo.name.equals(r.info.name)) {
3692 // We found the current one... the next matching is
3693 // after it.
3694 i++;
3695 if (i<N) {
3696 aInfo = resolves.get(i).activityInfo;
3697 }
3698 break;
3699 }
3700 }
3701 } catch (RemoteException e) {
3702 }
3703
3704 if (aInfo == null) {
3705 // Nobody who is next!
3706 return false;
3707 }
3708
3709 intent.setComponent(new ComponentName(
3710 aInfo.applicationInfo.packageName, aInfo.name));
3711 intent.setFlags(intent.getFlags()&~(
3712 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3713 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3714 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3715 Intent.FLAG_ACTIVITY_NEW_TASK));
3716
3717 // Okay now we need to start the new activity, replacing the
3718 // currently running activity. This is a little tricky because
3719 // we want to start the new one as if the current one is finished,
3720 // but not finish the current one first so that there is no flicker.
3721 // And thus...
3722 final boolean wasFinishing = r.finishing;
3723 r.finishing = true;
3724
3725 // Propagate reply information over to the new activity.
3726 final HistoryRecord resultTo = r.resultTo;
3727 final String resultWho = r.resultWho;
3728 final int requestCode = r.requestCode;
3729 r.resultTo = null;
3730 if (resultTo != null) {
3731 resultTo.removeResultsLocked(r, resultWho, requestCode);
3732 }
3733
3734 final long origId = Binder.clearCallingIdentity();
3735 // XXX we are not dealing with propagating grantedUriPermissions...
3736 // those are not yet exposed to user code, so there is no need.
3737 int res = startActivityLocked(r.app.thread, intent,
3738 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003739 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003740 Binder.restoreCallingIdentity(origId);
3741
3742 r.finishing = wasFinishing;
3743 if (res != START_SUCCESS) {
3744 return false;
3745 }
3746 return true;
3747 }
3748 }
3749
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003750 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 Intent intent, String resolvedType, IBinder resultTo,
3752 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003753
3754 // This is so super not safe, that only the system (or okay root)
3755 // can do it.
3756 final int callingUid = Binder.getCallingUid();
3757 if (callingUid != 0 && callingUid != Process.myUid()) {
3758 throw new SecurityException(
3759 "startActivityInPackage only available to the system");
3760 }
3761
The Android Open Source Project4df24232009-03-05 14:34:35 -08003762 final boolean componentSpecified = intent.getComponent() != null;
3763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003764 // Don't modify the client's object!
3765 intent = new Intent(intent);
3766
3767 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003768 ActivityInfo aInfo;
3769 try {
3770 ResolveInfo rInfo =
3771 ActivityThread.getPackageManager().resolveIntent(
3772 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003773 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003774 aInfo = rInfo != null ? rInfo.activityInfo : null;
3775 } catch (RemoteException e) {
3776 aInfo = null;
3777 }
3778
3779 if (aInfo != null) {
3780 // Store the found target back into the intent, because now that
3781 // we have it we never want to do this again. For example, if the
3782 // user navigates back to this point in the history, we should
3783 // always restart the exact same activity.
3784 intent.setComponent(new ComponentName(
3785 aInfo.applicationInfo.packageName, aInfo.name));
3786 }
3787
3788 synchronized(this) {
3789 return startActivityLocked(null, intent, resolvedType,
3790 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003791 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003792 }
3793 }
3794
3795 private final void addRecentTask(TaskRecord task) {
3796 // Remove any existing entries that are the same kind of task.
3797 int N = mRecentTasks.size();
3798 for (int i=0; i<N; i++) {
3799 TaskRecord tr = mRecentTasks.get(i);
3800 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3801 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3802 mRecentTasks.remove(i);
3803 i--;
3804 N--;
3805 if (task.intent == null) {
3806 // If the new recent task we are adding is not fully
3807 // specified, then replace it with the existing recent task.
3808 task = tr;
3809 }
3810 }
3811 }
3812 if (N >= MAX_RECENT_TASKS) {
3813 mRecentTasks.remove(N-1);
3814 }
3815 mRecentTasks.add(0, task);
3816 }
3817
3818 public void setRequestedOrientation(IBinder token,
3819 int requestedOrientation) {
3820 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003821 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822 if (index < 0) {
3823 return;
3824 }
3825 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3826 final long origId = Binder.clearCallingIdentity();
3827 mWindowManager.setAppOrientation(r, requestedOrientation);
3828 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003829 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 r.mayFreezeScreenLocked(r.app) ? r : null);
3831 if (config != null) {
3832 r.frozenBeforeDestroy = true;
3833 if (!updateConfigurationLocked(config, r)) {
3834 resumeTopActivityLocked(null);
3835 }
3836 }
3837 Binder.restoreCallingIdentity(origId);
3838 }
3839 }
3840
3841 public int getRequestedOrientation(IBinder token) {
3842 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003843 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003844 if (index < 0) {
3845 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3846 }
3847 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3848 return mWindowManager.getAppOrientation(r);
3849 }
3850 }
3851
3852 private final void stopActivityLocked(HistoryRecord r) {
3853 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3854 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3855 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3856 if (!r.finishing) {
3857 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3858 "no-history");
3859 }
3860 } else if (r.app != null && r.app.thread != null) {
3861 if (mFocusedActivity == r) {
3862 setFocusedActivityLocked(topRunningActivityLocked(null));
3863 }
3864 r.resumeKeyDispatchingLocked();
3865 try {
3866 r.stopped = false;
3867 r.state = ActivityState.STOPPING;
3868 if (DEBUG_VISBILITY) Log.v(
3869 TAG, "Stopping visible=" + r.visible + " for " + r);
3870 if (!r.visible) {
3871 mWindowManager.setAppVisibility(r, false);
3872 }
3873 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3874 } catch (Exception e) {
3875 // Maybe just ignore exceptions here... if the process
3876 // has crashed, our death notification will clean things
3877 // up.
3878 Log.w(TAG, "Exception thrown during pause", e);
3879 // Just in case, assume it to be stopped.
3880 r.stopped = true;
3881 r.state = ActivityState.STOPPED;
3882 if (r.configDestroy) {
3883 destroyActivityLocked(r, true);
3884 }
3885 }
3886 }
3887 }
3888
3889 /**
3890 * @return Returns true if the activity is being finished, false if for
3891 * some reason it is being left as-is.
3892 */
3893 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3894 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003895 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003896 TAG, "Finishing activity: token=" + token
3897 + ", result=" + resultCode + ", data=" + resultData);
3898
Dianne Hackborn75b03852009-06-12 15:43:26 -07003899 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003900 if (index < 0) {
3901 return false;
3902 }
3903 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3904
3905 // Is this the last activity left?
3906 boolean lastActivity = true;
3907 for (int i=mHistory.size()-1; i>=0; i--) {
3908 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3909 if (!p.finishing && p != r) {
3910 lastActivity = false;
3911 break;
3912 }
3913 }
3914
3915 // If this is the last activity, but it is the home activity, then
3916 // just don't finish it.
3917 if (lastActivity) {
3918 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3919 return false;
3920 }
3921 }
3922
3923 finishActivityLocked(r, index, resultCode, resultData, reason);
3924 return true;
3925 }
3926
3927 /**
3928 * @return Returns true if this activity has been removed from the history
3929 * list, or false if it is still in the list and will be removed later.
3930 */
3931 private final boolean finishActivityLocked(HistoryRecord r, int index,
3932 int resultCode, Intent resultData, String reason) {
3933 if (r.finishing) {
3934 Log.w(TAG, "Duplicate finish request for " + r);
3935 return false;
3936 }
3937
3938 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003939 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003940 System.identityHashCode(r),
3941 r.task.taskId, r.shortComponentName, reason);
3942 r.task.numActivities--;
3943 if (r.frontOfTask && index < (mHistory.size()-1)) {
3944 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3945 if (next.task == r.task) {
3946 next.frontOfTask = true;
3947 }
3948 }
3949
3950 r.pauseKeyDispatchingLocked();
3951 if (mFocusedActivity == r) {
3952 setFocusedActivityLocked(topRunningActivityLocked(null));
3953 }
3954
3955 // send the result
3956 HistoryRecord resultTo = r.resultTo;
3957 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003958 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3959 + " who=" + r.resultWho + " req=" + r.requestCode
3960 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003961 if (r.info.applicationInfo.uid > 0) {
3962 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3963 r.packageName, resultData, r);
3964 }
3965 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3966 resultData);
3967 r.resultTo = null;
3968 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003969 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003970
3971 // Make sure this HistoryRecord is not holding on to other resources,
3972 // because clients have remote IPC references to this object so we
3973 // can't assume that will go away and want to avoid circular IPC refs.
3974 r.results = null;
3975 r.pendingResults = null;
3976 r.newIntents = null;
3977 r.icicle = null;
3978
3979 if (mPendingThumbnails.size() > 0) {
3980 // There are clients waiting to receive thumbnails so, in case
3981 // this is an activity that someone is waiting for, add it
3982 // to the pending list so we can correctly update the clients.
3983 mCancelledThumbnails.add(r);
3984 }
3985
3986 if (mResumedActivity == r) {
3987 boolean endTask = index <= 0
3988 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3989 if (DEBUG_TRANSITION) Log.v(TAG,
3990 "Prepare close transition: finishing " + r);
3991 mWindowManager.prepareAppTransition(endTask
3992 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3993 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3994
3995 // Tell window manager to prepare for this one to be removed.
3996 mWindowManager.setAppVisibility(r, false);
3997
3998 if (mPausingActivity == null) {
3999 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4000 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4001 startPausingLocked(false, false);
4002 }
4003
4004 } else if (r.state != ActivityState.PAUSING) {
4005 // If the activity is PAUSING, we will complete the finish once
4006 // it is done pausing; else we can just directly finish it here.
4007 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4008 return finishCurrentActivityLocked(r, index,
4009 FINISH_AFTER_PAUSE) == null;
4010 } else {
4011 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4012 }
4013
4014 return false;
4015 }
4016
4017 private static final int FINISH_IMMEDIATELY = 0;
4018 private static final int FINISH_AFTER_PAUSE = 1;
4019 private static final int FINISH_AFTER_VISIBLE = 2;
4020
4021 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4022 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004023 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004024 if (index < 0) {
4025 return null;
4026 }
4027
4028 return finishCurrentActivityLocked(r, index, mode);
4029 }
4030
4031 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4032 int index, int mode) {
4033 // First things first: if this activity is currently visible,
4034 // and the resumed activity is not yet visible, then hold off on
4035 // finishing until the resumed one becomes visible.
4036 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4037 if (!mStoppingActivities.contains(r)) {
4038 mStoppingActivities.add(r);
4039 if (mStoppingActivities.size() > 3) {
4040 // If we already have a few activities waiting to stop,
4041 // then give up on things going idle and start clearing
4042 // them out.
4043 Message msg = Message.obtain();
4044 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4045 mHandler.sendMessage(msg);
4046 }
4047 }
4048 r.state = ActivityState.STOPPING;
4049 updateOomAdjLocked();
4050 return r;
4051 }
4052
4053 // make sure the record is cleaned out of other places.
4054 mStoppingActivities.remove(r);
4055 mWaitingVisibleActivities.remove(r);
4056 if (mResumedActivity == r) {
4057 mResumedActivity = null;
4058 }
4059 final ActivityState prevState = r.state;
4060 r.state = ActivityState.FINISHING;
4061
4062 if (mode == FINISH_IMMEDIATELY
4063 || prevState == ActivityState.STOPPED
4064 || prevState == ActivityState.INITIALIZING) {
4065 // If this activity is already stopped, we can just finish
4066 // it right now.
4067 return destroyActivityLocked(r, true) ? null : r;
4068 } else {
4069 // Need to go through the full pause cycle to get this
4070 // activity into the stopped state and then finish it.
4071 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4072 mFinishingActivities.add(r);
4073 resumeTopActivityLocked(null);
4074 }
4075 return r;
4076 }
4077
4078 /**
4079 * This is the internal entry point for handling Activity.finish().
4080 *
4081 * @param token The Binder token referencing the Activity we want to finish.
4082 * @param resultCode Result code, if any, from this Activity.
4083 * @param resultData Result data (Intent), if any, from this Activity.
4084 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004085 * @return Returns true if the activity successfully finished, or false if it is still running.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004086 */
4087 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4088 // Refuse possible leaked file descriptors
4089 if (resultData != null && resultData.hasFileDescriptors() == true) {
4090 throw new IllegalArgumentException("File descriptors passed in Intent");
4091 }
4092
4093 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004094 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004095 // Find the first activity that is not finishing.
4096 HistoryRecord next = topRunningActivityLocked(token, 0);
4097 if (next != null) {
4098 // ask watcher if this is allowed
4099 boolean resumeOK = true;
4100 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004101 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004102 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004103 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004104 }
4105
4106 if (!resumeOK) {
4107 return false;
4108 }
4109 }
4110 }
4111 final long origId = Binder.clearCallingIdentity();
4112 boolean res = requestFinishActivityLocked(token, resultCode,
4113 resultData, "app-request");
4114 Binder.restoreCallingIdentity(origId);
4115 return res;
4116 }
4117 }
4118
4119 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4120 String resultWho, int requestCode, int resultCode, Intent data) {
4121
4122 if (callingUid > 0) {
4123 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4124 data, r);
4125 }
4126
The Android Open Source Project10592532009-03-18 17:39:46 -07004127 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4128 + " : who=" + resultWho + " req=" + requestCode
4129 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004130 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4131 try {
4132 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4133 list.add(new ResultInfo(resultWho, requestCode,
4134 resultCode, data));
4135 r.app.thread.scheduleSendResult(r, list);
4136 return;
4137 } catch (Exception e) {
4138 Log.w(TAG, "Exception thrown sending result to " + r, e);
4139 }
4140 }
4141
4142 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4143 }
4144
4145 public final void finishSubActivity(IBinder token, String resultWho,
4146 int requestCode) {
4147 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004148 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004149 if (index < 0) {
4150 return;
4151 }
4152 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4153
4154 final long origId = Binder.clearCallingIdentity();
4155
4156 int i;
4157 for (i=mHistory.size()-1; i>=0; i--) {
4158 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4159 if (r.resultTo == self && r.requestCode == requestCode) {
4160 if ((r.resultWho == null && resultWho == null) ||
4161 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4162 finishActivityLocked(r, i,
4163 Activity.RESULT_CANCELED, null, "request-sub");
4164 }
4165 }
4166 }
4167
4168 Binder.restoreCallingIdentity(origId);
4169 }
4170 }
4171
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004172 public void overridePendingTransition(IBinder token, String packageName,
4173 int enterAnim, int exitAnim) {
4174 synchronized(this) {
4175 int index = indexOfTokenLocked(token);
4176 if (index < 0) {
4177 return;
4178 }
4179 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4180
4181 final long origId = Binder.clearCallingIdentity();
4182
4183 if (self.state == ActivityState.RESUMED
4184 || self.state == ActivityState.PAUSING) {
4185 mWindowManager.overridePendingAppTransition(packageName,
4186 enterAnim, exitAnim);
4187 }
4188
4189 Binder.restoreCallingIdentity(origId);
4190 }
4191 }
4192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004193 /**
4194 * Perform clean-up of service connections in an activity record.
4195 */
4196 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4197 // Throw away any services that have been bound by this activity.
4198 if (r.connections != null) {
4199 Iterator<ConnectionRecord> it = r.connections.iterator();
4200 while (it.hasNext()) {
4201 ConnectionRecord c = it.next();
4202 removeConnectionLocked(c, null, r);
4203 }
4204 r.connections = null;
4205 }
4206 }
4207
4208 /**
4209 * Perform the common clean-up of an activity record. This is called both
4210 * as part of destroyActivityLocked() (when destroying the client-side
4211 * representation) and cleaning things up as a result of its hosting
4212 * processing going away, in which case there is no remaining client-side
4213 * state to destroy so only the cleanup here is needed.
4214 */
4215 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4216 if (mResumedActivity == r) {
4217 mResumedActivity = null;
4218 }
4219 if (mFocusedActivity == r) {
4220 mFocusedActivity = null;
4221 }
4222
4223 r.configDestroy = false;
4224 r.frozenBeforeDestroy = false;
4225
4226 // Make sure this record is no longer in the pending finishes list.
4227 // This could happen, for example, if we are trimming activities
4228 // down to the max limit while they are still waiting to finish.
4229 mFinishingActivities.remove(r);
4230 mWaitingVisibleActivities.remove(r);
4231
4232 // Remove any pending results.
4233 if (r.finishing && r.pendingResults != null) {
4234 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4235 PendingIntentRecord rec = apr.get();
4236 if (rec != null) {
4237 cancelIntentSenderLocked(rec, false);
4238 }
4239 }
4240 r.pendingResults = null;
4241 }
4242
4243 if (cleanServices) {
4244 cleanUpActivityServicesLocked(r);
4245 }
4246
4247 if (mPendingThumbnails.size() > 0) {
4248 // There are clients waiting to receive thumbnails so, in case
4249 // this is an activity that someone is waiting for, add it
4250 // to the pending list so we can correctly update the clients.
4251 mCancelledThumbnails.add(r);
4252 }
4253
4254 // Get rid of any pending idle timeouts.
4255 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4256 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4257 }
4258
4259 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4260 if (r.state != ActivityState.DESTROYED) {
4261 mHistory.remove(r);
4262 r.inHistory = false;
4263 r.state = ActivityState.DESTROYED;
4264 mWindowManager.removeAppToken(r);
4265 if (VALIDATE_TOKENS) {
4266 mWindowManager.validateAppTokens(mHistory);
4267 }
4268 cleanUpActivityServicesLocked(r);
4269 removeActivityUriPermissionsLocked(r);
4270 }
4271 }
4272
4273 /**
4274 * Destroy the current CLIENT SIDE instance of an activity. This may be
4275 * called both when actually finishing an activity, or when performing
4276 * a configuration switch where we destroy the current client-side object
4277 * but then create a new client-side object for this same HistoryRecord.
4278 */
4279 private final boolean destroyActivityLocked(HistoryRecord r,
4280 boolean removeFromApp) {
4281 if (DEBUG_SWITCH) Log.v(
4282 TAG, "Removing activity: token=" + r
4283 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004284 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004285 System.identityHashCode(r),
4286 r.task.taskId, r.shortComponentName);
4287
4288 boolean removedFromHistory = false;
4289
4290 cleanUpActivityLocked(r, false);
4291
Dianne Hackborn03abb812010-01-04 18:43:19 -08004292 final boolean hadApp = r.app != null;
4293
4294 if (hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004295 if (removeFromApp) {
4296 int idx = r.app.activities.indexOf(r);
4297 if (idx >= 0) {
4298 r.app.activities.remove(idx);
4299 }
4300 if (r.persistent) {
4301 decPersistentCountLocked(r.app);
4302 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004303 if (r.app.activities.size() == 0) {
4304 // No longer have activities, so update location in
4305 // LRU list.
4306 updateLruProcessLocked(r.app, true, false);
4307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004308 }
4309
4310 boolean skipDestroy = false;
4311
4312 try {
4313 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4314 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4315 r.configChangeFlags);
4316 } catch (Exception e) {
4317 // We can just ignore exceptions here... if the process
4318 // has crashed, our death notification will clean things
4319 // up.
4320 //Log.w(TAG, "Exception thrown during finish", e);
4321 if (r.finishing) {
4322 removeActivityFromHistoryLocked(r);
4323 removedFromHistory = true;
4324 skipDestroy = true;
4325 }
4326 }
4327
4328 r.app = null;
4329 r.nowVisible = false;
4330
4331 if (r.finishing && !skipDestroy) {
4332 r.state = ActivityState.DESTROYING;
4333 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4334 msg.obj = r;
4335 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4336 } else {
4337 r.state = ActivityState.DESTROYED;
4338 }
4339 } else {
4340 // remove this record from the history.
4341 if (r.finishing) {
4342 removeActivityFromHistoryLocked(r);
4343 removedFromHistory = true;
4344 } else {
4345 r.state = ActivityState.DESTROYED;
4346 }
4347 }
4348
4349 r.configChangeFlags = 0;
4350
Dianne Hackborn03abb812010-01-04 18:43:19 -08004351 if (!mLRUActivities.remove(r) && hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004352 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4353 }
4354
4355 return removedFromHistory;
4356 }
4357
Dianne Hackborn03abb812010-01-04 18:43:19 -08004358 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004359 int i = list.size();
4360 if (localLOGV) Log.v(
4361 TAG, "Removing app " + app + " from list " + list
4362 + " with " + i + " entries");
4363 while (i > 0) {
4364 i--;
4365 HistoryRecord r = (HistoryRecord)list.get(i);
4366 if (localLOGV) Log.v(
4367 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4368 if (r.app == app) {
4369 if (localLOGV) Log.v(TAG, "Removing this entry!");
4370 list.remove(i);
4371 }
4372 }
4373 }
4374
4375 /**
4376 * Main function for removing an existing process from the activity manager
4377 * as a result of that process going away. Clears out all connections
4378 * to the process.
4379 */
4380 private final void handleAppDiedLocked(ProcessRecord app,
4381 boolean restarting) {
4382 cleanUpApplicationRecordLocked(app, restarting, -1);
4383 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004384 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004385 }
4386
4387 // Just in case...
4388 if (mPausingActivity != null && mPausingActivity.app == app) {
4389 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4390 mPausingActivity = null;
4391 }
4392 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4393 mLastPausedActivity = null;
4394 }
4395
4396 // Remove this application's activities from active lists.
4397 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4398 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4399 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4400 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4401
4402 boolean atTop = true;
4403 boolean hasVisibleActivities = false;
4404
4405 // Clean out the history list.
4406 int i = mHistory.size();
4407 if (localLOGV) Log.v(
4408 TAG, "Removing app " + app + " from history with " + i + " entries");
4409 while (i > 0) {
4410 i--;
4411 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4412 if (localLOGV) Log.v(
4413 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4414 if (r.app == app) {
4415 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4416 if (localLOGV) Log.v(
4417 TAG, "Removing this entry! frozen=" + r.haveState
4418 + " finishing=" + r.finishing);
4419 mHistory.remove(i);
4420
4421 r.inHistory = false;
4422 mWindowManager.removeAppToken(r);
4423 if (VALIDATE_TOKENS) {
4424 mWindowManager.validateAppTokens(mHistory);
4425 }
4426 removeActivityUriPermissionsLocked(r);
4427
4428 } else {
4429 // We have the current state for this activity, so
4430 // it can be restarted later when needed.
4431 if (localLOGV) Log.v(
4432 TAG, "Keeping entry, setting app to null");
4433 if (r.visible) {
4434 hasVisibleActivities = true;
4435 }
4436 r.app = null;
4437 r.nowVisible = false;
4438 if (!r.haveState) {
4439 r.icicle = null;
4440 }
4441 }
4442
4443 cleanUpActivityLocked(r, true);
4444 r.state = ActivityState.STOPPED;
4445 }
4446 atTop = false;
4447 }
4448
4449 app.activities.clear();
4450
4451 if (app.instrumentationClass != null) {
4452 Log.w(TAG, "Crash of app " + app.processName
4453 + " running instrumentation " + app.instrumentationClass);
4454 Bundle info = new Bundle();
4455 info.putString("shortMsg", "Process crashed.");
4456 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4457 }
4458
4459 if (!restarting) {
4460 if (!resumeTopActivityLocked(null)) {
4461 // If there was nothing to resume, and we are not already
4462 // restarting this process, but there is a visible activity that
4463 // is hosted by the process... then make sure all visible
4464 // activities are running, taking care of restarting this
4465 // process.
4466 if (hasVisibleActivities) {
4467 ensureActivitiesVisibleLocked(null, 0);
4468 }
4469 }
4470 }
4471 }
4472
4473 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4474 IBinder threadBinder = thread.asBinder();
4475
4476 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004477 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4478 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004479 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4480 return i;
4481 }
4482 }
4483 return -1;
4484 }
4485
4486 private final ProcessRecord getRecordForAppLocked(
4487 IApplicationThread thread) {
4488 if (thread == null) {
4489 return null;
4490 }
4491
4492 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004493 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004494 }
4495
4496 private final void appDiedLocked(ProcessRecord app, int pid,
4497 IApplicationThread thread) {
4498
4499 mProcDeaths[0]++;
4500
4501 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4502 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4503 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004504 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004505 if (localLOGV) Log.v(
4506 TAG, "Dying app: " + app + ", pid: " + pid
4507 + ", thread: " + thread.asBinder());
4508 boolean doLowMem = app.instrumentationClass == null;
4509 handleAppDiedLocked(app, false);
4510
4511 if (doLowMem) {
4512 // If there are no longer any background processes running,
4513 // and the app that died was not running instrumentation,
4514 // then tell everyone we are now low on memory.
4515 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004516 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4517 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004518 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4519 haveBg = true;
4520 break;
4521 }
4522 }
4523
4524 if (!haveBg) {
4525 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004526 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004527 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004528 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4529 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004530 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004531 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4532 // The low memory report is overriding any current
4533 // state for a GC request. Make sure to do
4534 // visible/foreground processes first.
4535 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4536 rec.lastRequestedGc = 0;
4537 } else {
4538 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004539 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004540 rec.reportLowMemory = true;
4541 rec.lastLowMemory = now;
4542 mProcessesToGc.remove(rec);
4543 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004544 }
4545 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004546 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004547 }
4548 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004549 } else if (DEBUG_PROCESSES) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004550 Log.d(TAG, "Received spurious death notification for thread "
4551 + thread.asBinder());
4552 }
4553 }
4554
Dan Egnor42471dd2010-01-07 17:25:22 -08004555 /**
4556 * If a stack trace dump file is configured, dump process stack traces.
4557 * @param pids of dalvik VM processes to dump stack traces for
4558 * @return file containing stack traces, or null if no dump file is configured
4559 */
4560 private static File dumpStackTraces(ArrayList<Integer> pids) {
4561 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4562 if (tracesPath == null || tracesPath.length() == 0) {
4563 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004564 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004565
4566 File tracesFile = new File(tracesPath);
4567 try {
4568 File tracesDir = tracesFile.getParentFile();
4569 if (!tracesDir.exists()) tracesFile.mkdirs();
4570 FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
4571
4572 if (tracesFile.exists()) tracesFile.delete();
4573 tracesFile.createNewFile();
4574 FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
4575 } catch (IOException e) {
4576 Log.w(TAG, "Unable to prepare ANR traces file: " + tracesPath, e);
4577 return null;
4578 }
4579
4580 // Use a FileObserver to detect when traces finish writing.
4581 // The order of traces is considered important to maintain for legibility.
4582 FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
4583 public synchronized void onEvent(int event, String path) { notify(); }
4584 };
4585
4586 try {
4587 observer.startWatching();
4588 int num = pids.size();
4589 for (int i = 0; i < num; i++) {
4590 synchronized (observer) {
4591 Process.sendSignal(pids.get(i), Process.SIGNAL_QUIT);
4592 observer.wait(200); // Wait for write-close, give up after 200msec
4593 }
4594 }
4595 } catch (InterruptedException e) {
4596 Log.wtf(TAG, e);
4597 } finally {
4598 observer.stopWatching();
4599 }
4600
4601 return tracesFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004602 }
4603
Dan Egnor42471dd2010-01-07 17:25:22 -08004604 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4605 HistoryRecord parent, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004606 if (app.notResponding || app.crashing) {
4607 return;
4608 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004610 // Log the ANR to the event log.
Dan Egnor2780e732010-01-22 14:47:35 -08004611 EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
4612 annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004613
Dan Egnor42471dd2010-01-07 17:25:22 -08004614 // Dump thread traces as quickly as we can, starting with "interesting" processes.
4615 ArrayList<Integer> pids = new ArrayList<Integer>(20);
4616 pids.add(app.pid);
4617
4618 int parentPid = app.pid;
4619 if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
4620 if (parentPid != app.pid) pids.add(parentPid);
4621
4622 if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
4623
4624 for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
4625 ProcessRecord r = mLruProcesses.get(i);
4626 if (r != null && r.thread != null) {
4627 int pid = r.pid;
4628 if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629 }
4630 }
4631
Dan Egnor42471dd2010-01-07 17:25:22 -08004632 File tracesFile = dumpStackTraces(pids);
4633
4634 // Log the ANR to the main log.
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004635 StringBuilder info = mStringBuilder;
4636 info.setLength(0);
Dan Egnor42471dd2010-01-07 17:25:22 -08004637 info.append("ANR in ").append(app.processName);
4638 if (activity != null && activity.shortComponentName != null) {
4639 info.append(" (").append(activity.shortComponentName).append(")");
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004640 }
Eric Rowe6f4f6192010-02-17 18:29:04 -08004641 info.append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004642 if (annotation != null) {
Eric Rowe6f4f6192010-02-17 18:29:04 -08004643 info.append("Reason: ").append(annotation).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004644 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004645 if (parent != null && parent != activity) {
Eric Rowe6f4f6192010-02-17 18:29:04 -08004646 info.append("Parent: ").append(parent.shortComponentName).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004648
Dan Egnor42471dd2010-01-07 17:25:22 -08004649 String cpuInfo = null;
4650 if (MONITOR_CPU_USAGE) {
4651 updateCpuStatsNow();
4652 synchronized (mProcessStatsThread) { cpuInfo = mProcessStats.printCurrentState(); }
4653 info.append(cpuInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004654 }
4655
Dan Egnor42471dd2010-01-07 17:25:22 -08004656 Log.e(TAG, info.toString());
4657 if (tracesFile == null) {
4658 // There is no trace file, so dump (only) the alleged culprit's threads to the log
4659 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4660 }
4661
4662 addErrorToDropBox("anr", app, activity, parent, annotation, cpuInfo, tracesFile, null);
4663
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004664 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004665 try {
Dan Egnor42471dd2010-01-07 17:25:22 -08004666 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
4667 int res = mController.appNotResponding(app.processName, app.pid, info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004668 if (res != 0) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004669 if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
4670 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004671 }
4672 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004673 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004674 }
4675 }
4676
Dan Egnor42471dd2010-01-07 17:25:22 -08004677 // Unless configured otherwise, swallow ANRs in background processes & kill the process.
4678 boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
4679 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
4680 if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
4681 Process.killProcess(app.pid);
4682 return;
4683 }
4684
4685 // Set the app's notResponding state, and look up the errorReportReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004686 makeAppNotRespondingLocked(app,
4687 activity != null ? activity.shortComponentName : null,
4688 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004689 info.toString());
Dan Egnor42471dd2010-01-07 17:25:22 -08004690
4691 // Bring up the infamous App Not Responding dialog
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004692 Message msg = Message.obtain();
4693 HashMap map = new HashMap();
4694 msg.what = SHOW_NOT_RESPONDING_MSG;
4695 msg.obj = map;
4696 map.put("app", app);
4697 if (activity != null) {
4698 map.put("activity", activity);
4699 }
4700
4701 mHandler.sendMessage(msg);
4702 return;
4703 }
4704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004705 private final void decPersistentCountLocked(ProcessRecord app)
4706 {
4707 app.persistentActivities--;
4708 if (app.persistentActivities > 0) {
4709 // Still more of 'em...
4710 return;
4711 }
4712 if (app.persistent) {
4713 // Ah, but the application itself is persistent. Whatever!
4714 return;
4715 }
4716
4717 // App is no longer persistent... make sure it and the ones
4718 // following it in the LRU list have the correc oom_adj.
4719 updateOomAdjLocked();
4720 }
4721
4722 public void setPersistent(IBinder token, boolean isPersistent) {
4723 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4724 != PackageManager.PERMISSION_GRANTED) {
4725 String msg = "Permission Denial: setPersistent() from pid="
4726 + Binder.getCallingPid()
4727 + ", uid=" + Binder.getCallingUid()
4728 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4729 Log.w(TAG, msg);
4730 throw new SecurityException(msg);
4731 }
4732
4733 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004734 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004735 if (index < 0) {
4736 return;
4737 }
4738 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4739 ProcessRecord app = r.app;
4740
4741 if (localLOGV) Log.v(
4742 TAG, "Setting persistence " + isPersistent + ": " + r);
4743
4744 if (isPersistent) {
4745 if (r.persistent) {
4746 // Okay okay, I heard you already!
4747 if (localLOGV) Log.v(TAG, "Already persistent!");
4748 return;
4749 }
4750 r.persistent = true;
4751 app.persistentActivities++;
4752 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4753 if (app.persistentActivities > 1) {
4754 // We aren't the first...
4755 if (localLOGV) Log.v(TAG, "Not the first!");
4756 return;
4757 }
4758 if (app.persistent) {
4759 // This would be redundant.
4760 if (localLOGV) Log.v(TAG, "App is persistent!");
4761 return;
4762 }
4763
4764 // App is now persistent... make sure it and the ones
4765 // following it now have the correct oom_adj.
4766 final long origId = Binder.clearCallingIdentity();
4767 updateOomAdjLocked();
4768 Binder.restoreCallingIdentity(origId);
4769
4770 } else {
4771 if (!r.persistent) {
4772 // Okay okay, I heard you already!
4773 return;
4774 }
4775 r.persistent = false;
4776 final long origId = Binder.clearCallingIdentity();
4777 decPersistentCountLocked(app);
4778 Binder.restoreCallingIdentity(origId);
4779
4780 }
4781 }
4782 }
4783
4784 public boolean clearApplicationUserData(final String packageName,
4785 final IPackageDataObserver observer) {
4786 int uid = Binder.getCallingUid();
4787 int pid = Binder.getCallingPid();
4788 long callingId = Binder.clearCallingIdentity();
4789 try {
4790 IPackageManager pm = ActivityThread.getPackageManager();
4791 int pkgUid = -1;
4792 synchronized(this) {
4793 try {
4794 pkgUid = pm.getPackageUid(packageName);
4795 } catch (RemoteException e) {
4796 }
4797 if (pkgUid == -1) {
4798 Log.w(TAG, "Invalid packageName:" + packageName);
4799 return false;
4800 }
4801 if (uid == pkgUid || checkComponentPermission(
4802 android.Manifest.permission.CLEAR_APP_USER_DATA,
4803 pid, uid, -1)
4804 == PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08004805 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004806 } else {
4807 throw new SecurityException(pid+" does not have permission:"+
4808 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4809 "for process:"+packageName);
4810 }
4811 }
4812
4813 try {
4814 //clear application user data
4815 pm.clearApplicationUserData(packageName, observer);
4816 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4817 Uri.fromParts("package", packageName, null));
4818 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4819 broadcastIntentLocked(null, null, intent,
4820 null, null, 0, null, null, null,
4821 false, false, MY_PID, Process.SYSTEM_UID);
4822 } catch (RemoteException e) {
4823 }
4824 } finally {
4825 Binder.restoreCallingIdentity(callingId);
4826 }
4827 return true;
4828 }
4829
Dianne Hackborn03abb812010-01-04 18:43:19 -08004830 public void killBackgroundProcesses(final String packageName) {
4831 if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
4832 != PackageManager.PERMISSION_GRANTED &&
4833 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4834 != PackageManager.PERMISSION_GRANTED) {
4835 String msg = "Permission Denial: killBackgroundProcesses() from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004836 + Binder.getCallingPid()
4837 + ", uid=" + Binder.getCallingUid()
Dianne Hackborn03abb812010-01-04 18:43:19 -08004838 + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004839 Log.w(TAG, msg);
4840 throw new SecurityException(msg);
4841 }
4842
4843 long callingId = Binder.clearCallingIdentity();
4844 try {
4845 IPackageManager pm = ActivityThread.getPackageManager();
4846 int pkgUid = -1;
4847 synchronized(this) {
4848 try {
4849 pkgUid = pm.getPackageUid(packageName);
4850 } catch (RemoteException e) {
4851 }
4852 if (pkgUid == -1) {
4853 Log.w(TAG, "Invalid packageName: " + packageName);
4854 return;
4855 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004856 killPackageProcessesLocked(packageName, pkgUid,
4857 SECONDARY_SERVER_ADJ, false);
4858 }
4859 } finally {
4860 Binder.restoreCallingIdentity(callingId);
4861 }
4862 }
4863
4864 public void forceStopPackage(final String packageName) {
4865 if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
4866 != PackageManager.PERMISSION_GRANTED) {
4867 String msg = "Permission Denial: forceStopPackage() from pid="
4868 + Binder.getCallingPid()
4869 + ", uid=" + Binder.getCallingUid()
4870 + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
4871 Log.w(TAG, msg);
4872 throw new SecurityException(msg);
4873 }
4874
4875 long callingId = Binder.clearCallingIdentity();
4876 try {
4877 IPackageManager pm = ActivityThread.getPackageManager();
4878 int pkgUid = -1;
4879 synchronized(this) {
4880 try {
4881 pkgUid = pm.getPackageUid(packageName);
4882 } catch (RemoteException e) {
4883 }
4884 if (pkgUid == -1) {
4885 Log.w(TAG, "Invalid packageName: " + packageName);
4886 return;
4887 }
4888 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004889 }
4890 } finally {
4891 Binder.restoreCallingIdentity(callingId);
4892 }
4893 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004894
4895 /*
4896 * The pkg name and uid have to be specified.
4897 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4898 */
4899 public void killApplicationWithUid(String pkg, int uid) {
4900 if (pkg == null) {
4901 return;
4902 }
4903 // Make sure the uid is valid.
4904 if (uid < 0) {
4905 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4906 return;
4907 }
4908 int callerUid = Binder.getCallingUid();
4909 // Only the system server can kill an application
4910 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004911 // Post an aysnc message to kill the application
4912 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4913 msg.arg1 = uid;
4914 msg.arg2 = 0;
4915 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004916 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004917 } else {
4918 throw new SecurityException(callerUid + " cannot kill pkg: " +
4919 pkg);
4920 }
4921 }
4922
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004923 public void closeSystemDialogs(String reason) {
4924 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4925 if (reason != null) {
4926 intent.putExtra("reason", reason);
4927 }
4928
4929 final int uid = Binder.getCallingUid();
4930 final long origId = Binder.clearCallingIdentity();
4931 synchronized (this) {
4932 int i = mWatchers.beginBroadcast();
4933 while (i > 0) {
4934 i--;
4935 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4936 if (w != null) {
4937 try {
4938 w.closingSystemDialogs(reason);
4939 } catch (RemoteException e) {
4940 }
4941 }
4942 }
4943 mWatchers.finishBroadcast();
4944
Dianne Hackbornffa42482009-09-23 22:20:11 -07004945 mWindowManager.closeSystemDialogs(reason);
4946
4947 for (i=mHistory.size()-1; i>=0; i--) {
4948 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4949 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4950 finishActivityLocked(r, i,
4951 Activity.RESULT_CANCELED, null, "close-sys");
4952 }
4953 }
4954
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004955 broadcastIntentLocked(null, null, intent, null,
4956 null, 0, null, null, null, false, false, -1, uid);
4957 }
4958 Binder.restoreCallingIdentity(origId);
4959 }
4960
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004961 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004962 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004963 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4964 for (int i=pids.length-1; i>=0; i--) {
4965 infos[i] = new Debug.MemoryInfo();
4966 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004967 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004968 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004969 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004970
4971 public void killApplicationProcess(String processName, int uid) {
4972 if (processName == null) {
4973 return;
4974 }
4975
4976 int callerUid = Binder.getCallingUid();
4977 // Only the system server can kill an application
4978 if (callerUid == Process.SYSTEM_UID) {
4979 synchronized (this) {
4980 ProcessRecord app = getProcessRecordLocked(processName, uid);
4981 if (app != null) {
4982 try {
4983 app.thread.scheduleSuicide();
4984 } catch (RemoteException e) {
4985 // If the other end already died, then our work here is done.
4986 }
4987 } else {
4988 Log.w(TAG, "Process/uid not found attempting kill of "
4989 + processName + " / " + uid);
4990 }
4991 }
4992 } else {
4993 throw new SecurityException(callerUid + " cannot kill app process: " +
4994 processName);
4995 }
4996 }
4997
Dianne Hackborn03abb812010-01-04 18:43:19 -08004998 private void forceStopPackageLocked(final String packageName, int uid) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08004999 forceStopPackageLocked(packageName, uid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005000 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5001 Uri.fromParts("package", packageName, null));
5002 intent.putExtra(Intent.EXTRA_UID, uid);
5003 broadcastIntentLocked(null, null, intent,
5004 null, null, 0, null, null, null,
5005 false, false, MY_PID, Process.SYSTEM_UID);
5006 }
5007
Dianne Hackborn03abb812010-01-04 18:43:19 -08005008 private final void killPackageProcessesLocked(String packageName, int uid,
5009 int minOomAdj, boolean callerWillRestart) {
5010 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005011
Dianne Hackborn03abb812010-01-04 18:43:19 -08005012 // Remove all processes this package may have touched: all with the
5013 // same UID (except for the system or root user), and all whose name
5014 // matches the package name.
5015 final String procNamePrefix = packageName + ":";
5016 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5017 final int NA = apps.size();
5018 for (int ia=0; ia<NA; ia++) {
5019 ProcessRecord app = apps.valueAt(ia);
5020 if (app.removed) {
5021 procs.add(app);
5022 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5023 || app.processName.equals(packageName)
5024 || app.processName.startsWith(procNamePrefix)) {
5025 if (app.setAdj >= minOomAdj) {
5026 app.removed = true;
5027 procs.add(app);
5028 }
5029 }
5030 }
5031 }
5032
5033 int N = procs.size();
5034 for (int i=0; i<N; i++) {
5035 removeProcessLocked(procs.get(i), callerWillRestart);
5036 }
5037 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005038
Dianne Hackborn03abb812010-01-04 18:43:19 -08005039 private final void forceStopPackageLocked(String name, int uid,
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005040 boolean callerWillRestart, boolean purgeCache) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005041 int i, N;
5042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005043 if (uid < 0) {
5044 try {
5045 uid = ActivityThread.getPackageManager().getPackageUid(name);
5046 } catch (RemoteException e) {
5047 }
5048 }
5049
Dianne Hackborn03abb812010-01-04 18:43:19 -08005050 Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
5051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005052 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5053 while (badApps.hasNext()) {
5054 SparseArray<Long> ba = badApps.next();
5055 if (ba.get(uid) != null) {
5056 badApps.remove();
5057 }
5058 }
5059
Dianne Hackborn03abb812010-01-04 18:43:19 -08005060 killPackageProcessesLocked(name, uid, -100, callerWillRestart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005061
5062 for (i=mHistory.size()-1; i>=0; i--) {
5063 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5064 if (r.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005065 Log.i(TAG, " Force finishing activity " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005066 if (r.app != null) {
5067 r.app.removed = true;
5068 }
5069 r.app = null;
5070 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5071 }
5072 }
5073
5074 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5075 for (ServiceRecord service : mServices.values()) {
5076 if (service.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005077 Log.i(TAG, " Force stopping service " + service);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005078 if (service.app != null) {
5079 service.app.removed = true;
5080 }
5081 service.app = null;
5082 services.add(service);
5083 }
5084 }
5085
5086 N = services.size();
5087 for (i=0; i<N; i++) {
5088 bringDownServiceLocked(services.get(i), true);
5089 }
5090
5091 resumeTopActivityLocked(null);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005092 if (purgeCache) {
5093 AttributeCache ac = AttributeCache.instance();
5094 if (ac != null) {
5095 ac.removePackage(name);
5096 }
5097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005098 }
5099
5100 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5101 final String name = app.processName;
5102 final int uid = app.info.uid;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005103 if (DEBUG_PROCESSES) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005104 TAG, "Force removing process " + app + " (" + name
5105 + "/" + uid + ")");
5106
5107 mProcessNames.remove(name, uid);
5108 boolean needRestart = false;
5109 if (app.pid > 0 && app.pid != MY_PID) {
5110 int pid = app.pid;
5111 synchronized (mPidsSelfLocked) {
5112 mPidsSelfLocked.remove(pid);
5113 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5114 }
5115 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005116 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005117 Process.killProcess(pid);
5118
5119 if (app.persistent) {
5120 if (!callerWillRestart) {
5121 addAppLocked(app.info);
5122 } else {
5123 needRestart = true;
5124 }
5125 }
5126 } else {
5127 mRemovedProcesses.add(app);
5128 }
5129
5130 return needRestart;
5131 }
5132
5133 private final void processStartTimedOutLocked(ProcessRecord app) {
5134 final int pid = app.pid;
5135 boolean gone = false;
5136 synchronized (mPidsSelfLocked) {
5137 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5138 if (knownApp != null && knownApp.thread == null) {
5139 mPidsSelfLocked.remove(pid);
5140 gone = true;
5141 }
5142 }
5143
5144 if (gone) {
5145 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005146 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005147 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005148 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005149 // Take care of any launching providers waiting for this process.
5150 checkAppInLaunchingProvidersLocked(app, true);
5151 // Take care of any services that are waiting for the process.
5152 for (int i=0; i<mPendingServices.size(); i++) {
5153 ServiceRecord sr = mPendingServices.get(i);
5154 if (app.info.uid == sr.appInfo.uid
5155 && app.processName.equals(sr.processName)) {
5156 Log.w(TAG, "Forcing bringing down service: " + sr);
5157 mPendingServices.remove(i);
5158 i--;
5159 bringDownServiceLocked(sr, true);
5160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005161 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005162 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005163 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5164 Log.w(TAG, "Unattached app died before backup, skipping");
5165 try {
5166 IBackupManager bm = IBackupManager.Stub.asInterface(
5167 ServiceManager.getService(Context.BACKUP_SERVICE));
5168 bm.agentDisconnected(app.info.packageName);
5169 } catch (RemoteException e) {
5170 // Can't happen; the backup manager is local
5171 }
5172 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005173 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5174 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5175 mPendingBroadcast = null;
5176 scheduleBroadcastsLocked();
5177 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005178 } else {
5179 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5180 }
5181 }
5182
5183 private final boolean attachApplicationLocked(IApplicationThread thread,
5184 int pid) {
5185
5186 // Find the application record that is being attached... either via
5187 // the pid if we are running in multiple processes, or just pull the
5188 // next app record if we are emulating process with anonymous threads.
5189 ProcessRecord app;
5190 if (pid != MY_PID && pid >= 0) {
5191 synchronized (mPidsSelfLocked) {
5192 app = mPidsSelfLocked.get(pid);
5193 }
5194 } else if (mStartingProcesses.size() > 0) {
5195 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005196 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005197 } else {
5198 app = null;
5199 }
5200
5201 if (app == null) {
5202 Log.w(TAG, "No pending application record for pid " + pid
5203 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005204 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005205 if (pid > 0 && pid != MY_PID) {
5206 Process.killProcess(pid);
5207 } else {
5208 try {
5209 thread.scheduleExit();
5210 } catch (Exception e) {
5211 // Ignore exceptions.
5212 }
5213 }
5214 return false;
5215 }
5216
5217 // If this application record is still attached to a previous
5218 // process, clean it up now.
5219 if (app.thread != null) {
5220 handleAppDiedLocked(app, true);
5221 }
5222
5223 // Tell the process all about itself.
5224
5225 if (localLOGV) Log.v(
5226 TAG, "Binding process pid " + pid + " to record " + app);
5227
5228 String processName = app.processName;
5229 try {
5230 thread.asBinder().linkToDeath(new AppDeathRecipient(
5231 app, pid, thread), 0);
5232 } catch (RemoteException e) {
5233 app.resetPackageList();
5234 startProcessLocked(app, "link fail", processName);
5235 return false;
5236 }
5237
Doug Zongker2bec3d42009-12-04 12:52:44 -08005238 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005239
5240 app.thread = thread;
5241 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005242 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5243 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005244 app.forcingToForeground = null;
5245 app.foregroundServices = false;
5246 app.debugging = false;
5247
5248 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5249
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005250 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5251 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005252
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005253 if (!normalMode) {
5254 Log.i(TAG, "Launching preboot mode app: " + app);
5255 }
5256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005257 if (localLOGV) Log.v(
5258 TAG, "New app record " + app
5259 + " thread=" + thread.asBinder() + " pid=" + pid);
5260 try {
5261 int testMode = IApplicationThread.DEBUG_OFF;
5262 if (mDebugApp != null && mDebugApp.equals(processName)) {
5263 testMode = mWaitForDebugger
5264 ? IApplicationThread.DEBUG_WAIT
5265 : IApplicationThread.DEBUG_ON;
5266 app.debugging = true;
5267 if (mDebugTransient) {
5268 mDebugApp = mOrigDebugApp;
5269 mWaitForDebugger = mOrigWaitForDebugger;
5270 }
5271 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005272
Christopher Tate181fafa2009-05-14 11:12:14 -07005273 // If the app is being launched for restore or full backup, set it up specially
5274 boolean isRestrictedBackupMode = false;
5275 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5276 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5277 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5278 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005279
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005280 ensurePackageDexOpt(app.instrumentationInfo != null
5281 ? app.instrumentationInfo.packageName
5282 : app.info.packageName);
5283 if (app.instrumentationClass != null) {
5284 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005285 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005286 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5287 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005288 thread.bindApplication(processName, app.instrumentationInfo != null
5289 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005290 app.instrumentationClass, app.instrumentationProfileFile,
5291 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005292 isRestrictedBackupMode || !normalMode,
5293 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005294 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005295 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005296 } catch (Exception e) {
5297 // todo: Yikes! What should we do? For now we will try to
5298 // start another process, but that could easily get us in
5299 // an infinite loop of restarting processes...
5300 Log.w(TAG, "Exception thrown during bind!", e);
5301
5302 app.resetPackageList();
5303 startProcessLocked(app, "bind fail", processName);
5304 return false;
5305 }
5306
5307 // Remove this record from the list of starting applications.
5308 mPersistentStartingProcesses.remove(app);
5309 mProcessesOnHold.remove(app);
5310
5311 boolean badApp = false;
5312 boolean didSomething = false;
5313
5314 // See if the top visible activity is waiting to run in this process...
5315 HistoryRecord hr = topRunningActivityLocked(null);
5316 if (hr != null) {
5317 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5318 && processName.equals(hr.processName)) {
5319 try {
5320 if (realStartActivityLocked(hr, app, true, true)) {
5321 didSomething = true;
5322 }
5323 } catch (Exception e) {
5324 Log.w(TAG, "Exception in new application when starting activity "
5325 + hr.intent.getComponent().flattenToShortString(), e);
5326 badApp = true;
5327 }
5328 } else {
5329 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5330 }
5331 }
5332
5333 // Find any services that should be running in this process...
5334 if (!badApp && mPendingServices.size() > 0) {
5335 ServiceRecord sr = null;
5336 try {
5337 for (int i=0; i<mPendingServices.size(); i++) {
5338 sr = mPendingServices.get(i);
5339 if (app.info.uid != sr.appInfo.uid
5340 || !processName.equals(sr.processName)) {
5341 continue;
5342 }
5343
5344 mPendingServices.remove(i);
5345 i--;
5346 realStartServiceLocked(sr, app);
5347 didSomething = true;
5348 }
5349 } catch (Exception e) {
5350 Log.w(TAG, "Exception in new application when starting service "
5351 + sr.shortName, e);
5352 badApp = true;
5353 }
5354 }
5355
5356 // Check if the next broadcast receiver is in this process...
5357 BroadcastRecord br = mPendingBroadcast;
5358 if (!badApp && br != null && br.curApp == app) {
5359 try {
5360 mPendingBroadcast = null;
5361 processCurBroadcastLocked(br, app);
5362 didSomething = true;
5363 } catch (Exception e) {
5364 Log.w(TAG, "Exception in new application when starting receiver "
5365 + br.curComponent.flattenToShortString(), e);
5366 badApp = true;
5367 logBroadcastReceiverDiscard(br);
5368 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5369 br.resultExtras, br.resultAbort, true);
5370 scheduleBroadcastsLocked();
5371 }
5372 }
5373
Christopher Tate181fafa2009-05-14 11:12:14 -07005374 // Check whether the next backup agent is in this process...
5375 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5376 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005377 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005378 try {
5379 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5380 } catch (Exception e) {
5381 Log.w(TAG, "Exception scheduling backup agent creation: ");
5382 e.printStackTrace();
5383 }
5384 }
5385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005386 if (badApp) {
5387 // todo: Also need to kill application to deal with all
5388 // kinds of exceptions.
5389 handleAppDiedLocked(app, false);
5390 return false;
5391 }
5392
5393 if (!didSomething) {
5394 updateOomAdjLocked();
5395 }
5396
5397 return true;
5398 }
5399
5400 public final void attachApplication(IApplicationThread thread) {
5401 synchronized (this) {
5402 int callingPid = Binder.getCallingPid();
5403 final long origId = Binder.clearCallingIdentity();
5404 attachApplicationLocked(thread, callingPid);
5405 Binder.restoreCallingIdentity(origId);
5406 }
5407 }
5408
Dianne Hackborne88846e2009-09-30 21:34:25 -07005409 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005410 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005411 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005412 Binder.restoreCallingIdentity(origId);
5413 }
5414
5415 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5416 boolean remove) {
5417 int N = mStoppingActivities.size();
5418 if (N <= 0) return null;
5419
5420 ArrayList<HistoryRecord> stops = null;
5421
5422 final boolean nowVisible = mResumedActivity != null
5423 && mResumedActivity.nowVisible
5424 && !mResumedActivity.waitingVisible;
5425 for (int i=0; i<N; i++) {
5426 HistoryRecord s = mStoppingActivities.get(i);
5427 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5428 + nowVisible + " waitingVisible=" + s.waitingVisible
5429 + " finishing=" + s.finishing);
5430 if (s.waitingVisible && nowVisible) {
5431 mWaitingVisibleActivities.remove(s);
5432 s.waitingVisible = false;
5433 if (s.finishing) {
5434 // If this activity is finishing, it is sitting on top of
5435 // everyone else but we now know it is no longer needed...
5436 // so get rid of it. Otherwise, we need to go through the
5437 // normal flow and hide it once we determine that it is
5438 // hidden by the activities in front of it.
5439 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5440 mWindowManager.setAppVisibility(s, false);
5441 }
5442 }
5443 if (!s.waitingVisible && remove) {
5444 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5445 if (stops == null) {
5446 stops = new ArrayList<HistoryRecord>();
5447 }
5448 stops.add(s);
5449 mStoppingActivities.remove(i);
5450 N--;
5451 i--;
5452 }
5453 }
5454
5455 return stops;
5456 }
5457
5458 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005459 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005460 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005461 mWindowManager.enableScreenAfterBoot();
5462 }
5463
Dianne Hackborne88846e2009-09-30 21:34:25 -07005464 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5465 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005466 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5467
5468 ArrayList<HistoryRecord> stops = null;
5469 ArrayList<HistoryRecord> finishes = null;
5470 ArrayList<HistoryRecord> thumbnails = null;
5471 int NS = 0;
5472 int NF = 0;
5473 int NT = 0;
5474 IApplicationThread sendThumbnail = null;
5475 boolean booting = false;
5476 boolean enableScreen = false;
5477
5478 synchronized (this) {
5479 if (token != null) {
5480 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5481 }
5482
5483 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005484 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005485 if (index >= 0) {
5486 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5487
Dianne Hackborne88846e2009-09-30 21:34:25 -07005488 // This is a hack to semi-deal with a race condition
5489 // in the client where it can be constructed with a
5490 // newer configuration from when we asked it to launch.
5491 // We'll update with whatever configuration it now says
5492 // it used to launch.
5493 if (config != null) {
5494 r.configuration = config;
5495 }
5496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005497 // No longer need to keep the device awake.
5498 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5499 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5500 mLaunchingActivity.release();
5501 }
5502
5503 // We are now idle. If someone is waiting for a thumbnail from
5504 // us, we can now deliver.
5505 r.idle = true;
5506 scheduleAppGcsLocked();
5507 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5508 sendThumbnail = r.app.thread;
5509 r.thumbnailNeeded = false;
5510 }
5511
5512 // If this activity is fullscreen, set up to hide those under it.
5513
5514 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5515 ensureActivitiesVisibleLocked(null, 0);
5516
5517 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5518 if (!mBooted && !fromTimeout) {
5519 mBooted = true;
5520 enableScreen = true;
5521 }
5522 }
5523
5524 // Atomically retrieve all of the other things to do.
5525 stops = processStoppingActivitiesLocked(true);
5526 NS = stops != null ? stops.size() : 0;
5527 if ((NF=mFinishingActivities.size()) > 0) {
5528 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5529 mFinishingActivities.clear();
5530 }
5531 if ((NT=mCancelledThumbnails.size()) > 0) {
5532 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5533 mCancelledThumbnails.clear();
5534 }
5535
5536 booting = mBooting;
5537 mBooting = false;
5538 }
5539
5540 int i;
5541
5542 // Send thumbnail if requested.
5543 if (sendThumbnail != null) {
5544 try {
5545 sendThumbnail.requestThumbnail(token);
5546 } catch (Exception e) {
5547 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5548 sendPendingThumbnail(null, token, null, null, true);
5549 }
5550 }
5551
5552 // Stop any activities that are scheduled to do so but have been
5553 // waiting for the next one to start.
5554 for (i=0; i<NS; i++) {
5555 HistoryRecord r = (HistoryRecord)stops.get(i);
5556 synchronized (this) {
5557 if (r.finishing) {
5558 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5559 } else {
5560 stopActivityLocked(r);
5561 }
5562 }
5563 }
5564
5565 // Finish any activities that are scheduled to do so but have been
5566 // waiting for the next one to start.
5567 for (i=0; i<NF; i++) {
5568 HistoryRecord r = (HistoryRecord)finishes.get(i);
5569 synchronized (this) {
5570 destroyActivityLocked(r, true);
5571 }
5572 }
5573
5574 // Report back to any thumbnail receivers.
5575 for (i=0; i<NT; i++) {
5576 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5577 sendPendingThumbnail(r, null, null, null, true);
5578 }
5579
5580 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005581 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005582 }
5583
5584 trimApplications();
5585 //dump();
5586 //mWindowManager.dump();
5587
5588 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005589 enableScreenAfterBoot();
5590 }
5591 }
5592
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005593 final void finishBooting() {
5594 // Ensure that any processes we had put on hold are now started
5595 // up.
5596 final int NP = mProcessesOnHold.size();
5597 if (NP > 0) {
5598 ArrayList<ProcessRecord> procs =
5599 new ArrayList<ProcessRecord>(mProcessesOnHold);
5600 for (int ip=0; ip<NP; ip++) {
5601 this.startProcessLocked(procs.get(ip), "on-hold", null);
5602 }
5603 }
5604 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5605 // Tell anyone interested that we are done booting!
5606 synchronized (this) {
5607 broadcastIntentLocked(null, null,
5608 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5609 null, null, 0, null, null,
5610 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5611 false, false, MY_PID, Process.SYSTEM_UID);
5612 }
5613 }
5614 }
5615
5616 final void ensureBootCompleted() {
5617 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005618 boolean enableScreen;
5619 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005620 booting = mBooting;
5621 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005622 enableScreen = !mBooted;
5623 mBooted = true;
5624 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005625
5626 if (booting) {
5627 finishBooting();
5628 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005629
5630 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005631 enableScreenAfterBoot();
5632 }
5633 }
5634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005635 public final void activityPaused(IBinder token, Bundle icicle) {
5636 // Refuse possible leaked file descriptors
5637 if (icicle != null && icicle.hasFileDescriptors()) {
5638 throw new IllegalArgumentException("File descriptors passed in Bundle");
5639 }
5640
5641 final long origId = Binder.clearCallingIdentity();
5642 activityPaused(token, icicle, false);
5643 Binder.restoreCallingIdentity(origId);
5644 }
5645
5646 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5647 if (DEBUG_PAUSE) Log.v(
5648 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5649 + ", timeout=" + timeout);
5650
5651 HistoryRecord r = null;
5652
5653 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005654 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005655 if (index >= 0) {
5656 r = (HistoryRecord)mHistory.get(index);
5657 if (!timeout) {
5658 r.icicle = icicle;
5659 r.haveState = true;
5660 }
5661 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5662 if (mPausingActivity == r) {
5663 r.state = ActivityState.PAUSED;
5664 completePauseLocked();
5665 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005666 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005667 System.identityHashCode(r), r.shortComponentName,
5668 mPausingActivity != null
5669 ? mPausingActivity.shortComponentName : "(none)");
5670 }
5671 }
5672 }
5673 }
5674
5675 public final void activityStopped(IBinder token, Bitmap thumbnail,
5676 CharSequence description) {
5677 if (localLOGV) Log.v(
5678 TAG, "Activity stopped: token=" + token);
5679
5680 HistoryRecord r = null;
5681
5682 final long origId = Binder.clearCallingIdentity();
5683
5684 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005685 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005686 if (index >= 0) {
5687 r = (HistoryRecord)mHistory.get(index);
5688 r.thumbnail = thumbnail;
5689 r.description = description;
5690 r.stopped = true;
5691 r.state = ActivityState.STOPPED;
5692 if (!r.finishing) {
5693 if (r.configDestroy) {
5694 destroyActivityLocked(r, true);
5695 resumeTopActivityLocked(null);
5696 }
5697 }
5698 }
5699 }
5700
5701 if (r != null) {
5702 sendPendingThumbnail(r, null, null, null, false);
5703 }
5704
5705 trimApplications();
5706
5707 Binder.restoreCallingIdentity(origId);
5708 }
5709
5710 public final void activityDestroyed(IBinder token) {
5711 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5712 synchronized (this) {
5713 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5714
Dianne Hackborn75b03852009-06-12 15:43:26 -07005715 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005716 if (index >= 0) {
5717 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5718 if (r.state == ActivityState.DESTROYING) {
5719 final long origId = Binder.clearCallingIdentity();
5720 removeActivityFromHistoryLocked(r);
5721 Binder.restoreCallingIdentity(origId);
5722 }
5723 }
5724 }
5725 }
5726
5727 public String getCallingPackage(IBinder token) {
5728 synchronized (this) {
5729 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005730 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005731 }
5732 }
5733
5734 public ComponentName getCallingActivity(IBinder token) {
5735 synchronized (this) {
5736 HistoryRecord r = getCallingRecordLocked(token);
5737 return r != null ? r.intent.getComponent() : null;
5738 }
5739 }
5740
5741 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005742 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005743 if (index >= 0) {
5744 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5745 if (r != null) {
5746 return r.resultTo;
5747 }
5748 }
5749 return null;
5750 }
5751
5752 public ComponentName getActivityClassForToken(IBinder token) {
5753 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005754 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005755 if (index >= 0) {
5756 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5757 return r.intent.getComponent();
5758 }
5759 return null;
5760 }
5761 }
5762
5763 public String getPackageForToken(IBinder token) {
5764 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005765 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005766 if (index >= 0) {
5767 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5768 return r.packageName;
5769 }
5770 return null;
5771 }
5772 }
5773
5774 public IIntentSender getIntentSender(int type,
5775 String packageName, IBinder token, String resultWho,
5776 int requestCode, Intent intent, String resolvedType, int flags) {
5777 // Refuse possible leaked file descriptors
5778 if (intent != null && intent.hasFileDescriptors() == true) {
5779 throw new IllegalArgumentException("File descriptors passed in Intent");
5780 }
5781
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005782 if (type == INTENT_SENDER_BROADCAST) {
5783 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5784 throw new IllegalArgumentException(
5785 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5786 }
5787 }
5788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005789 synchronized(this) {
5790 int callingUid = Binder.getCallingUid();
5791 try {
5792 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5793 Process.supportsProcesses()) {
5794 int uid = ActivityThread.getPackageManager()
5795 .getPackageUid(packageName);
5796 if (uid != Binder.getCallingUid()) {
5797 String msg = "Permission Denial: getIntentSender() from pid="
5798 + Binder.getCallingPid()
5799 + ", uid=" + Binder.getCallingUid()
5800 + ", (need uid=" + uid + ")"
5801 + " is not allowed to send as package " + packageName;
5802 Log.w(TAG, msg);
5803 throw new SecurityException(msg);
5804 }
5805 }
5806 } catch (RemoteException e) {
5807 throw new SecurityException(e);
5808 }
5809 HistoryRecord activity = null;
5810 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005811 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005812 if (index < 0) {
5813 return null;
5814 }
5815 activity = (HistoryRecord)mHistory.get(index);
5816 if (activity.finishing) {
5817 return null;
5818 }
5819 }
5820
5821 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5822 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5823 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5824 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5825 |PendingIntent.FLAG_UPDATE_CURRENT);
5826
5827 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5828 type, packageName, activity, resultWho,
5829 requestCode, intent, resolvedType, flags);
5830 WeakReference<PendingIntentRecord> ref;
5831 ref = mIntentSenderRecords.get(key);
5832 PendingIntentRecord rec = ref != null ? ref.get() : null;
5833 if (rec != null) {
5834 if (!cancelCurrent) {
5835 if (updateCurrent) {
5836 rec.key.requestIntent.replaceExtras(intent);
5837 }
5838 return rec;
5839 }
5840 rec.canceled = true;
5841 mIntentSenderRecords.remove(key);
5842 }
5843 if (noCreate) {
5844 return rec;
5845 }
5846 rec = new PendingIntentRecord(this, key, callingUid);
5847 mIntentSenderRecords.put(key, rec.ref);
5848 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5849 if (activity.pendingResults == null) {
5850 activity.pendingResults
5851 = new HashSet<WeakReference<PendingIntentRecord>>();
5852 }
5853 activity.pendingResults.add(rec.ref);
5854 }
5855 return rec;
5856 }
5857 }
5858
5859 public void cancelIntentSender(IIntentSender sender) {
5860 if (!(sender instanceof PendingIntentRecord)) {
5861 return;
5862 }
5863 synchronized(this) {
5864 PendingIntentRecord rec = (PendingIntentRecord)sender;
5865 try {
5866 int uid = ActivityThread.getPackageManager()
5867 .getPackageUid(rec.key.packageName);
5868 if (uid != Binder.getCallingUid()) {
5869 String msg = "Permission Denial: cancelIntentSender() from pid="
5870 + Binder.getCallingPid()
5871 + ", uid=" + Binder.getCallingUid()
5872 + " is not allowed to cancel packges "
5873 + rec.key.packageName;
5874 Log.w(TAG, msg);
5875 throw new SecurityException(msg);
5876 }
5877 } catch (RemoteException e) {
5878 throw new SecurityException(e);
5879 }
5880 cancelIntentSenderLocked(rec, true);
5881 }
5882 }
5883
5884 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5885 rec.canceled = true;
5886 mIntentSenderRecords.remove(rec.key);
5887 if (cleanActivity && rec.key.activity != null) {
5888 rec.key.activity.pendingResults.remove(rec.ref);
5889 }
5890 }
5891
5892 public String getPackageForIntentSender(IIntentSender pendingResult) {
5893 if (!(pendingResult instanceof PendingIntentRecord)) {
5894 return null;
5895 }
5896 synchronized(this) {
5897 try {
5898 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5899 return res.key.packageName;
5900 } catch (ClassCastException e) {
5901 }
5902 }
5903 return null;
5904 }
5905
5906 public void setProcessLimit(int max) {
5907 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5908 "setProcessLimit()");
5909 mProcessLimit = max;
5910 }
5911
5912 public int getProcessLimit() {
5913 return mProcessLimit;
5914 }
5915
5916 void foregroundTokenDied(ForegroundToken token) {
5917 synchronized (ActivityManagerService.this) {
5918 synchronized (mPidsSelfLocked) {
5919 ForegroundToken cur
5920 = mForegroundProcesses.get(token.pid);
5921 if (cur != token) {
5922 return;
5923 }
5924 mForegroundProcesses.remove(token.pid);
5925 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5926 if (pr == null) {
5927 return;
5928 }
5929 pr.forcingToForeground = null;
5930 pr.foregroundServices = false;
5931 }
5932 updateOomAdjLocked();
5933 }
5934 }
5935
5936 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5937 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5938 "setProcessForeground()");
5939 synchronized(this) {
5940 boolean changed = false;
5941
5942 synchronized (mPidsSelfLocked) {
5943 ProcessRecord pr = mPidsSelfLocked.get(pid);
5944 if (pr == null) {
5945 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5946 return;
5947 }
5948 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5949 if (oldToken != null) {
5950 oldToken.token.unlinkToDeath(oldToken, 0);
5951 mForegroundProcesses.remove(pid);
5952 pr.forcingToForeground = null;
5953 changed = true;
5954 }
5955 if (isForeground && token != null) {
5956 ForegroundToken newToken = new ForegroundToken() {
5957 public void binderDied() {
5958 foregroundTokenDied(this);
5959 }
5960 };
5961 newToken.pid = pid;
5962 newToken.token = token;
5963 try {
5964 token.linkToDeath(newToken, 0);
5965 mForegroundProcesses.put(pid, newToken);
5966 pr.forcingToForeground = token;
5967 changed = true;
5968 } catch (RemoteException e) {
5969 // If the process died while doing this, we will later
5970 // do the cleanup with the process death link.
5971 }
5972 }
5973 }
5974
5975 if (changed) {
5976 updateOomAdjLocked();
5977 }
5978 }
5979 }
5980
5981 // =========================================================
5982 // PERMISSIONS
5983 // =========================================================
5984
5985 static class PermissionController extends IPermissionController.Stub {
5986 ActivityManagerService mActivityManagerService;
5987 PermissionController(ActivityManagerService activityManagerService) {
5988 mActivityManagerService = activityManagerService;
5989 }
5990
5991 public boolean checkPermission(String permission, int pid, int uid) {
5992 return mActivityManagerService.checkPermission(permission, pid,
5993 uid) == PackageManager.PERMISSION_GRANTED;
5994 }
5995 }
5996
5997 /**
5998 * This can be called with or without the global lock held.
5999 */
6000 int checkComponentPermission(String permission, int pid, int uid,
6001 int reqUid) {
6002 // We might be performing an operation on behalf of an indirect binder
6003 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6004 // client identity accordingly before proceeding.
6005 Identity tlsIdentity = sCallerIdentity.get();
6006 if (tlsIdentity != null) {
6007 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6008 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6009 uid = tlsIdentity.uid;
6010 pid = tlsIdentity.pid;
6011 }
6012
6013 // Root, system server and our own process get to do everything.
6014 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6015 !Process.supportsProcesses()) {
6016 return PackageManager.PERMISSION_GRANTED;
6017 }
6018 // If the target requires a specific UID, always fail for others.
6019 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006020 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006021 return PackageManager.PERMISSION_DENIED;
6022 }
6023 if (permission == null) {
6024 return PackageManager.PERMISSION_GRANTED;
6025 }
6026 try {
6027 return ActivityThread.getPackageManager()
6028 .checkUidPermission(permission, uid);
6029 } catch (RemoteException e) {
6030 // Should never happen, but if it does... deny!
6031 Log.e(TAG, "PackageManager is dead?!?", e);
6032 }
6033 return PackageManager.PERMISSION_DENIED;
6034 }
6035
6036 /**
6037 * As the only public entry point for permissions checking, this method
6038 * can enforce the semantic that requesting a check on a null global
6039 * permission is automatically denied. (Internally a null permission
6040 * string is used when calling {@link #checkComponentPermission} in cases
6041 * when only uid-based security is needed.)
6042 *
6043 * This can be called with or without the global lock held.
6044 */
6045 public int checkPermission(String permission, int pid, int uid) {
6046 if (permission == null) {
6047 return PackageManager.PERMISSION_DENIED;
6048 }
6049 return checkComponentPermission(permission, pid, uid, -1);
6050 }
6051
6052 /**
6053 * Binder IPC calls go through the public entry point.
6054 * This can be called with or without the global lock held.
6055 */
6056 int checkCallingPermission(String permission) {
6057 return checkPermission(permission,
6058 Binder.getCallingPid(),
6059 Binder.getCallingUid());
6060 }
6061
6062 /**
6063 * This can be called with or without the global lock held.
6064 */
6065 void enforceCallingPermission(String permission, String func) {
6066 if (checkCallingPermission(permission)
6067 == PackageManager.PERMISSION_GRANTED) {
6068 return;
6069 }
6070
6071 String msg = "Permission Denial: " + func + " from pid="
6072 + Binder.getCallingPid()
6073 + ", uid=" + Binder.getCallingUid()
6074 + " requires " + permission;
6075 Log.w(TAG, msg);
6076 throw new SecurityException(msg);
6077 }
6078
6079 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6080 ProviderInfo pi, int uid, int modeFlags) {
6081 try {
6082 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6083 if ((pi.readPermission != null) &&
6084 (pm.checkUidPermission(pi.readPermission, uid)
6085 != PackageManager.PERMISSION_GRANTED)) {
6086 return false;
6087 }
6088 }
6089 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6090 if ((pi.writePermission != null) &&
6091 (pm.checkUidPermission(pi.writePermission, uid)
6092 != PackageManager.PERMISSION_GRANTED)) {
6093 return false;
6094 }
6095 }
6096 return true;
6097 } catch (RemoteException e) {
6098 return false;
6099 }
6100 }
6101
6102 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6103 int modeFlags) {
6104 // Root gets to do everything.
6105 if (uid == 0 || !Process.supportsProcesses()) {
6106 return true;
6107 }
6108 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6109 if (perms == null) return false;
6110 UriPermission perm = perms.get(uri);
6111 if (perm == null) return false;
6112 return (modeFlags&perm.modeFlags) == modeFlags;
6113 }
6114
6115 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6116 // Another redirected-binder-call permissions check as in
6117 // {@link checkComponentPermission}.
6118 Identity tlsIdentity = sCallerIdentity.get();
6119 if (tlsIdentity != null) {
6120 uid = tlsIdentity.uid;
6121 pid = tlsIdentity.pid;
6122 }
6123
6124 // Our own process gets to do everything.
6125 if (pid == MY_PID) {
6126 return PackageManager.PERMISSION_GRANTED;
6127 }
6128 synchronized(this) {
6129 return checkUriPermissionLocked(uri, uid, modeFlags)
6130 ? PackageManager.PERMISSION_GRANTED
6131 : PackageManager.PERMISSION_DENIED;
6132 }
6133 }
6134
6135 private void grantUriPermissionLocked(int callingUid,
6136 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6137 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6138 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6139 if (modeFlags == 0) {
6140 return;
6141 }
6142
6143 final IPackageManager pm = ActivityThread.getPackageManager();
6144
6145 // If this is not a content: uri, we can't do anything with it.
6146 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6147 return;
6148 }
6149
6150 String name = uri.getAuthority();
6151 ProviderInfo pi = null;
6152 ContentProviderRecord cpr
6153 = (ContentProviderRecord)mProvidersByName.get(name);
6154 if (cpr != null) {
6155 pi = cpr.info;
6156 } else {
6157 try {
6158 pi = pm.resolveContentProvider(name,
6159 PackageManager.GET_URI_PERMISSION_PATTERNS);
6160 } catch (RemoteException ex) {
6161 }
6162 }
6163 if (pi == null) {
6164 Log.w(TAG, "No content provider found for: " + name);
6165 return;
6166 }
6167
6168 int targetUid;
6169 try {
6170 targetUid = pm.getPackageUid(targetPkg);
6171 if (targetUid < 0) {
6172 return;
6173 }
6174 } catch (RemoteException ex) {
6175 return;
6176 }
6177
6178 // First... does the target actually need this permission?
6179 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6180 // No need to grant the target this permission.
6181 return;
6182 }
6183
6184 // Second... maybe someone else has already granted the
6185 // permission?
6186 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6187 // No need to grant the target this permission.
6188 return;
6189 }
6190
6191 // Third... is the provider allowing granting of URI permissions?
6192 if (!pi.grantUriPermissions) {
6193 throw new SecurityException("Provider " + pi.packageName
6194 + "/" + pi.name
6195 + " does not allow granting of Uri permissions (uri "
6196 + uri + ")");
6197 }
6198 if (pi.uriPermissionPatterns != null) {
6199 final int N = pi.uriPermissionPatterns.length;
6200 boolean allowed = false;
6201 for (int i=0; i<N; i++) {
6202 if (pi.uriPermissionPatterns[i] != null
6203 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6204 allowed = true;
6205 break;
6206 }
6207 }
6208 if (!allowed) {
6209 throw new SecurityException("Provider " + pi.packageName
6210 + "/" + pi.name
6211 + " does not allow granting of permission to path of Uri "
6212 + uri);
6213 }
6214 }
6215
6216 // Fourth... does the caller itself have permission to access
6217 // this uri?
6218 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6219 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6220 throw new SecurityException("Uid " + callingUid
6221 + " does not have permission to uri " + uri);
6222 }
6223 }
6224
6225 // Okay! So here we are: the caller has the assumed permission
6226 // to the uri, and the target doesn't. Let's now give this to
6227 // the target.
6228
6229 HashMap<Uri, UriPermission> targetUris
6230 = mGrantedUriPermissions.get(targetUid);
6231 if (targetUris == null) {
6232 targetUris = new HashMap<Uri, UriPermission>();
6233 mGrantedUriPermissions.put(targetUid, targetUris);
6234 }
6235
6236 UriPermission perm = targetUris.get(uri);
6237 if (perm == null) {
6238 perm = new UriPermission(targetUid, uri);
6239 targetUris.put(uri, perm);
6240
6241 }
6242 perm.modeFlags |= modeFlags;
6243 if (activity == null) {
6244 perm.globalModeFlags |= modeFlags;
6245 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6246 perm.readActivities.add(activity);
6247 if (activity.readUriPermissions == null) {
6248 activity.readUriPermissions = new HashSet<UriPermission>();
6249 }
6250 activity.readUriPermissions.add(perm);
6251 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6252 perm.writeActivities.add(activity);
6253 if (activity.writeUriPermissions == null) {
6254 activity.writeUriPermissions = new HashSet<UriPermission>();
6255 }
6256 activity.writeUriPermissions.add(perm);
6257 }
6258 }
6259
6260 private void grantUriPermissionFromIntentLocked(int callingUid,
6261 String targetPkg, Intent intent, HistoryRecord activity) {
6262 if (intent == null) {
6263 return;
6264 }
6265 Uri data = intent.getData();
6266 if (data == null) {
6267 return;
6268 }
6269 grantUriPermissionLocked(callingUid, targetPkg, data,
6270 intent.getFlags(), activity);
6271 }
6272
6273 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6274 Uri uri, int modeFlags) {
6275 synchronized(this) {
6276 final ProcessRecord r = getRecordForAppLocked(caller);
6277 if (r == null) {
6278 throw new SecurityException("Unable to find app for caller "
6279 + caller
6280 + " when granting permission to uri " + uri);
6281 }
6282 if (targetPkg == null) {
6283 Log.w(TAG, "grantUriPermission: null target");
6284 return;
6285 }
6286 if (uri == null) {
6287 Log.w(TAG, "grantUriPermission: null uri");
6288 return;
6289 }
6290
6291 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6292 null);
6293 }
6294 }
6295
6296 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6297 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6298 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6299 HashMap<Uri, UriPermission> perms
6300 = mGrantedUriPermissions.get(perm.uid);
6301 if (perms != null) {
6302 perms.remove(perm.uri);
6303 if (perms.size() == 0) {
6304 mGrantedUriPermissions.remove(perm.uid);
6305 }
6306 }
6307 }
6308 }
6309
6310 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6311 if (activity.readUriPermissions != null) {
6312 for (UriPermission perm : activity.readUriPermissions) {
6313 perm.readActivities.remove(activity);
6314 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6315 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6316 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6317 removeUriPermissionIfNeededLocked(perm);
6318 }
6319 }
6320 }
6321 if (activity.writeUriPermissions != null) {
6322 for (UriPermission perm : activity.writeUriPermissions) {
6323 perm.writeActivities.remove(activity);
6324 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6325 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6326 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6327 removeUriPermissionIfNeededLocked(perm);
6328 }
6329 }
6330 }
6331 }
6332
6333 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6334 int modeFlags) {
6335 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6336 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6337 if (modeFlags == 0) {
6338 return;
6339 }
6340
6341 final IPackageManager pm = ActivityThread.getPackageManager();
6342
6343 final String authority = uri.getAuthority();
6344 ProviderInfo pi = null;
6345 ContentProviderRecord cpr
6346 = (ContentProviderRecord)mProvidersByName.get(authority);
6347 if (cpr != null) {
6348 pi = cpr.info;
6349 } else {
6350 try {
6351 pi = pm.resolveContentProvider(authority,
6352 PackageManager.GET_URI_PERMISSION_PATTERNS);
6353 } catch (RemoteException ex) {
6354 }
6355 }
6356 if (pi == null) {
6357 Log.w(TAG, "No content provider found for: " + authority);
6358 return;
6359 }
6360
6361 // Does the caller have this permission on the URI?
6362 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6363 // Right now, if you are not the original owner of the permission,
6364 // you are not allowed to revoke it.
6365 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6366 throw new SecurityException("Uid " + callingUid
6367 + " does not have permission to uri " + uri);
6368 //}
6369 }
6370
6371 // Go through all of the permissions and remove any that match.
6372 final List<String> SEGMENTS = uri.getPathSegments();
6373 if (SEGMENTS != null) {
6374 final int NS = SEGMENTS.size();
6375 int N = mGrantedUriPermissions.size();
6376 for (int i=0; i<N; i++) {
6377 HashMap<Uri, UriPermission> perms
6378 = mGrantedUriPermissions.valueAt(i);
6379 Iterator<UriPermission> it = perms.values().iterator();
6380 toploop:
6381 while (it.hasNext()) {
6382 UriPermission perm = it.next();
6383 Uri targetUri = perm.uri;
6384 if (!authority.equals(targetUri.getAuthority())) {
6385 continue;
6386 }
6387 List<String> targetSegments = targetUri.getPathSegments();
6388 if (targetSegments == null) {
6389 continue;
6390 }
6391 if (targetSegments.size() < NS) {
6392 continue;
6393 }
6394 for (int j=0; j<NS; j++) {
6395 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6396 continue toploop;
6397 }
6398 }
6399 perm.clearModes(modeFlags);
6400 if (perm.modeFlags == 0) {
6401 it.remove();
6402 }
6403 }
6404 if (perms.size() == 0) {
6405 mGrantedUriPermissions.remove(
6406 mGrantedUriPermissions.keyAt(i));
6407 N--;
6408 i--;
6409 }
6410 }
6411 }
6412 }
6413
6414 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6415 int modeFlags) {
6416 synchronized(this) {
6417 final ProcessRecord r = getRecordForAppLocked(caller);
6418 if (r == null) {
6419 throw new SecurityException("Unable to find app for caller "
6420 + caller
6421 + " when revoking permission to uri " + uri);
6422 }
6423 if (uri == null) {
6424 Log.w(TAG, "revokeUriPermission: null uri");
6425 return;
6426 }
6427
6428 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6429 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6430 if (modeFlags == 0) {
6431 return;
6432 }
6433
6434 final IPackageManager pm = ActivityThread.getPackageManager();
6435
6436 final String authority = uri.getAuthority();
6437 ProviderInfo pi = null;
6438 ContentProviderRecord cpr
6439 = (ContentProviderRecord)mProvidersByName.get(authority);
6440 if (cpr != null) {
6441 pi = cpr.info;
6442 } else {
6443 try {
6444 pi = pm.resolveContentProvider(authority,
6445 PackageManager.GET_URI_PERMISSION_PATTERNS);
6446 } catch (RemoteException ex) {
6447 }
6448 }
6449 if (pi == null) {
6450 Log.w(TAG, "No content provider found for: " + authority);
6451 return;
6452 }
6453
6454 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6455 }
6456 }
6457
6458 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6459 synchronized (this) {
6460 ProcessRecord app =
6461 who != null ? getRecordForAppLocked(who) : null;
6462 if (app == null) return;
6463
6464 Message msg = Message.obtain();
6465 msg.what = WAIT_FOR_DEBUGGER_MSG;
6466 msg.obj = app;
6467 msg.arg1 = waiting ? 1 : 0;
6468 mHandler.sendMessage(msg);
6469 }
6470 }
6471
6472 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6473 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006474 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006475 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006476 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006477 }
6478
6479 // =========================================================
6480 // TASK MANAGEMENT
6481 // =========================================================
6482
6483 public List getTasks(int maxNum, int flags,
6484 IThumbnailReceiver receiver) {
6485 ArrayList list = new ArrayList();
6486
6487 PendingThumbnailsRecord pending = null;
6488 IApplicationThread topThumbnail = null;
6489 HistoryRecord topRecord = null;
6490
6491 synchronized(this) {
6492 if (localLOGV) Log.v(
6493 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6494 + ", receiver=" + receiver);
6495
6496 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6497 != PackageManager.PERMISSION_GRANTED) {
6498 if (receiver != null) {
6499 // If the caller wants to wait for pending thumbnails,
6500 // it ain't gonna get them.
6501 try {
6502 receiver.finished();
6503 } catch (RemoteException ex) {
6504 }
6505 }
6506 String msg = "Permission Denial: getTasks() from pid="
6507 + Binder.getCallingPid()
6508 + ", uid=" + Binder.getCallingUid()
6509 + " requires " + android.Manifest.permission.GET_TASKS;
6510 Log.w(TAG, msg);
6511 throw new SecurityException(msg);
6512 }
6513
6514 int pos = mHistory.size()-1;
6515 HistoryRecord next =
6516 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6517 HistoryRecord top = null;
6518 CharSequence topDescription = null;
6519 TaskRecord curTask = null;
6520 int numActivities = 0;
6521 int numRunning = 0;
6522 while (pos >= 0 && maxNum > 0) {
6523 final HistoryRecord r = next;
6524 pos--;
6525 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6526
6527 // Initialize state for next task if needed.
6528 if (top == null ||
6529 (top.state == ActivityState.INITIALIZING
6530 && top.task == r.task)) {
6531 top = r;
6532 topDescription = r.description;
6533 curTask = r.task;
6534 numActivities = numRunning = 0;
6535 }
6536
6537 // Add 'r' into the current task.
6538 numActivities++;
6539 if (r.app != null && r.app.thread != null) {
6540 numRunning++;
6541 }
6542 if (topDescription == null) {
6543 topDescription = r.description;
6544 }
6545
6546 if (localLOGV) Log.v(
6547 TAG, r.intent.getComponent().flattenToShortString()
6548 + ": task=" + r.task);
6549
6550 // If the next one is a different task, generate a new
6551 // TaskInfo entry for what we have.
6552 if (next == null || next.task != curTask) {
6553 ActivityManager.RunningTaskInfo ci
6554 = new ActivityManager.RunningTaskInfo();
6555 ci.id = curTask.taskId;
6556 ci.baseActivity = r.intent.getComponent();
6557 ci.topActivity = top.intent.getComponent();
6558 ci.thumbnail = top.thumbnail;
6559 ci.description = topDescription;
6560 ci.numActivities = numActivities;
6561 ci.numRunning = numRunning;
6562 //System.out.println(
6563 // "#" + maxNum + ": " + " descr=" + ci.description);
6564 if (ci.thumbnail == null && receiver != null) {
6565 if (localLOGV) Log.v(
6566 TAG, "State=" + top.state + "Idle=" + top.idle
6567 + " app=" + top.app
6568 + " thr=" + (top.app != null ? top.app.thread : null));
6569 if (top.state == ActivityState.RESUMED
6570 || top.state == ActivityState.PAUSING) {
6571 if (top.idle && top.app != null
6572 && top.app.thread != null) {
6573 topRecord = top;
6574 topThumbnail = top.app.thread;
6575 } else {
6576 top.thumbnailNeeded = true;
6577 }
6578 }
6579 if (pending == null) {
6580 pending = new PendingThumbnailsRecord(receiver);
6581 }
6582 pending.pendingRecords.add(top);
6583 }
6584 list.add(ci);
6585 maxNum--;
6586 top = null;
6587 }
6588 }
6589
6590 if (pending != null) {
6591 mPendingThumbnails.add(pending);
6592 }
6593 }
6594
6595 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6596
6597 if (topThumbnail != null) {
6598 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6599 try {
6600 topThumbnail.requestThumbnail(topRecord);
6601 } catch (Exception e) {
6602 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6603 sendPendingThumbnail(null, topRecord, null, null, true);
6604 }
6605 }
6606
6607 if (pending == null && receiver != null) {
6608 // In this case all thumbnails were available and the client
6609 // is being asked to be told when the remaining ones come in...
6610 // which is unusually, since the top-most currently running
6611 // activity should never have a canned thumbnail! Oh well.
6612 try {
6613 receiver.finished();
6614 } catch (RemoteException ex) {
6615 }
6616 }
6617
6618 return list;
6619 }
6620
6621 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6622 int flags) {
6623 synchronized (this) {
6624 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6625 "getRecentTasks()");
6626
6627 final int N = mRecentTasks.size();
6628 ArrayList<ActivityManager.RecentTaskInfo> res
6629 = new ArrayList<ActivityManager.RecentTaskInfo>(
6630 maxNum < N ? maxNum : N);
6631 for (int i=0; i<N && maxNum > 0; i++) {
6632 TaskRecord tr = mRecentTasks.get(i);
6633 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6634 || (tr.intent == null)
6635 || ((tr.intent.getFlags()
6636 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6637 ActivityManager.RecentTaskInfo rti
6638 = new ActivityManager.RecentTaskInfo();
6639 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6640 rti.baseIntent = new Intent(
6641 tr.intent != null ? tr.intent : tr.affinityIntent);
6642 rti.origActivity = tr.origActivity;
6643 res.add(rti);
6644 maxNum--;
6645 }
6646 }
6647 return res;
6648 }
6649 }
6650
6651 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6652 int j;
6653 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6654 TaskRecord jt = startTask;
6655
6656 // First look backwards
6657 for (j=startIndex-1; j>=0; j--) {
6658 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6659 if (r.task != jt) {
6660 jt = r.task;
6661 if (affinity.equals(jt.affinity)) {
6662 return j;
6663 }
6664 }
6665 }
6666
6667 // Now look forwards
6668 final int N = mHistory.size();
6669 jt = startTask;
6670 for (j=startIndex+1; j<N; j++) {
6671 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6672 if (r.task != jt) {
6673 if (affinity.equals(jt.affinity)) {
6674 return j;
6675 }
6676 jt = r.task;
6677 }
6678 }
6679
6680 // Might it be at the top?
6681 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6682 return N-1;
6683 }
6684
6685 return -1;
6686 }
6687
6688 /**
6689 * Perform a reset of the given task, if needed as part of launching it.
6690 * Returns the new HistoryRecord at the top of the task.
6691 */
6692 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6693 HistoryRecord newActivity) {
6694 boolean forceReset = (newActivity.info.flags
6695 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6696 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6697 if ((newActivity.info.flags
6698 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6699 forceReset = true;
6700 }
6701 }
6702
6703 final TaskRecord task = taskTop.task;
6704
6705 // We are going to move through the history list so that we can look
6706 // at each activity 'target' with 'below' either the interesting
6707 // activity immediately below it in the stack or null.
6708 HistoryRecord target = null;
6709 int targetI = 0;
6710 int taskTopI = -1;
6711 int replyChainEnd = -1;
6712 int lastReparentPos = -1;
6713 for (int i=mHistory.size()-1; i>=-1; i--) {
6714 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6715
6716 if (below != null && below.finishing) {
6717 continue;
6718 }
6719 if (target == null) {
6720 target = below;
6721 targetI = i;
6722 // If we were in the middle of a reply chain before this
6723 // task, it doesn't appear like the root of the chain wants
6724 // anything interesting, so drop it.
6725 replyChainEnd = -1;
6726 continue;
6727 }
6728
6729 final int flags = target.info.flags;
6730
6731 final boolean finishOnTaskLaunch =
6732 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6733 final boolean allowTaskReparenting =
6734 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6735
6736 if (target.task == task) {
6737 // We are inside of the task being reset... we'll either
6738 // finish this activity, push it out for another task,
6739 // or leave it as-is. We only do this
6740 // for activities that are not the root of the task (since
6741 // if we finish the root, we may no longer have the task!).
6742 if (taskTopI < 0) {
6743 taskTopI = targetI;
6744 }
6745 if (below != null && below.task == task) {
6746 final boolean clearWhenTaskReset =
6747 (target.intent.getFlags()
6748 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006749 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006750 // If this activity is sending a reply to a previous
6751 // activity, we can't do anything with it now until
6752 // we reach the start of the reply chain.
6753 // XXX note that we are assuming the result is always
6754 // to the previous activity, which is almost always
6755 // the case but we really shouldn't count on.
6756 if (replyChainEnd < 0) {
6757 replyChainEnd = targetI;
6758 }
Ed Heyl73798232009-03-24 21:32:21 -07006759 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006760 && target.taskAffinity != null
6761 && !target.taskAffinity.equals(task.affinity)) {
6762 // If this activity has an affinity for another
6763 // task, then we need to move it out of here. We will
6764 // move it as far out of the way as possible, to the
6765 // bottom of the activity stack. This also keeps it
6766 // correctly ordered with any activities we previously
6767 // moved.
6768 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6769 if (target.taskAffinity != null
6770 && target.taskAffinity.equals(p.task.affinity)) {
6771 // If the activity currently at the bottom has the
6772 // same task affinity as the one we are moving,
6773 // then merge it into the same task.
6774 target.task = p.task;
6775 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6776 + " out to bottom task " + p.task);
6777 } else {
6778 mCurTask++;
6779 if (mCurTask <= 0) {
6780 mCurTask = 1;
6781 }
6782 target.task = new TaskRecord(mCurTask, target.info, null,
6783 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6784 target.task.affinityIntent = target.intent;
6785 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6786 + " out to new task " + target.task);
6787 }
6788 mWindowManager.setAppGroupId(target, task.taskId);
6789 if (replyChainEnd < 0) {
6790 replyChainEnd = targetI;
6791 }
6792 int dstPos = 0;
6793 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6794 p = (HistoryRecord)mHistory.get(srcPos);
6795 if (p.finishing) {
6796 continue;
6797 }
6798 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6799 + " out to target's task " + target.task);
6800 task.numActivities--;
6801 p.task = target.task;
6802 target.task.numActivities++;
6803 mHistory.remove(srcPos);
6804 mHistory.add(dstPos, p);
6805 mWindowManager.moveAppToken(dstPos, p);
6806 mWindowManager.setAppGroupId(p, p.task.taskId);
6807 dstPos++;
6808 if (VALIDATE_TOKENS) {
6809 mWindowManager.validateAppTokens(mHistory);
6810 }
6811 i++;
6812 }
6813 if (taskTop == p) {
6814 taskTop = below;
6815 }
6816 if (taskTopI == replyChainEnd) {
6817 taskTopI = -1;
6818 }
6819 replyChainEnd = -1;
6820 addRecentTask(target.task);
6821 } else if (forceReset || finishOnTaskLaunch
6822 || clearWhenTaskReset) {
6823 // If the activity should just be removed -- either
6824 // because it asks for it, or the task should be
6825 // cleared -- then finish it and anything that is
6826 // part of its reply chain.
6827 if (clearWhenTaskReset) {
6828 // In this case, we want to finish this activity
6829 // and everything above it, so be sneaky and pretend
6830 // like these are all in the reply chain.
6831 replyChainEnd = targetI+1;
6832 while (replyChainEnd < mHistory.size() &&
6833 ((HistoryRecord)mHistory.get(
6834 replyChainEnd)).task == task) {
6835 replyChainEnd++;
6836 }
6837 replyChainEnd--;
6838 } else if (replyChainEnd < 0) {
6839 replyChainEnd = targetI;
6840 }
6841 HistoryRecord p = null;
6842 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6843 p = (HistoryRecord)mHistory.get(srcPos);
6844 if (p.finishing) {
6845 continue;
6846 }
6847 if (finishActivityLocked(p, srcPos,
6848 Activity.RESULT_CANCELED, null, "reset")) {
6849 replyChainEnd--;
6850 srcPos--;
6851 }
6852 }
6853 if (taskTop == p) {
6854 taskTop = below;
6855 }
6856 if (taskTopI == replyChainEnd) {
6857 taskTopI = -1;
6858 }
6859 replyChainEnd = -1;
6860 } else {
6861 // If we were in the middle of a chain, well the
6862 // activity that started it all doesn't want anything
6863 // special, so leave it all as-is.
6864 replyChainEnd = -1;
6865 }
6866 } else {
6867 // Reached the bottom of the task -- any reply chain
6868 // should be left as-is.
6869 replyChainEnd = -1;
6870 }
6871
6872 } else if (target.resultTo != null) {
6873 // If this activity is sending a reply to a previous
6874 // activity, we can't do anything with it now until
6875 // we reach the start of the reply chain.
6876 // XXX note that we are assuming the result is always
6877 // to the previous activity, which is almost always
6878 // the case but we really shouldn't count on.
6879 if (replyChainEnd < 0) {
6880 replyChainEnd = targetI;
6881 }
6882
6883 } else if (taskTopI >= 0 && allowTaskReparenting
6884 && task.affinity != null
6885 && task.affinity.equals(target.taskAffinity)) {
6886 // We are inside of another task... if this activity has
6887 // an affinity for our task, then either remove it if we are
6888 // clearing or move it over to our task. Note that
6889 // we currently punt on the case where we are resetting a
6890 // task that is not at the top but who has activities above
6891 // with an affinity to it... this is really not a normal
6892 // case, and we will need to later pull that task to the front
6893 // and usually at that point we will do the reset and pick
6894 // up those remaining activities. (This only happens if
6895 // someone starts an activity in a new task from an activity
6896 // in a task that is not currently on top.)
6897 if (forceReset || finishOnTaskLaunch) {
6898 if (replyChainEnd < 0) {
6899 replyChainEnd = targetI;
6900 }
6901 HistoryRecord p = null;
6902 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6903 p = (HistoryRecord)mHistory.get(srcPos);
6904 if (p.finishing) {
6905 continue;
6906 }
6907 if (finishActivityLocked(p, srcPos,
6908 Activity.RESULT_CANCELED, null, "reset")) {
6909 taskTopI--;
6910 lastReparentPos--;
6911 replyChainEnd--;
6912 srcPos--;
6913 }
6914 }
6915 replyChainEnd = -1;
6916 } else {
6917 if (replyChainEnd < 0) {
6918 replyChainEnd = targetI;
6919 }
6920 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6921 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6922 if (p.finishing) {
6923 continue;
6924 }
6925 if (lastReparentPos < 0) {
6926 lastReparentPos = taskTopI;
6927 taskTop = p;
6928 } else {
6929 lastReparentPos--;
6930 }
6931 mHistory.remove(srcPos);
6932 p.task.numActivities--;
6933 p.task = task;
6934 mHistory.add(lastReparentPos, p);
6935 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6936 + " in to resetting task " + task);
6937 task.numActivities++;
6938 mWindowManager.moveAppToken(lastReparentPos, p);
6939 mWindowManager.setAppGroupId(p, p.task.taskId);
6940 if (VALIDATE_TOKENS) {
6941 mWindowManager.validateAppTokens(mHistory);
6942 }
6943 }
6944 replyChainEnd = -1;
6945
6946 // Now we've moved it in to place... but what if this is
6947 // a singleTop activity and we have put it on top of another
6948 // instance of the same activity? Then we drop the instance
6949 // below so it remains singleTop.
6950 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6951 for (int j=lastReparentPos-1; j>=0; j--) {
6952 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6953 if (p.finishing) {
6954 continue;
6955 }
6956 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6957 if (finishActivityLocked(p, j,
6958 Activity.RESULT_CANCELED, null, "replace")) {
6959 taskTopI--;
6960 lastReparentPos--;
6961 }
6962 }
6963 }
6964 }
6965 }
6966 }
6967
6968 target = below;
6969 targetI = i;
6970 }
6971
6972 return taskTop;
6973 }
6974
6975 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006976 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006977 */
6978 public void moveTaskToFront(int task) {
6979 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6980 "moveTaskToFront()");
6981
6982 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006983 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6984 Binder.getCallingUid(), "Task to front")) {
6985 return;
6986 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006987 final long origId = Binder.clearCallingIdentity();
6988 try {
6989 int N = mRecentTasks.size();
6990 for (int i=0; i<N; i++) {
6991 TaskRecord tr = mRecentTasks.get(i);
6992 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006993 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006994 return;
6995 }
6996 }
6997 for (int i=mHistory.size()-1; i>=0; i--) {
6998 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6999 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007000 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007001 return;
7002 }
7003 }
7004 } finally {
7005 Binder.restoreCallingIdentity(origId);
7006 }
7007 }
7008 }
7009
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007010 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007011 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7012
7013 final int task = tr.taskId;
7014 int top = mHistory.size()-1;
7015
7016 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7017 // nothing to do!
7018 return;
7019 }
7020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007021 ArrayList moved = new ArrayList();
7022
7023 // Applying the affinities may have removed entries from the history,
7024 // so get the size again.
7025 top = mHistory.size()-1;
7026 int pos = top;
7027
7028 // Shift all activities with this task up to the top
7029 // of the stack, keeping them in the same internal order.
7030 while (pos >= 0) {
7031 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7032 if (localLOGV) Log.v(
7033 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7034 boolean first = true;
7035 if (r.task.taskId == task) {
7036 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7037 mHistory.remove(pos);
7038 mHistory.add(top, r);
7039 moved.add(0, r);
7040 top--;
7041 if (first) {
7042 addRecentTask(r.task);
7043 first = false;
7044 }
7045 }
7046 pos--;
7047 }
7048
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007049 if (DEBUG_TRANSITION) Log.v(TAG,
7050 "Prepare to front transition: task=" + tr);
7051 if (reason != null &&
7052 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7053 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7054 HistoryRecord r = topRunningActivityLocked(null);
7055 if (r != null) {
7056 mNoAnimActivities.add(r);
7057 }
7058 } else {
7059 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7060 }
7061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007062 mWindowManager.moveAppTokensToTop(moved);
7063 if (VALIDATE_TOKENS) {
7064 mWindowManager.validateAppTokens(mHistory);
7065 }
7066
7067 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007068 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007069 }
7070
7071 private final void finishTaskMove(int task) {
7072 resumeTopActivityLocked(null);
7073 }
7074
7075 public void moveTaskToBack(int task) {
7076 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7077 "moveTaskToBack()");
7078
7079 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007080 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7081 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7082 Binder.getCallingUid(), "Task to back")) {
7083 return;
7084 }
7085 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007086 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007087 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007088 Binder.restoreCallingIdentity(origId);
7089 }
7090 }
7091
7092 /**
7093 * Moves an activity, and all of the other activities within the same task, to the bottom
7094 * of the history stack. The activity's order within the task is unchanged.
7095 *
7096 * @param token A reference to the activity we wish to move
7097 * @param nonRoot If false then this only works if the activity is the root
7098 * of a task; if true it will work for any activity in a task.
7099 * @return Returns true if the move completed, false if not.
7100 */
7101 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7102 synchronized(this) {
7103 final long origId = Binder.clearCallingIdentity();
7104 int taskId = getTaskForActivityLocked(token, !nonRoot);
7105 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007106 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007107 }
7108 Binder.restoreCallingIdentity(origId);
7109 }
7110 return false;
7111 }
7112
7113 /**
7114 * Worker method for rearranging history stack. Implements the function of moving all
7115 * activities for a specific task (gathering them if disjoint) into a single group at the
7116 * bottom of the stack.
7117 *
7118 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7119 * to premeptively cancel the move.
7120 *
7121 * @param task The taskId to collect and move to the bottom.
7122 * @return Returns true if the move completed, false if not.
7123 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007124 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007125 Log.i(TAG, "moveTaskToBack: " + task);
7126
7127 // If we have a watcher, preflight the move before committing to it. First check
7128 // for *other* available tasks, but if none are available, then try again allowing the
7129 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007130 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007131 HistoryRecord next = topRunningActivityLocked(null, task);
7132 if (next == null) {
7133 next = topRunningActivityLocked(null, 0);
7134 }
7135 if (next != null) {
7136 // ask watcher if this is allowed
7137 boolean moveOK = true;
7138 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007139 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007140 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007141 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007142 }
7143 if (!moveOK) {
7144 return false;
7145 }
7146 }
7147 }
7148
7149 ArrayList moved = new ArrayList();
7150
7151 if (DEBUG_TRANSITION) Log.v(TAG,
7152 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007153
7154 final int N = mHistory.size();
7155 int bottom = 0;
7156 int pos = 0;
7157
7158 // Shift all activities with this task down to the bottom
7159 // of the stack, keeping them in the same internal order.
7160 while (pos < N) {
7161 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7162 if (localLOGV) Log.v(
7163 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7164 if (r.task.taskId == task) {
7165 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7166 mHistory.remove(pos);
7167 mHistory.add(bottom, r);
7168 moved.add(r);
7169 bottom++;
7170 }
7171 pos++;
7172 }
7173
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007174 if (reason != null &&
7175 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7176 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7177 HistoryRecord r = topRunningActivityLocked(null);
7178 if (r != null) {
7179 mNoAnimActivities.add(r);
7180 }
7181 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007182 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007184 mWindowManager.moveAppTokensToBottom(moved);
7185 if (VALIDATE_TOKENS) {
7186 mWindowManager.validateAppTokens(mHistory);
7187 }
7188
7189 finishTaskMove(task);
7190 return true;
7191 }
7192
7193 public void moveTaskBackwards(int task) {
7194 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7195 "moveTaskBackwards()");
7196
7197 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007198 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7199 Binder.getCallingUid(), "Task backwards")) {
7200 return;
7201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007202 final long origId = Binder.clearCallingIdentity();
7203 moveTaskBackwardsLocked(task);
7204 Binder.restoreCallingIdentity(origId);
7205 }
7206 }
7207
7208 private final void moveTaskBackwardsLocked(int task) {
7209 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7210 }
7211
7212 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7213 synchronized(this) {
7214 return getTaskForActivityLocked(token, onlyRoot);
7215 }
7216 }
7217
7218 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7219 final int N = mHistory.size();
7220 TaskRecord lastTask = null;
7221 for (int i=0; i<N; i++) {
7222 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7223 if (r == token) {
7224 if (!onlyRoot || lastTask != r.task) {
7225 return r.task.taskId;
7226 }
7227 return -1;
7228 }
7229 lastTask = r.task;
7230 }
7231
7232 return -1;
7233 }
7234
7235 /**
7236 * Returns the top activity in any existing task matching the given
7237 * Intent. Returns null if no such task is found.
7238 */
7239 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7240 ComponentName cls = intent.getComponent();
7241 if (info.targetActivity != null) {
7242 cls = new ComponentName(info.packageName, info.targetActivity);
7243 }
7244
7245 TaskRecord cp = null;
7246
7247 final int N = mHistory.size();
7248 for (int i=(N-1); i>=0; i--) {
7249 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7250 if (!r.finishing && r.task != cp
7251 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7252 cp = r.task;
7253 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7254 // + "/aff=" + r.task.affinity + " to new cls="
7255 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7256 if (r.task.affinity != null) {
7257 if (r.task.affinity.equals(info.taskAffinity)) {
7258 //Log.i(TAG, "Found matching affinity!");
7259 return r;
7260 }
7261 } else if (r.task.intent != null
7262 && r.task.intent.getComponent().equals(cls)) {
7263 //Log.i(TAG, "Found matching class!");
7264 //dump();
7265 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7266 return r;
7267 } else if (r.task.affinityIntent != null
7268 && r.task.affinityIntent.getComponent().equals(cls)) {
7269 //Log.i(TAG, "Found matching class!");
7270 //dump();
7271 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7272 return r;
7273 }
7274 }
7275 }
7276
7277 return null;
7278 }
7279
7280 /**
7281 * Returns the first activity (starting from the top of the stack) that
7282 * is the same as the given activity. Returns null if no such activity
7283 * is found.
7284 */
7285 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7286 ComponentName cls = intent.getComponent();
7287 if (info.targetActivity != null) {
7288 cls = new ComponentName(info.packageName, info.targetActivity);
7289 }
7290
7291 final int N = mHistory.size();
7292 for (int i=(N-1); i>=0; i--) {
7293 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7294 if (!r.finishing) {
7295 if (r.intent.getComponent().equals(cls)) {
7296 //Log.i(TAG, "Found matching class!");
7297 //dump();
7298 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7299 return r;
7300 }
7301 }
7302 }
7303
7304 return null;
7305 }
7306
7307 public void finishOtherInstances(IBinder token, ComponentName className) {
7308 synchronized(this) {
7309 final long origId = Binder.clearCallingIdentity();
7310
7311 int N = mHistory.size();
7312 TaskRecord lastTask = null;
7313 for (int i=0; i<N; i++) {
7314 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7315 if (r.realActivity.equals(className)
7316 && r != token && lastTask != r.task) {
7317 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7318 null, "others")) {
7319 i--;
7320 N--;
7321 }
7322 }
7323 lastTask = r.task;
7324 }
7325
7326 Binder.restoreCallingIdentity(origId);
7327 }
7328 }
7329
7330 // =========================================================
7331 // THUMBNAILS
7332 // =========================================================
7333
7334 public void reportThumbnail(IBinder token,
7335 Bitmap thumbnail, CharSequence description) {
7336 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7337 final long origId = Binder.clearCallingIdentity();
7338 sendPendingThumbnail(null, token, thumbnail, description, true);
7339 Binder.restoreCallingIdentity(origId);
7340 }
7341
7342 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7343 Bitmap thumbnail, CharSequence description, boolean always) {
7344 TaskRecord task = null;
7345 ArrayList receivers = null;
7346
7347 //System.out.println("Send pending thumbnail: " + r);
7348
7349 synchronized(this) {
7350 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007351 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007352 if (index < 0) {
7353 return;
7354 }
7355 r = (HistoryRecord)mHistory.get(index);
7356 }
7357 if (thumbnail == null) {
7358 thumbnail = r.thumbnail;
7359 description = r.description;
7360 }
7361 if (thumbnail == null && !always) {
7362 // If there is no thumbnail, and this entry is not actually
7363 // going away, then abort for now and pick up the next
7364 // thumbnail we get.
7365 return;
7366 }
7367 task = r.task;
7368
7369 int N = mPendingThumbnails.size();
7370 int i=0;
7371 while (i<N) {
7372 PendingThumbnailsRecord pr =
7373 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7374 //System.out.println("Looking in " + pr.pendingRecords);
7375 if (pr.pendingRecords.remove(r)) {
7376 if (receivers == null) {
7377 receivers = new ArrayList();
7378 }
7379 receivers.add(pr);
7380 if (pr.pendingRecords.size() == 0) {
7381 pr.finished = true;
7382 mPendingThumbnails.remove(i);
7383 N--;
7384 continue;
7385 }
7386 }
7387 i++;
7388 }
7389 }
7390
7391 if (receivers != null) {
7392 final int N = receivers.size();
7393 for (int i=0; i<N; i++) {
7394 try {
7395 PendingThumbnailsRecord pr =
7396 (PendingThumbnailsRecord)receivers.get(i);
7397 pr.receiver.newThumbnail(
7398 task != null ? task.taskId : -1, thumbnail, description);
7399 if (pr.finished) {
7400 pr.receiver.finished();
7401 }
7402 } catch (Exception e) {
7403 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7404 }
7405 }
7406 }
7407 }
7408
7409 // =========================================================
7410 // CONTENT PROVIDERS
7411 // =========================================================
7412
7413 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7414 List providers = null;
7415 try {
7416 providers = ActivityThread.getPackageManager().
7417 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007418 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007419 } catch (RemoteException ex) {
7420 }
7421 if (providers != null) {
7422 final int N = providers.size();
7423 for (int i=0; i<N; i++) {
7424 ProviderInfo cpi =
7425 (ProviderInfo)providers.get(i);
7426 ContentProviderRecord cpr =
7427 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7428 if (cpr == null) {
7429 cpr = new ContentProviderRecord(cpi, app.info);
7430 mProvidersByClass.put(cpi.name, cpr);
7431 }
7432 app.pubProviders.put(cpi.name, cpr);
7433 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007434 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007435 }
7436 }
7437 return providers;
7438 }
7439
7440 private final String checkContentProviderPermissionLocked(
7441 ProviderInfo cpi, ProcessRecord r, int mode) {
7442 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7443 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7444 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7445 cpi.exported ? -1 : cpi.applicationInfo.uid)
7446 == PackageManager.PERMISSION_GRANTED
7447 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7448 return null;
7449 }
7450 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7451 cpi.exported ? -1 : cpi.applicationInfo.uid)
7452 == PackageManager.PERMISSION_GRANTED) {
7453 return null;
7454 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007455
7456 PathPermission[] pps = cpi.pathPermissions;
7457 if (pps != null) {
7458 int i = pps.length;
7459 while (i > 0) {
7460 i--;
7461 PathPermission pp = pps[i];
7462 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7463 cpi.exported ? -1 : cpi.applicationInfo.uid)
7464 == PackageManager.PERMISSION_GRANTED
7465 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7466 return null;
7467 }
7468 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7469 cpi.exported ? -1 : cpi.applicationInfo.uid)
7470 == PackageManager.PERMISSION_GRANTED) {
7471 return null;
7472 }
7473 }
7474 }
7475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007476 String msg = "Permission Denial: opening provider " + cpi.name
7477 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7478 + ", uid=" + callingUid + ") requires "
7479 + cpi.readPermission + " or " + cpi.writePermission;
7480 Log.w(TAG, msg);
7481 return msg;
7482 }
7483
7484 private final ContentProviderHolder getContentProviderImpl(
7485 IApplicationThread caller, String name) {
7486 ContentProviderRecord cpr;
7487 ProviderInfo cpi = null;
7488
7489 synchronized(this) {
7490 ProcessRecord r = null;
7491 if (caller != null) {
7492 r = getRecordForAppLocked(caller);
7493 if (r == null) {
7494 throw new SecurityException(
7495 "Unable to find app for caller " + caller
7496 + " (pid=" + Binder.getCallingPid()
7497 + ") when getting content provider " + name);
7498 }
7499 }
7500
7501 // First check if this content provider has been published...
7502 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7503 if (cpr != null) {
7504 cpi = cpr.info;
7505 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7506 return new ContentProviderHolder(cpi,
7507 cpi.readPermission != null
7508 ? cpi.readPermission : cpi.writePermission);
7509 }
7510
7511 if (r != null && cpr.canRunHere(r)) {
7512 // This provider has been published or is in the process
7513 // of being published... but it is also allowed to run
7514 // in the caller's process, so don't make a connection
7515 // and just let the caller instantiate its own instance.
7516 if (cpr.provider != null) {
7517 // don't give caller the provider object, it needs
7518 // to make its own.
7519 cpr = new ContentProviderRecord(cpr);
7520 }
7521 return cpr;
7522 }
7523
7524 final long origId = Binder.clearCallingIdentity();
7525
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007526 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007527 // return it right away.
7528 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007529 if (DEBUG_PROVIDER) Log.v(TAG,
7530 "Adding provider requested by "
7531 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007532 + cpr.info.processName);
7533 Integer cnt = r.conProviders.get(cpr);
7534 if (cnt == null) {
7535 r.conProviders.put(cpr, new Integer(1));
7536 } else {
7537 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007539 cpr.clients.add(r);
7540 } else {
7541 cpr.externals++;
7542 }
7543
7544 if (cpr.app != null) {
7545 updateOomAdjLocked(cpr.app);
7546 }
7547
7548 Binder.restoreCallingIdentity(origId);
7549
7550 } else {
7551 try {
7552 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007553 resolveContentProvider(name,
7554 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007555 } catch (RemoteException ex) {
7556 }
7557 if (cpi == null) {
7558 return null;
7559 }
7560
7561 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7562 return new ContentProviderHolder(cpi,
7563 cpi.readPermission != null
7564 ? cpi.readPermission : cpi.writePermission);
7565 }
7566
7567 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7568 final boolean firstClass = cpr == null;
7569 if (firstClass) {
7570 try {
7571 ApplicationInfo ai =
7572 ActivityThread.getPackageManager().
7573 getApplicationInfo(
7574 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007575 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007576 if (ai == null) {
7577 Log.w(TAG, "No package info for content provider "
7578 + cpi.name);
7579 return null;
7580 }
7581 cpr = new ContentProviderRecord(cpi, ai);
7582 } catch (RemoteException ex) {
7583 // pm is in same process, this will never happen.
7584 }
7585 }
7586
7587 if (r != null && cpr.canRunHere(r)) {
7588 // If this is a multiprocess provider, then just return its
7589 // info and allow the caller to instantiate it. Only do
7590 // this if the provider is the same user as the caller's
7591 // process, or can run as root (so can be in any process).
7592 return cpr;
7593 }
7594
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007595 if (DEBUG_PROVIDER) {
7596 RuntimeException e = new RuntimeException("here");
7597 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7598 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007599 }
7600
7601 // This is single process, and our app is now connecting to it.
7602 // See if we are already in the process of launching this
7603 // provider.
7604 final int N = mLaunchingProviders.size();
7605 int i;
7606 for (i=0; i<N; i++) {
7607 if (mLaunchingProviders.get(i) == cpr) {
7608 break;
7609 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007610 }
7611
7612 // If the provider is not already being launched, then get it
7613 // started.
7614 if (i >= N) {
7615 final long origId = Binder.clearCallingIdentity();
7616 ProcessRecord proc = startProcessLocked(cpi.processName,
7617 cpr.appInfo, false, 0, "content provider",
7618 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007619 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007620 if (proc == null) {
7621 Log.w(TAG, "Unable to launch app "
7622 + cpi.applicationInfo.packageName + "/"
7623 + cpi.applicationInfo.uid + " for provider "
7624 + name + ": process is bad");
7625 return null;
7626 }
7627 cpr.launchingApp = proc;
7628 mLaunchingProviders.add(cpr);
7629 Binder.restoreCallingIdentity(origId);
7630 }
7631
7632 // Make sure the provider is published (the same provider class
7633 // may be published under multiple names).
7634 if (firstClass) {
7635 mProvidersByClass.put(cpi.name, cpr);
7636 }
7637 mProvidersByName.put(name, cpr);
7638
7639 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007640 if (DEBUG_PROVIDER) Log.v(TAG,
7641 "Adding provider requested by "
7642 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007643 + cpr.info.processName);
7644 Integer cnt = r.conProviders.get(cpr);
7645 if (cnt == null) {
7646 r.conProviders.put(cpr, new Integer(1));
7647 } else {
7648 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007650 cpr.clients.add(r);
7651 } else {
7652 cpr.externals++;
7653 }
7654 }
7655 }
7656
7657 // Wait for the provider to be published...
7658 synchronized (cpr) {
7659 while (cpr.provider == null) {
7660 if (cpr.launchingApp == null) {
7661 Log.w(TAG, "Unable to launch app "
7662 + cpi.applicationInfo.packageName + "/"
7663 + cpi.applicationInfo.uid + " for provider "
7664 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007665 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007666 cpi.applicationInfo.packageName,
7667 cpi.applicationInfo.uid, name);
7668 return null;
7669 }
7670 try {
7671 cpr.wait();
7672 } catch (InterruptedException ex) {
7673 }
7674 }
7675 }
7676 return cpr;
7677 }
7678
7679 public final ContentProviderHolder getContentProvider(
7680 IApplicationThread caller, String name) {
7681 if (caller == null) {
7682 String msg = "null IApplicationThread when getting content provider "
7683 + name;
7684 Log.w(TAG, msg);
7685 throw new SecurityException(msg);
7686 }
7687
7688 return getContentProviderImpl(caller, name);
7689 }
7690
7691 private ContentProviderHolder getContentProviderExternal(String name) {
7692 return getContentProviderImpl(null, name);
7693 }
7694
7695 /**
7696 * Drop a content provider from a ProcessRecord's bookkeeping
7697 * @param cpr
7698 */
7699 public void removeContentProvider(IApplicationThread caller, String name) {
7700 synchronized (this) {
7701 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7702 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007703 // remove from mProvidersByClass
7704 if (DEBUG_PROVIDER) Log.v(TAG, name +
7705 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007706 return;
7707 }
7708 final ProcessRecord r = getRecordForAppLocked(caller);
7709 if (r == null) {
7710 throw new SecurityException(
7711 "Unable to find app for caller " + caller +
7712 " when removing content provider " + name);
7713 }
7714 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007715 ContentProviderRecord localCpr = (ContentProviderRecord)
7716 mProvidersByClass.get(cpr.info.name);
7717 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7718 + r.info.processName + " from process "
7719 + localCpr.appInfo.processName);
7720 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007721 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007722 Log.w(TAG, "removeContentProvider called on local provider: "
7723 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007724 return;
7725 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007726 Integer cnt = r.conProviders.get(localCpr);
7727 if (cnt == null || cnt.intValue() <= 1) {
7728 localCpr.clients.remove(r);
7729 r.conProviders.remove(localCpr);
7730 } else {
7731 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7732 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007733 }
7734 updateOomAdjLocked();
7735 }
7736 }
7737
7738 private void removeContentProviderExternal(String name) {
7739 synchronized (this) {
7740 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7741 if(cpr == null) {
7742 //remove from mProvidersByClass
7743 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7744 return;
7745 }
7746
7747 //update content provider record entry info
7748 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7749 localCpr.externals--;
7750 if (localCpr.externals < 0) {
7751 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7752 }
7753 updateOomAdjLocked();
7754 }
7755 }
7756
7757 public final void publishContentProviders(IApplicationThread caller,
7758 List<ContentProviderHolder> providers) {
7759 if (providers == null) {
7760 return;
7761 }
7762
7763 synchronized(this) {
7764 final ProcessRecord r = getRecordForAppLocked(caller);
7765 if (r == null) {
7766 throw new SecurityException(
7767 "Unable to find app for caller " + caller
7768 + " (pid=" + Binder.getCallingPid()
7769 + ") when publishing content providers");
7770 }
7771
7772 final long origId = Binder.clearCallingIdentity();
7773
7774 final int N = providers.size();
7775 for (int i=0; i<N; i++) {
7776 ContentProviderHolder src = providers.get(i);
7777 if (src == null || src.info == null || src.provider == null) {
7778 continue;
7779 }
7780 ContentProviderRecord dst =
7781 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7782 if (dst != null) {
7783 mProvidersByClass.put(dst.info.name, dst);
7784 String names[] = dst.info.authority.split(";");
7785 for (int j = 0; j < names.length; j++) {
7786 mProvidersByName.put(names[j], dst);
7787 }
7788
7789 int NL = mLaunchingProviders.size();
7790 int j;
7791 for (j=0; j<NL; j++) {
7792 if (mLaunchingProviders.get(j) == dst) {
7793 mLaunchingProviders.remove(j);
7794 j--;
7795 NL--;
7796 }
7797 }
7798 synchronized (dst) {
7799 dst.provider = src.provider;
7800 dst.app = r;
7801 dst.notifyAll();
7802 }
7803 updateOomAdjLocked(r);
7804 }
7805 }
7806
7807 Binder.restoreCallingIdentity(origId);
7808 }
7809 }
7810
7811 public static final void installSystemProviders() {
7812 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7813 List providers = mSelf.generateApplicationProvidersLocked(app);
7814 mSystemThread.installSystemProviders(providers);
7815 }
7816
7817 // =========================================================
7818 // GLOBAL MANAGEMENT
7819 // =========================================================
7820
7821 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7822 ApplicationInfo info, String customProcess) {
7823 String proc = customProcess != null ? customProcess : info.processName;
7824 BatteryStatsImpl.Uid.Proc ps = null;
7825 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7826 synchronized (stats) {
7827 ps = stats.getProcessStatsLocked(info.uid, proc);
7828 }
7829 return new ProcessRecord(ps, thread, info, proc);
7830 }
7831
7832 final ProcessRecord addAppLocked(ApplicationInfo info) {
7833 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7834
7835 if (app == null) {
7836 app = newProcessRecordLocked(null, info, null);
7837 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007838 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007839 }
7840
7841 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7842 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7843 app.persistent = true;
7844 app.maxAdj = CORE_SERVER_ADJ;
7845 }
7846 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7847 mPersistentStartingProcesses.add(app);
7848 startProcessLocked(app, "added application", app.processName);
7849 }
7850
7851 return app;
7852 }
7853
7854 public void unhandledBack() {
7855 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7856 "unhandledBack()");
7857
7858 synchronized(this) {
7859 int count = mHistory.size();
Dianne Hackborn03abb812010-01-04 18:43:19 -08007860 if (DEBUG_SWITCH) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007861 TAG, "Performing unhandledBack(): stack size = " + count);
7862 if (count > 1) {
7863 final long origId = Binder.clearCallingIdentity();
7864 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7865 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7866 Binder.restoreCallingIdentity(origId);
7867 }
7868 }
7869 }
7870
7871 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7872 String name = uri.getAuthority();
7873 ContentProviderHolder cph = getContentProviderExternal(name);
7874 ParcelFileDescriptor pfd = null;
7875 if (cph != null) {
7876 // We record the binder invoker's uid in thread-local storage before
7877 // going to the content provider to open the file. Later, in the code
7878 // that handles all permissions checks, we look for this uid and use
7879 // that rather than the Activity Manager's own uid. The effect is that
7880 // we do the check against the caller's permissions even though it looks
7881 // to the content provider like the Activity Manager itself is making
7882 // the request.
7883 sCallerIdentity.set(new Identity(
7884 Binder.getCallingPid(), Binder.getCallingUid()));
7885 try {
7886 pfd = cph.provider.openFile(uri, "r");
7887 } catch (FileNotFoundException e) {
7888 // do nothing; pfd will be returned null
7889 } finally {
7890 // Ensure that whatever happens, we clean up the identity state
7891 sCallerIdentity.remove();
7892 }
7893
7894 // We've got the fd now, so we're done with the provider.
7895 removeContentProviderExternal(name);
7896 } else {
7897 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7898 }
7899 return pfd;
7900 }
7901
7902 public void goingToSleep() {
7903 synchronized(this) {
7904 mSleeping = true;
7905 mWindowManager.setEventDispatching(false);
7906
7907 if (mResumedActivity != null) {
7908 pauseIfSleepingLocked();
7909 } else {
7910 Log.w(TAG, "goingToSleep with no resumed activity!");
7911 }
7912 }
7913 }
7914
Dianne Hackborn55280a92009-05-07 15:53:46 -07007915 public boolean shutdown(int timeout) {
7916 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7917 != PackageManager.PERMISSION_GRANTED) {
7918 throw new SecurityException("Requires permission "
7919 + android.Manifest.permission.SHUTDOWN);
7920 }
7921
7922 boolean timedout = false;
7923
7924 synchronized(this) {
7925 mShuttingDown = true;
7926 mWindowManager.setEventDispatching(false);
7927
7928 if (mResumedActivity != null) {
7929 pauseIfSleepingLocked();
7930 final long endTime = System.currentTimeMillis() + timeout;
7931 while (mResumedActivity != null || mPausingActivity != null) {
7932 long delay = endTime - System.currentTimeMillis();
7933 if (delay <= 0) {
7934 Log.w(TAG, "Activity manager shutdown timed out");
7935 timedout = true;
7936 break;
7937 }
7938 try {
7939 this.wait();
7940 } catch (InterruptedException e) {
7941 }
7942 }
7943 }
7944 }
7945
7946 mUsageStatsService.shutdown();
7947 mBatteryStatsService.shutdown();
7948
7949 return timedout;
7950 }
7951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007952 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007953 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007954 if (!mGoingToSleep.isHeld()) {
7955 mGoingToSleep.acquire();
7956 if (mLaunchingActivity.isHeld()) {
7957 mLaunchingActivity.release();
7958 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7959 }
7960 }
7961
7962 // If we are not currently pausing an activity, get the current
7963 // one to pause. If we are pausing one, we will just let that stuff
7964 // run and release the wake lock when all done.
7965 if (mPausingActivity == null) {
7966 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7967 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7968 startPausingLocked(false, true);
7969 }
7970 }
7971 }
7972
7973 public void wakingUp() {
7974 synchronized(this) {
7975 if (mGoingToSleep.isHeld()) {
7976 mGoingToSleep.release();
7977 }
7978 mWindowManager.setEventDispatching(true);
7979 mSleeping = false;
7980 resumeTopActivityLocked(null);
7981 }
7982 }
7983
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007984 public void stopAppSwitches() {
7985 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7986 != PackageManager.PERMISSION_GRANTED) {
7987 throw new SecurityException("Requires permission "
7988 + android.Manifest.permission.STOP_APP_SWITCHES);
7989 }
7990
7991 synchronized(this) {
7992 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7993 + APP_SWITCH_DELAY_TIME;
7994 mDidAppSwitch = false;
7995 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7996 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7997 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7998 }
7999 }
8000
8001 public void resumeAppSwitches() {
8002 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8003 != PackageManager.PERMISSION_GRANTED) {
8004 throw new SecurityException("Requires permission "
8005 + android.Manifest.permission.STOP_APP_SWITCHES);
8006 }
8007
8008 synchronized(this) {
8009 // Note that we don't execute any pending app switches... we will
8010 // let those wait until either the timeout, or the next start
8011 // activity request.
8012 mAppSwitchesAllowedTime = 0;
8013 }
8014 }
8015
8016 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8017 String name) {
8018 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8019 return true;
8020 }
8021
8022 final int perm = checkComponentPermission(
8023 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8024 callingUid, -1);
8025 if (perm == PackageManager.PERMISSION_GRANTED) {
8026 return true;
8027 }
8028
8029 Log.w(TAG, name + " request from " + callingUid + " stopped");
8030 return false;
8031 }
8032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008033 public void setDebugApp(String packageName, boolean waitForDebugger,
8034 boolean persistent) {
8035 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8036 "setDebugApp()");
8037
8038 // Note that this is not really thread safe if there are multiple
8039 // callers into it at the same time, but that's not a situation we
8040 // care about.
8041 if (persistent) {
8042 final ContentResolver resolver = mContext.getContentResolver();
8043 Settings.System.putString(
8044 resolver, Settings.System.DEBUG_APP,
8045 packageName);
8046 Settings.System.putInt(
8047 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8048 waitForDebugger ? 1 : 0);
8049 }
8050
8051 synchronized (this) {
8052 if (!persistent) {
8053 mOrigDebugApp = mDebugApp;
8054 mOrigWaitForDebugger = mWaitForDebugger;
8055 }
8056 mDebugApp = packageName;
8057 mWaitForDebugger = waitForDebugger;
8058 mDebugTransient = !persistent;
8059 if (packageName != null) {
8060 final long origId = Binder.clearCallingIdentity();
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08008061 forceStopPackageLocked(packageName, -1, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008062 Binder.restoreCallingIdentity(origId);
8063 }
8064 }
8065 }
8066
8067 public void setAlwaysFinish(boolean enabled) {
8068 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8069 "setAlwaysFinish()");
8070
8071 Settings.System.putInt(
8072 mContext.getContentResolver(),
8073 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8074
8075 synchronized (this) {
8076 mAlwaysFinishActivities = enabled;
8077 }
8078 }
8079
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008080 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008081 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008082 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008083 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008084 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008085 }
8086 }
8087
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08008088 public boolean isUserAMonkey() {
8089 // For now the fact that there is a controller implies
8090 // we have a monkey.
8091 synchronized (this) {
8092 return mController != null;
8093 }
8094 }
8095
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008096 public void registerActivityWatcher(IActivityWatcher watcher) {
8097 mWatchers.register(watcher);
8098 }
8099
8100 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8101 mWatchers.unregister(watcher);
8102 }
8103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008104 public final void enterSafeMode() {
8105 synchronized(this) {
8106 // It only makes sense to do this before the system is ready
8107 // and started launching other packages.
8108 if (!mSystemReady) {
8109 try {
8110 ActivityThread.getPackageManager().enterSafeMode();
8111 } catch (RemoteException e) {
8112 }
8113
8114 View v = LayoutInflater.from(mContext).inflate(
8115 com.android.internal.R.layout.safe_mode, null);
8116 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8117 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8118 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8119 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8120 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8121 lp.format = v.getBackground().getOpacity();
8122 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8123 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8124 ((WindowManager)mContext.getSystemService(
8125 Context.WINDOW_SERVICE)).addView(v, lp);
8126 }
8127 }
8128 }
8129
8130 public void noteWakeupAlarm(IIntentSender sender) {
8131 if (!(sender instanceof PendingIntentRecord)) {
8132 return;
8133 }
8134 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8135 synchronized (stats) {
8136 if (mBatteryStatsService.isOnBattery()) {
8137 mBatteryStatsService.enforceCallingPermission();
8138 PendingIntentRecord rec = (PendingIntentRecord)sender;
8139 int MY_UID = Binder.getCallingUid();
8140 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8141 BatteryStatsImpl.Uid.Pkg pkg =
8142 stats.getPackageStatsLocked(uid, rec.key.packageName);
8143 pkg.incWakeupsLocked();
8144 }
8145 }
8146 }
8147
8148 public boolean killPidsForMemory(int[] pids) {
8149 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8150 throw new SecurityException("killPidsForMemory only available to the system");
8151 }
8152
8153 // XXX Note: don't acquire main activity lock here, because the window
8154 // manager calls in with its locks held.
8155
8156 boolean killed = false;
8157 synchronized (mPidsSelfLocked) {
8158 int[] types = new int[pids.length];
8159 int worstType = 0;
8160 for (int i=0; i<pids.length; i++) {
8161 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8162 if (proc != null) {
8163 int type = proc.setAdj;
8164 types[i] = type;
8165 if (type > worstType) {
8166 worstType = type;
8167 }
8168 }
8169 }
8170
8171 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8172 // then constrain it so we will kill all hidden procs.
8173 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8174 worstType = HIDDEN_APP_MIN_ADJ;
8175 }
8176 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8177 for (int i=0; i<pids.length; i++) {
8178 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8179 if (proc == null) {
8180 continue;
8181 }
8182 int adj = proc.setAdj;
8183 if (adj >= worstType) {
8184 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8185 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008186 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008187 proc.processName, adj);
8188 killed = true;
8189 Process.killProcess(pids[i]);
8190 }
8191 }
8192 }
8193 return killed;
8194 }
8195
8196 public void reportPss(IApplicationThread caller, int pss) {
8197 Watchdog.PssRequestor req;
8198 String name;
8199 ProcessRecord callerApp;
8200 synchronized (this) {
8201 if (caller == null) {
8202 return;
8203 }
8204 callerApp = getRecordForAppLocked(caller);
8205 if (callerApp == null) {
8206 return;
8207 }
8208 callerApp.lastPss = pss;
8209 req = callerApp;
8210 name = callerApp.processName;
8211 }
8212 Watchdog.getInstance().reportPss(req, name, pss);
8213 if (!callerApp.persistent) {
8214 removeRequestedPss(callerApp);
8215 }
8216 }
8217
8218 public void requestPss(Runnable completeCallback) {
8219 ArrayList<ProcessRecord> procs;
8220 synchronized (this) {
8221 mRequestPssCallback = completeCallback;
8222 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008223 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8224 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008225 if (!proc.persistent) {
8226 mRequestPssList.add(proc);
8227 }
8228 }
8229 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8230 }
8231
8232 int oldPri = Process.getThreadPriority(Process.myTid());
8233 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8234 for (int i=procs.size()-1; i>=0; i--) {
8235 ProcessRecord proc = procs.get(i);
8236 proc.lastPss = 0;
8237 proc.requestPss();
8238 }
8239 Process.setThreadPriority(oldPri);
8240 }
8241
8242 void removeRequestedPss(ProcessRecord proc) {
8243 Runnable callback = null;
8244 synchronized (this) {
8245 if (mRequestPssList.remove(proc)) {
8246 if (mRequestPssList.size() == 0) {
8247 callback = mRequestPssCallback;
8248 mRequestPssCallback = null;
8249 }
8250 }
8251 }
8252
8253 if (callback != null) {
8254 callback.run();
8255 }
8256 }
8257
8258 public void collectPss(Watchdog.PssStats stats) {
8259 stats.mEmptyPss = 0;
8260 stats.mEmptyCount = 0;
8261 stats.mBackgroundPss = 0;
8262 stats.mBackgroundCount = 0;
8263 stats.mServicePss = 0;
8264 stats.mServiceCount = 0;
8265 stats.mVisiblePss = 0;
8266 stats.mVisibleCount = 0;
8267 stats.mForegroundPss = 0;
8268 stats.mForegroundCount = 0;
8269 stats.mNoPssCount = 0;
8270 synchronized (this) {
8271 int i;
8272 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8273 ? mProcDeaths.length : stats.mProcDeaths.length;
8274 int aggr = 0;
8275 for (i=0; i<NPD; i++) {
8276 aggr += mProcDeaths[i];
8277 stats.mProcDeaths[i] = aggr;
8278 }
8279 while (i<stats.mProcDeaths.length) {
8280 stats.mProcDeaths[i] = 0;
8281 i++;
8282 }
8283
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008284 for (i=mLruProcesses.size()-1; i>=0; i--) {
8285 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008286 if (proc.persistent) {
8287 continue;
8288 }
8289 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8290 if (proc.lastPss == 0) {
8291 stats.mNoPssCount++;
8292 continue;
8293 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008294 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8295 if (proc.empty) {
8296 stats.mEmptyPss += proc.lastPss;
8297 stats.mEmptyCount++;
8298 } else {
8299 stats.mBackgroundPss += proc.lastPss;
8300 stats.mBackgroundCount++;
8301 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008302 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8303 stats.mVisiblePss += proc.lastPss;
8304 stats.mVisibleCount++;
8305 } else {
8306 stats.mForegroundPss += proc.lastPss;
8307 stats.mForegroundCount++;
8308 }
8309 }
8310 }
8311 }
8312
8313 public final void startRunning(String pkg, String cls, String action,
8314 String data) {
8315 synchronized(this) {
8316 if (mStartRunning) {
8317 return;
8318 }
8319 mStartRunning = true;
8320 mTopComponent = pkg != null && cls != null
8321 ? new ComponentName(pkg, cls) : null;
8322 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8323 mTopData = data;
8324 if (!mSystemReady) {
8325 return;
8326 }
8327 }
8328
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008329 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008330 }
8331
8332 private void retrieveSettings() {
8333 final ContentResolver resolver = mContext.getContentResolver();
8334 String debugApp = Settings.System.getString(
8335 resolver, Settings.System.DEBUG_APP);
8336 boolean waitForDebugger = Settings.System.getInt(
8337 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8338 boolean alwaysFinishActivities = Settings.System.getInt(
8339 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8340
8341 Configuration configuration = new Configuration();
8342 Settings.System.getConfiguration(resolver, configuration);
8343
8344 synchronized (this) {
8345 mDebugApp = mOrigDebugApp = debugApp;
8346 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8347 mAlwaysFinishActivities = alwaysFinishActivities;
8348 // This happens before any activities are started, so we can
8349 // change mConfiguration in-place.
8350 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008351 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008352 }
8353 }
8354
8355 public boolean testIsSystemReady() {
8356 // no need to synchronize(this) just to read & return the value
8357 return mSystemReady;
8358 }
8359
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008360 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008361 // In the simulator, startRunning will never have been called, which
8362 // normally sets a few crucial variables. Do it here instead.
8363 if (!Process.supportsProcesses()) {
8364 mStartRunning = true;
8365 mTopAction = Intent.ACTION_MAIN;
8366 }
8367
8368 synchronized(this) {
8369 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008370 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008371 return;
8372 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008373
8374 // Check to see if there are any update receivers to run.
8375 if (!mDidUpdate) {
8376 if (mWaitingUpdate) {
8377 return;
8378 }
8379 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8380 List<ResolveInfo> ris = null;
8381 try {
8382 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8383 intent, null, 0);
8384 } catch (RemoteException e) {
8385 }
8386 if (ris != null) {
8387 for (int i=ris.size()-1; i>=0; i--) {
8388 if ((ris.get(i).activityInfo.applicationInfo.flags
8389 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8390 ris.remove(i);
8391 }
8392 }
8393 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8394 for (int i=0; i<ris.size(); i++) {
8395 ActivityInfo ai = ris.get(i).activityInfo;
8396 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8397 IIntentReceiver finisher = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -08008398 if (i == ris.size()-1) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008399 finisher = new IIntentReceiver.Stub() {
8400 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008401 String data, Bundle extras, boolean ordered,
8402 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008403 throws RemoteException {
8404 synchronized (ActivityManagerService.this) {
8405 mDidUpdate = true;
8406 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008407 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008408 }
8409 };
8410 }
8411 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8412 broadcastIntentLocked(null, null, intent, null, finisher,
8413 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornd6847842010-01-12 18:14:19 -08008414 if (finisher != null) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008415 mWaitingUpdate = true;
8416 }
8417 }
8418 }
8419 if (mWaitingUpdate) {
8420 return;
8421 }
8422 mDidUpdate = true;
8423 }
8424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008425 mSystemReady = true;
8426 if (!mStartRunning) {
8427 return;
8428 }
8429 }
8430
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008431 ArrayList<ProcessRecord> procsToKill = null;
8432 synchronized(mPidsSelfLocked) {
8433 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8434 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8435 if (!isAllowedWhileBooting(proc.info)){
8436 if (procsToKill == null) {
8437 procsToKill = new ArrayList<ProcessRecord>();
8438 }
8439 procsToKill.add(proc);
8440 }
8441 }
8442 }
8443
8444 if (procsToKill != null) {
8445 synchronized(this) {
8446 for (int i=procsToKill.size()-1; i>=0; i--) {
8447 ProcessRecord proc = procsToKill.get(i);
8448 Log.i(TAG, "Removing system update proc: " + proc);
8449 removeProcessLocked(proc, true);
8450 }
8451 }
8452 }
8453
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008454 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008455 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008456 SystemClock.uptimeMillis());
8457
8458 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008459 // Make sure we have no pre-ready processes sitting around.
8460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008461 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8462 ResolveInfo ri = mContext.getPackageManager()
8463 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008464 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008465 CharSequence errorMsg = null;
8466 if (ri != null) {
8467 ActivityInfo ai = ri.activityInfo;
8468 ApplicationInfo app = ai.applicationInfo;
8469 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8470 mTopAction = Intent.ACTION_FACTORY_TEST;
8471 mTopData = null;
8472 mTopComponent = new ComponentName(app.packageName,
8473 ai.name);
8474 } else {
8475 errorMsg = mContext.getResources().getText(
8476 com.android.internal.R.string.factorytest_not_system);
8477 }
8478 } else {
8479 errorMsg = mContext.getResources().getText(
8480 com.android.internal.R.string.factorytest_no_action);
8481 }
8482 if (errorMsg != null) {
8483 mTopAction = null;
8484 mTopData = null;
8485 mTopComponent = null;
8486 Message msg = Message.obtain();
8487 msg.what = SHOW_FACTORY_ERROR_MSG;
8488 msg.getData().putCharSequence("msg", errorMsg);
8489 mHandler.sendMessage(msg);
8490 }
8491 }
8492 }
8493
8494 retrieveSettings();
8495
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008496 if (goingCallback != null) goingCallback.run();
8497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008498 synchronized (this) {
8499 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8500 try {
8501 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008502 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008503 if (apps != null) {
8504 int N = apps.size();
8505 int i;
8506 for (i=0; i<N; i++) {
8507 ApplicationInfo info
8508 = (ApplicationInfo)apps.get(i);
8509 if (info != null &&
8510 !info.packageName.equals("android")) {
8511 addAppLocked(info);
8512 }
8513 }
8514 }
8515 } catch (RemoteException ex) {
8516 // pm is in same process, this will never happen.
8517 }
8518 }
8519
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008520 // Start up initial activity.
8521 mBooting = true;
8522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008523 try {
8524 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8525 Message msg = Message.obtain();
8526 msg.what = SHOW_UID_ERROR_MSG;
8527 mHandler.sendMessage(msg);
8528 }
8529 } catch (RemoteException e) {
8530 }
8531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008532 resumeTopActivityLocked(null);
8533 }
8534 }
8535
Dan Egnorb7f03672009-12-09 16:22:32 -08008536 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008537 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008538 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008539 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008540 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008541 startAppProblemLocked(app);
8542 app.stopFreezingAllLocked();
8543 return handleAppCrashLocked(app);
8544 }
8545
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008546 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Doug Zongker43866e02010-01-07 12:09:54 -08008547 // check if error reporting is enabled in secure settings
8548 int enabled = Settings.Secure.getInt(mContext.getContentResolver(),
8549 Settings.Secure.SEND_ACTION_APP_ERROR, 0);
Jacek Surazskia2339432009-09-18 15:01:26 +02008550 if (enabled == 0) {
8551 return null;
8552 }
8553
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008554 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008555
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008556 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008557 // look for receiver in the installer package
8558 String candidate = pm.getInstallerPackageName(app.info.packageName);
8559 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8560 if (result != null) {
8561 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008562 }
8563
Jacek Surazski82a73df2009-06-17 14:33:18 +02008564 // if the error app is on the system image, look for system apps
8565 // error receiver
8566 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8567 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8568 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8569 if (result != null) {
8570 return result;
8571 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008572 }
8573
Jacek Surazski82a73df2009-06-17 14:33:18 +02008574 // if there is a default receiver, try that
8575 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8576 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008577 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008578 // should not happen
8579 Log.e(TAG, "error talking to PackageManager", e);
8580 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008581 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008582 }
8583
8584 /**
8585 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8586 *
8587 * @param pm PackageManager isntance
8588 * @param errorPackage package which caused the error
8589 * @param receiverPackage candidate package to receive the error
8590 * @return activity component within receiverPackage which handles
8591 * ACTION_APP_ERROR, or null if not found
8592 */
8593 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8594 String receiverPackage) throws RemoteException {
8595 if (receiverPackage == null || receiverPackage.length() == 0) {
8596 return null;
8597 }
8598
8599 // break the loop if it's the error report receiver package that crashed
8600 if (receiverPackage.equals(errorPackage)) {
8601 return null;
8602 }
8603
8604 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8605 intent.setPackage(receiverPackage);
8606 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8607 if (info == null || info.activityInfo == null) {
8608 return null;
8609 }
8610 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008611 }
8612
Dan Egnorb7f03672009-12-09 16:22:32 -08008613 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008614 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008615 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008616 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008617 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8618 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008619 startAppProblemLocked(app);
8620 app.stopFreezingAllLocked();
8621 }
8622
8623 /**
8624 * Generate a process error record, suitable for attachment to a ProcessRecord.
8625 *
8626 * @param app The ProcessRecord in which the error occurred.
8627 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8628 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008629 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008630 * @param shortMsg Short message describing the crash.
8631 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008632 * @param stackTrace Full crash stack trace, may be null.
8633 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008634 * @return Returns a fully-formed AppErrorStateInfo record.
8635 */
8636 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008637 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008638 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008640 report.condition = condition;
8641 report.processName = app.processName;
8642 report.pid = app.pid;
8643 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008644 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008645 report.shortMsg = shortMsg;
8646 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008647 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008648
8649 return report;
8650 }
8651
Dan Egnor42471dd2010-01-07 17:25:22 -08008652 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008653 synchronized (this) {
8654 app.crashing = false;
8655 app.crashingReport = null;
8656 app.notResponding = false;
8657 app.notRespondingReport = null;
8658 if (app.anrDialog == fromDialog) {
8659 app.anrDialog = null;
8660 }
8661 if (app.waitDialog == fromDialog) {
8662 app.waitDialog = null;
8663 }
8664 if (app.pid > 0 && app.pid != MY_PID) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008665 handleAppCrashLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008666 Log.i(ActivityManagerService.TAG, "Killing process "
8667 + app.processName
8668 + " (pid=" + app.pid + ") at user's request");
8669 Process.killProcess(app.pid);
8670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008671 }
8672 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008673
Dan Egnorb7f03672009-12-09 16:22:32 -08008674 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008675 long now = SystemClock.uptimeMillis();
8676
8677 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8678 app.info.uid);
8679 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8680 // This process loses!
8681 Log.w(TAG, "Process " + app.info.processName
8682 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008683 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008684 app.info.processName, app.info.uid);
8685 killServicesLocked(app, false);
8686 for (int i=mHistory.size()-1; i>=0; i--) {
8687 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8688 if (r.app == app) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08008689 Log.w(TAG, " Force finishing activity "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008690 + r.intent.getComponent().flattenToShortString());
8691 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8692 }
8693 }
8694 if (!app.persistent) {
8695 // We don't want to start this process again until the user
8696 // explicitly does so... but for persistent process, we really
8697 // need to keep it running. If a persistent process is actually
8698 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008699 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008700 app.info.processName);
8701 mBadProcesses.put(app.info.processName, app.info.uid, now);
8702 app.bad = true;
8703 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8704 app.removed = true;
8705 removeProcessLocked(app, false);
8706 return false;
8707 }
8708 }
8709
8710 // Bump up the crash count of any services currently running in the proc.
8711 if (app.services.size() != 0) {
8712 // Any services running in the application need to be placed
8713 // back in the pending list.
8714 Iterator it = app.services.iterator();
8715 while (it.hasNext()) {
8716 ServiceRecord sr = (ServiceRecord)it.next();
8717 sr.crashCount++;
8718 }
8719 }
8720
8721 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8722 return true;
8723 }
8724
8725 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008726 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008727 skipCurrentReceiverLocked(app);
8728 }
8729
8730 void skipCurrentReceiverLocked(ProcessRecord app) {
8731 boolean reschedule = false;
8732 BroadcastRecord r = app.curReceiver;
8733 if (r != null) {
8734 // The current broadcast is waiting for this app's receiver
8735 // to be finished. Looks like that's not going to happen, so
8736 // let the broadcast continue.
8737 logBroadcastReceiverDiscard(r);
8738 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8739 r.resultExtras, r.resultAbort, true);
8740 reschedule = true;
8741 }
8742 r = mPendingBroadcast;
8743 if (r != null && r.curApp == app) {
8744 if (DEBUG_BROADCAST) Log.v(TAG,
8745 "skip & discard pending app " + r);
8746 logBroadcastReceiverDiscard(r);
8747 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8748 r.resultExtras, r.resultAbort, true);
8749 reschedule = true;
8750 }
8751 if (reschedule) {
8752 scheduleBroadcastsLocked();
8753 }
8754 }
8755
Dan Egnor60d87622009-12-16 16:32:58 -08008756 /**
8757 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8758 * The application process will exit immediately after this call returns.
8759 * @param app object of the crashing app, null for the system server
8760 * @param crashInfo describing the exception
8761 */
8762 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8763 ProcessRecord r = findAppProcess(app);
8764
8765 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8766 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008767 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008768 crashInfo.exceptionClassName,
8769 crashInfo.exceptionMessage,
8770 crashInfo.throwFileName,
8771 crashInfo.throwLineNumber);
8772
Dan Egnor42471dd2010-01-07 17:25:22 -08008773 addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008774
8775 crashApplication(r, crashInfo);
8776 }
8777
8778 /**
8779 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8780 * @param app object of the crashing app, null for the system server
8781 * @param tag reported by the caller
8782 * @param crashInfo describing the context of the error
8783 * @return true if the process should exit immediately (WTF is fatal)
8784 */
8785 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008786 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008787 ProcessRecord r = findAppProcess(app);
8788
8789 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8790 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008791 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008792 tag, crashInfo.exceptionMessage);
8793
Dan Egnor42471dd2010-01-07 17:25:22 -08008794 addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008795
Doug Zongker43866e02010-01-07 12:09:54 -08008796 if (Settings.Secure.getInt(mContext.getContentResolver(),
8797 Settings.Secure.WTF_IS_FATAL, 0) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008798 crashApplication(r, crashInfo);
8799 return true;
8800 } else {
8801 return false;
8802 }
8803 }
8804
8805 /**
8806 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8807 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8808 */
8809 private ProcessRecord findAppProcess(IBinder app) {
8810 if (app == null) {
8811 return null;
8812 }
8813
8814 synchronized (this) {
8815 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8816 final int NA = apps.size();
8817 for (int ia=0; ia<NA; ia++) {
8818 ProcessRecord p = apps.valueAt(ia);
8819 if (p.thread != null && p.thread.asBinder() == app) {
8820 return p;
8821 }
8822 }
8823 }
8824
8825 Log.w(TAG, "Can't find mystery application: " + app);
8826 return null;
8827 }
8828 }
8829
8830 /**
Dan Egnor42471dd2010-01-07 17:25:22 -08008831 * Write a description of an error (crash, WTF, ANR) to the drop box.
Dan Egnor60d87622009-12-16 16:32:58 -08008832 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
Dan Egnor42471dd2010-01-07 17:25:22 -08008833 * @param process which caused the error, null means the system server
8834 * @param activity which triggered the error, null if unknown
8835 * @param parent activity related to the error, null if unknown
8836 * @param subject line related to the error, null if absent
8837 * @param report in long form describing the error, null if absent
8838 * @param logFile to include in the report, null if none
8839 * @param crashInfo giving an application stack trace, null if absent
Dan Egnor60d87622009-12-16 16:32:58 -08008840 */
Dan Egnor42471dd2010-01-07 17:25:22 -08008841 private void addErrorToDropBox(String eventType,
8842 ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
8843 String subject, String report, File logFile,
Dan Egnor60d87622009-12-16 16:32:58 -08008844 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008845 String dropboxTag;
8846 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008847 dropboxTag = "system_server_" + eventType;
Dan Egnor42471dd2010-01-07 17:25:22 -08008848 } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008849 dropboxTag = "system_app_" + eventType;
8850 } else {
8851 dropboxTag = "data_app_" + eventType;
8852 }
8853
8854 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8855 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8856 StringBuilder sb = new StringBuilder(1024);
Dan Egnor42471dd2010-01-07 17:25:22 -08008857 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008858 sb.append("Process: system_server\n");
8859 } else {
Dan Egnor42471dd2010-01-07 17:25:22 -08008860 sb.append("Process: ").append(process.processName).append("\n");
Dan Egnor66c40e72010-01-26 16:23:11 -08008861 }
8862 if (process != null) {
8863 int flags = process.info.flags;
8864 IPackageManager pm = ActivityThread.getPackageManager();
8865 sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
8866 for (String pkg : process.pkgList) {
8867 sb.append("Package: ").append(pkg);
8868 try {
8869 PackageInfo pi = pm.getPackageInfo(pkg, 0);
8870 if (pi != null) {
8871 sb.append(" v").append(pi.versionCode);
8872 if (pi.versionName != null) {
8873 sb.append(" (").append(pi.versionName).append(")");
8874 }
8875 }
8876 } catch (RemoteException e) {
8877 Log.e(TAG, "Error getting package info: " + pkg, e);
8878 }
8879 sb.append("\n");
8880 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008881 }
8882 if (activity != null) {
8883 sb.append("Activity: ").append(activity.shortComponentName).append("\n");
8884 }
8885 if (parent != null && parent.app != null && parent.app.pid != process.pid) {
8886 sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
8887 }
8888 if (parent != null && parent != activity) {
8889 sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
8890 }
8891 if (subject != null) {
8892 sb.append("Subject: ").append(subject).append("\n");
8893 }
8894 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8895 sb.append("\n");
8896 if (report != null) {
8897 sb.append(report);
8898 }
8899 if (logFile != null) {
8900 try {
8901 sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
8902 } catch (IOException e) {
8903 Log.e(TAG, "Error reading " + logFile, e);
Dan Egnor60d87622009-12-16 16:32:58 -08008904 }
8905 }
Dan Egnor60d87622009-12-16 16:32:58 -08008906 if (crashInfo != null && crashInfo.stackTrace != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008907 sb.append(crashInfo.stackTrace);
Dan Egnor60d87622009-12-16 16:32:58 -08008908 }
8909 dbox.addText(dropboxTag, sb.toString());
8910 }
8911 }
8912
8913 /**
8914 * Bring up the "unexpected error" dialog box for a crashing app.
8915 * Deal with edge cases (intercepts from instrumented applications,
8916 * ActivityController, error intent receivers, that sort of thing).
8917 * @param r the application crashing
8918 * @param crashInfo describing the failure
8919 */
8920 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008921 long timeMillis = System.currentTimeMillis();
8922 String shortMsg = crashInfo.exceptionClassName;
8923 String longMsg = crashInfo.exceptionMessage;
8924 String stackTrace = crashInfo.stackTrace;
8925 if (shortMsg != null && longMsg != null) {
8926 longMsg = shortMsg + ": " + longMsg;
8927 } else if (shortMsg != null) {
8928 longMsg = shortMsg;
8929 }
8930
Dan Egnor60d87622009-12-16 16:32:58 -08008931 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008932 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008933 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008934 try {
8935 String name = r != null ? r.processName : null;
8936 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008937 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008938 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008939 Log.w(TAG, "Force-killing crashed app " + name
8940 + " at watcher's request");
8941 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008942 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008943 }
8944 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008945 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008946 }
8947 }
8948
8949 final long origId = Binder.clearCallingIdentity();
8950
8951 // If this process is running instrumentation, finish it.
8952 if (r != null && r.instrumentationClass != null) {
8953 Log.w(TAG, "Error in app " + r.processName
8954 + " running instrumentation " + r.instrumentationClass + ":");
8955 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8956 if (longMsg != null) Log.w(TAG, " " + longMsg);
8957 Bundle info = new Bundle();
8958 info.putString("shortMsg", shortMsg);
8959 info.putString("longMsg", longMsg);
8960 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8961 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008962 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008963 }
8964
Dan Egnor60d87622009-12-16 16:32:58 -08008965 // If we can't identify the process or it's already exceeded its crash quota,
8966 // quit right away without showing a crash dialog.
8967 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008968 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008969 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970 }
8971
8972 Message msg = Message.obtain();
8973 msg.what = SHOW_ERROR_MSG;
8974 HashMap data = new HashMap();
8975 data.put("result", result);
8976 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008977 msg.obj = data;
8978 mHandler.sendMessage(msg);
8979
8980 Binder.restoreCallingIdentity(origId);
8981 }
8982
8983 int res = result.get();
8984
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008985 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008986 synchronized (this) {
8987 if (r != null) {
8988 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8989 SystemClock.uptimeMillis());
8990 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008991 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008992 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008993 }
8994 }
8995
8996 if (appErrorIntent != null) {
8997 try {
8998 mContext.startActivity(appErrorIntent);
8999 } catch (ActivityNotFoundException e) {
9000 Log.w(TAG, "bug report receiver dissappeared", e);
9001 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009002 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009003 }
Dan Egnorb7f03672009-12-09 16:22:32 -08009004
9005 Intent createAppErrorIntentLocked(ProcessRecord r,
9006 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
9007 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009008 if (report == null) {
9009 return null;
9010 }
9011 Intent result = new Intent(Intent.ACTION_APP_ERROR);
9012 result.setComponent(r.errorReportReceiver);
9013 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
9014 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
9015 return result;
9016 }
9017
Dan Egnorb7f03672009-12-09 16:22:32 -08009018 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
9019 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009020 if (r.errorReportReceiver == null) {
9021 return null;
9022 }
9023
9024 if (!r.crashing && !r.notResponding) {
9025 return null;
9026 }
9027
Dan Egnorb7f03672009-12-09 16:22:32 -08009028 ApplicationErrorReport report = new ApplicationErrorReport();
9029 report.packageName = r.info.packageName;
9030 report.installerPackageName = r.errorReportReceiver.getPackageName();
9031 report.processName = r.processName;
9032 report.time = timeMillis;
Jacek Surazskie0ee6ef2010-01-07 16:23:03 +01009033 report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009034
Dan Egnorb7f03672009-12-09 16:22:32 -08009035 if (r.crashing) {
9036 report.type = ApplicationErrorReport.TYPE_CRASH;
9037 report.crashInfo = crashInfo;
9038 } else if (r.notResponding) {
9039 report.type = ApplicationErrorReport.TYPE_ANR;
9040 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009041
Dan Egnorb7f03672009-12-09 16:22:32 -08009042 report.anrInfo.activity = r.notRespondingReport.tag;
9043 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9044 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009045 }
9046
Dan Egnorb7f03672009-12-09 16:22:32 -08009047 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009048 }
9049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009050 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9051 // assume our apps are happy - lazy create the list
9052 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9053
9054 synchronized (this) {
9055
9056 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009057 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9058 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009059 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9060 // This one's in trouble, so we'll generate a report for it
9061 // crashes are higher priority (in case there's a crash *and* an anr)
9062 ActivityManager.ProcessErrorStateInfo report = null;
9063 if (app.crashing) {
9064 report = app.crashingReport;
9065 } else if (app.notResponding) {
9066 report = app.notRespondingReport;
9067 }
9068
9069 if (report != null) {
9070 if (errList == null) {
9071 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9072 }
9073 errList.add(report);
9074 } else {
9075 Log.w(TAG, "Missing app error report, app = " + app.processName +
9076 " crashing = " + app.crashing +
9077 " notResponding = " + app.notResponding);
9078 }
9079 }
9080 }
9081 }
9082
9083 return errList;
9084 }
9085
9086 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9087 // Lazy instantiation of list
9088 List<ActivityManager.RunningAppProcessInfo> runList = null;
9089 synchronized (this) {
9090 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009091 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9092 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009093 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9094 // Generate process state info for running application
9095 ActivityManager.RunningAppProcessInfo currApp =
9096 new ActivityManager.RunningAppProcessInfo(app.processName,
9097 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009098 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009099 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009100 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009101 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9102 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9103 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009104 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9105 } else if (adj >= HOME_APP_ADJ) {
9106 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9107 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009108 } else if (adj >= SECONDARY_SERVER_ADJ) {
9109 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9110 } else if (adj >= VISIBLE_APP_ADJ) {
9111 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9112 } else {
9113 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9114 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009115 currApp.importanceReasonCode = app.adjTypeCode;
9116 if (app.adjSource instanceof ProcessRecord) {
9117 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9118 } else if (app.adjSource instanceof HistoryRecord) {
9119 HistoryRecord r = (HistoryRecord)app.adjSource;
9120 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9121 }
9122 if (app.adjTarget instanceof ComponentName) {
9123 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009125 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9126 // + " lru=" + currApp.lru);
9127 if (runList == null) {
9128 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9129 }
9130 runList.add(currApp);
9131 }
9132 }
9133 }
9134 return runList;
9135 }
9136
9137 @Override
9138 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009139 if (checkCallingPermission(android.Manifest.permission.DUMP)
9140 != PackageManager.PERMISSION_GRANTED) {
9141 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9142 + Binder.getCallingPid()
9143 + ", uid=" + Binder.getCallingUid()
9144 + " without permission "
9145 + android.Manifest.permission.DUMP);
9146 return;
9147 }
9148
9149 boolean dumpAll = false;
9150
9151 int opti = 0;
9152 while (opti < args.length) {
9153 String opt = args[opti];
9154 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9155 break;
9156 }
9157 opti++;
9158 if ("-a".equals(opt)) {
9159 dumpAll = true;
9160 } else if ("-h".equals(opt)) {
9161 pw.println("Activity manager dump options:");
9162 pw.println(" [-a] [h- [cmd] ...");
9163 pw.println(" cmd may be one of:");
9164 pw.println(" activities: activity stack state");
9165 pw.println(" broadcasts: broadcast state");
9166 pw.println(" intents: pending intent state");
9167 pw.println(" processes: process state");
9168 pw.println(" providers: content provider state");
9169 pw.println(" services: service state");
9170 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009171 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009172 } else {
9173 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009174 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009175 }
9176
9177 // Is the caller requesting to dump a particular piece of data?
9178 if (opti < args.length) {
9179 String cmd = args[opti];
9180 opti++;
9181 if ("activities".equals(cmd) || "a".equals(cmd)) {
9182 synchronized (this) {
9183 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009184 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009185 return;
9186 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9187 synchronized (this) {
9188 dumpBroadcastsLocked(fd, pw, args, opti, true);
9189 }
9190 return;
9191 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9192 synchronized (this) {
9193 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9194 }
9195 return;
9196 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9197 synchronized (this) {
9198 dumpProcessesLocked(fd, pw, args, opti, true);
9199 }
9200 return;
9201 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9202 synchronized (this) {
9203 dumpProvidersLocked(fd, pw, args, opti, true);
9204 }
9205 return;
9206 } else if ("service".equals(cmd)) {
9207 dumpService(fd, pw, args, opti, true);
9208 return;
9209 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9210 synchronized (this) {
9211 dumpServicesLocked(fd, pw, args, opti, true);
9212 }
9213 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009214 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009215 }
9216
9217 // No piece of data specified, dump everything.
9218 synchronized (this) {
9219 boolean needSep;
9220 if (dumpAll) {
9221 pw.println("Providers in Current Activity Manager State:");
9222 }
9223 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9224 if (needSep) {
9225 pw.println(" ");
9226 }
9227 if (dumpAll) {
9228 pw.println("-------------------------------------------------------------------------------");
9229 pw.println("Broadcasts in Current Activity Manager State:");
9230 }
9231 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9232 if (needSep) {
9233 pw.println(" ");
9234 }
9235 if (dumpAll) {
9236 pw.println("-------------------------------------------------------------------------------");
9237 pw.println("Services in Current Activity Manager State:");
9238 }
9239 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9240 if (needSep) {
9241 pw.println(" ");
9242 }
9243 if (dumpAll) {
9244 pw.println("-------------------------------------------------------------------------------");
9245 pw.println("PendingIntents in Current Activity Manager State:");
9246 }
9247 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9248 if (needSep) {
9249 pw.println(" ");
9250 }
9251 if (dumpAll) {
9252 pw.println("-------------------------------------------------------------------------------");
9253 pw.println("Activities in Current Activity Manager State:");
9254 }
9255 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9256 if (needSep) {
9257 pw.println(" ");
9258 }
9259 if (dumpAll) {
9260 pw.println("-------------------------------------------------------------------------------");
9261 pw.println("Processes in Current Activity Manager State:");
9262 }
9263 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9264 }
9265 }
9266
9267 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9268 int opti, boolean dumpAll, boolean needHeader) {
9269 if (needHeader) {
9270 pw.println(" Activity stack:");
9271 }
9272 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9273 pw.println(" ");
9274 pw.println(" Running activities (most recent first):");
9275 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9276 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009277 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009278 pw.println(" Activities waiting for another to become visible:");
9279 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9280 }
9281 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009282 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009283 pw.println(" Activities waiting to stop:");
9284 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9285 }
9286 if (mFinishingActivities.size() > 0) {
9287 pw.println(" ");
9288 pw.println(" Activities waiting to finish:");
9289 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9290 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009291
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009292 pw.println(" ");
9293 pw.println(" mPausingActivity: " + mPausingActivity);
9294 pw.println(" mResumedActivity: " + mResumedActivity);
9295 pw.println(" mFocusedActivity: " + mFocusedActivity);
9296 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009297
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009298 if (dumpAll && mRecentTasks.size() > 0) {
9299 pw.println(" ");
9300 pw.println("Recent tasks in Current Activity Manager State:");
9301
9302 final int N = mRecentTasks.size();
9303 for (int i=0; i<N; i++) {
9304 TaskRecord tr = mRecentTasks.get(i);
9305 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9306 pw.println(tr);
9307 mRecentTasks.get(i).dump(pw, " ");
9308 }
9309 }
9310
9311 pw.println(" ");
9312 pw.println(" mCurTask: " + mCurTask);
9313
9314 return true;
9315 }
9316
9317 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9318 int opti, boolean dumpAll) {
9319 boolean needSep = false;
9320 int numPers = 0;
9321
9322 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009323 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9324 final int NA = procs.size();
9325 for (int ia=0; ia<NA; ia++) {
9326 if (!needSep) {
9327 pw.println(" All known processes:");
9328 needSep = true;
9329 }
9330 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009331 pw.print(r.persistent ? " *PERS*" : " *APP*");
9332 pw.print(" UID "); pw.print(procs.keyAt(ia));
9333 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009334 r.dump(pw, " ");
9335 if (r.persistent) {
9336 numPers++;
9337 }
9338 }
9339 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009340 }
9341
9342 if (mLruProcesses.size() > 0) {
9343 if (needSep) pw.println(" ");
9344 needSep = true;
9345 pw.println(" Running processes (most recent first):");
9346 dumpProcessList(pw, this, mLruProcesses, " ",
9347 "App ", "PERS", true);
9348 needSep = true;
9349 }
9350
9351 synchronized (mPidsSelfLocked) {
9352 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009353 if (needSep) pw.println(" ");
9354 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009355 pw.println(" PID mappings:");
9356 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9357 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9358 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009359 }
9360 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009361 }
9362
9363 if (mForegroundProcesses.size() > 0) {
9364 if (needSep) pw.println(" ");
9365 needSep = true;
9366 pw.println(" Foreground Processes:");
9367 for (int i=0; i<mForegroundProcesses.size(); i++) {
9368 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9369 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009370 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009371 }
9372
9373 if (mPersistentStartingProcesses.size() > 0) {
9374 if (needSep) pw.println(" ");
9375 needSep = true;
9376 pw.println(" Persisent processes that are starting:");
9377 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9378 "Starting Norm", "Restarting PERS", false);
9379 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009380
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009381 if (mStartingProcesses.size() > 0) {
9382 if (needSep) pw.println(" ");
9383 needSep = true;
9384 pw.println(" Processes that are starting:");
9385 dumpProcessList(pw, this, mStartingProcesses, " ",
9386 "Starting Norm", "Starting PERS", false);
9387 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009388
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009389 if (mRemovedProcesses.size() > 0) {
9390 if (needSep) pw.println(" ");
9391 needSep = true;
9392 pw.println(" Processes that are being removed:");
9393 dumpProcessList(pw, this, mRemovedProcesses, " ",
9394 "Removed Norm", "Removed PERS", false);
9395 }
9396
9397 if (mProcessesOnHold.size() > 0) {
9398 if (needSep) pw.println(" ");
9399 needSep = true;
9400 pw.println(" Processes that are on old until the system is ready:");
9401 dumpProcessList(pw, this, mProcessesOnHold, " ",
9402 "OnHold Norm", "OnHold PERS", false);
9403 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009404
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009405 if (mProcessesToGc.size() > 0) {
9406 if (needSep) pw.println(" ");
9407 needSep = true;
9408 pw.println(" Processes that are waiting to GC:");
9409 long now = SystemClock.uptimeMillis();
9410 for (int i=0; i<mProcessesToGc.size(); i++) {
9411 ProcessRecord proc = mProcessesToGc.get(i);
9412 pw.print(" Process "); pw.println(proc);
9413 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9414 pw.print(", last gced=");
9415 pw.print(now-proc.lastRequestedGc);
9416 pw.print(" ms ago, last lowMem=");
9417 pw.print(now-proc.lastLowMemory);
9418 pw.println(" ms ago");
9419
9420 }
9421 }
9422
9423 if (mProcessCrashTimes.getMap().size() > 0) {
9424 if (needSep) pw.println(" ");
9425 needSep = true;
9426 pw.println(" Time since processes crashed:");
9427 long now = SystemClock.uptimeMillis();
9428 for (Map.Entry<String, SparseArray<Long>> procs
9429 : mProcessCrashTimes.getMap().entrySet()) {
9430 SparseArray<Long> uids = procs.getValue();
9431 final int N = uids.size();
9432 for (int i=0; i<N; i++) {
9433 pw.print(" Process "); pw.print(procs.getKey());
9434 pw.print(" uid "); pw.print(uids.keyAt(i));
9435 pw.print(": last crashed ");
9436 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009437 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009438 }
9439 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009441
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009442 if (mBadProcesses.getMap().size() > 0) {
9443 if (needSep) pw.println(" ");
9444 needSep = true;
9445 pw.println(" Bad processes:");
9446 for (Map.Entry<String, SparseArray<Long>> procs
9447 : mBadProcesses.getMap().entrySet()) {
9448 SparseArray<Long> uids = procs.getValue();
9449 final int N = uids.size();
9450 for (int i=0; i<N; i++) {
9451 pw.print(" Bad process "); pw.print(procs.getKey());
9452 pw.print(" uid "); pw.print(uids.keyAt(i));
9453 pw.print(": crashed at time ");
9454 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009455 }
9456 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009458
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009459 pw.println(" ");
9460 pw.println(" mHomeProcess: " + mHomeProcess);
9461 pw.println(" mConfiguration: " + mConfiguration);
9462 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9463 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9464 || mOrigWaitForDebugger) {
9465 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9466 + " mDebugTransient=" + mDebugTransient
9467 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9468 }
9469 if (mAlwaysFinishActivities || mController != null) {
9470 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9471 + " mController=" + mController);
9472 }
9473 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009474 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009475 pw.println(" mStartRunning=" + mStartRunning
9476 + " mSystemReady=" + mSystemReady
9477 + " mBooting=" + mBooting
9478 + " mBooted=" + mBooted
9479 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009480 pw.println(" mGoingToSleep=" + mGoingToSleep);
9481 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009482 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009483
9484 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009485 }
9486
9487 /**
9488 * There are three ways to call this:
9489 * - no service specified: dump all the services
9490 * - a flattened component name that matched an existing service was specified as the
9491 * first arg: dump that one service
9492 * - the first arg isn't the flattened component name of an existing service:
9493 * dump all services whose component contains the first arg as a substring
9494 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009495 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9496 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009497 String[] newArgs;
9498 String componentNameString;
9499 ServiceRecord r;
Kenny Root3619b9ab2010-02-13 10:05:42 -08009500 if (opti >= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009501 componentNameString = null;
9502 newArgs = EMPTY_STRING_ARRAY;
9503 r = null;
9504 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009505 componentNameString = args[opti];
9506 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009507 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9508 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009509 newArgs = new String[args.length - opti];
9510 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009511 }
9512
9513 if (r != null) {
9514 dumpService(fd, pw, r, newArgs);
9515 } else {
9516 for (ServiceRecord r1 : mServices.values()) {
9517 if (componentNameString == null
9518 || r1.name.flattenToString().contains(componentNameString)) {
9519 dumpService(fd, pw, r1, newArgs);
9520 }
9521 }
9522 }
9523 }
9524
9525 /**
9526 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9527 * there is a thread associated with the service.
9528 */
9529 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9530 pw.println(" Service " + r.name.flattenToString());
9531 if (r.app != null && r.app.thread != null) {
9532 try {
9533 // flush anything that is already in the PrintWriter since the thread is going
9534 // to write to the file descriptor directly
9535 pw.flush();
9536 r.app.thread.dumpService(fd, r, args);
9537 pw.print("\n");
9538 } catch (RemoteException e) {
9539 pw.println("got a RemoteException while dumping the service");
9540 }
9541 }
9542 }
9543
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009544 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9545 int opti, boolean dumpAll) {
9546 boolean needSep = false;
9547
9548 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009549 if (mRegisteredReceivers.size() > 0) {
9550 pw.println(" ");
9551 pw.println(" Registered Receivers:");
9552 Iterator it = mRegisteredReceivers.values().iterator();
9553 while (it.hasNext()) {
9554 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009555 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009556 r.dump(pw, " ");
9557 }
9558 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009560 pw.println(" ");
9561 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009562 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009563 needSep = true;
9564 }
9565
9566 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9567 || mPendingBroadcast != null) {
9568 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009569 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009570 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009571 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009572 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9573 pw.println(" Broadcast #" + i + ":");
9574 mParallelBroadcasts.get(i).dump(pw, " ");
9575 }
9576 if (mOrderedBroadcasts.size() > 0) {
9577 pw.println(" ");
9578 pw.println(" Active serialized broadcasts:");
9579 }
9580 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9581 pw.println(" Serialized Broadcast #" + i + ":");
9582 mOrderedBroadcasts.get(i).dump(pw, " ");
9583 }
9584 pw.println(" ");
9585 pw.println(" Pending broadcast:");
9586 if (mPendingBroadcast != null) {
9587 mPendingBroadcast.dump(pw, " ");
9588 } else {
9589 pw.println(" (null)");
9590 }
9591 needSep = true;
9592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009593
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009594 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009595 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009596 pw.println(" Historical broadcasts:");
9597 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9598 BroadcastRecord r = mBroadcastHistory[i];
9599 if (r == null) {
9600 break;
9601 }
9602 pw.println(" Historical Broadcast #" + i + ":");
9603 r.dump(pw, " ");
9604 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009605 needSep = true;
9606 }
9607
9608 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009609 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009610 pw.println(" Sticky broadcasts:");
9611 StringBuilder sb = new StringBuilder(128);
9612 for (Map.Entry<String, ArrayList<Intent>> ent
9613 : mStickyBroadcasts.entrySet()) {
9614 pw.print(" * Sticky action "); pw.print(ent.getKey());
9615 pw.println(":");
9616 ArrayList<Intent> intents = ent.getValue();
9617 final int N = intents.size();
9618 for (int i=0; i<N; i++) {
9619 sb.setLength(0);
9620 sb.append(" Intent: ");
9621 intents.get(i).toShortString(sb, true, false);
9622 pw.println(sb.toString());
9623 Bundle bundle = intents.get(i).getExtras();
9624 if (bundle != null) {
9625 pw.print(" ");
9626 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009627 }
9628 }
9629 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009630 needSep = true;
9631 }
9632
9633 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009634 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009635 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009636 pw.println(" mHandler:");
9637 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009638 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009639 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009640
9641 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009642 }
9643
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009644 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9645 int opti, boolean dumpAll) {
9646 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009647
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009648 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009649 if (mServices.size() > 0) {
9650 pw.println(" Active services:");
9651 Iterator<ServiceRecord> it = mServices.values().iterator();
9652 while (it.hasNext()) {
9653 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009654 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009655 r.dump(pw, " ");
9656 }
9657 needSep = true;
9658 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009660
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009661 if (mPendingServices.size() > 0) {
9662 if (needSep) pw.println(" ");
9663 pw.println(" Pending services:");
9664 for (int i=0; i<mPendingServices.size(); i++) {
9665 ServiceRecord r = mPendingServices.get(i);
9666 pw.print(" * Pending "); pw.println(r);
9667 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009668 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009669 needSep = true;
9670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009671
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009672 if (mRestartingServices.size() > 0) {
9673 if (needSep) pw.println(" ");
9674 pw.println(" Restarting services:");
9675 for (int i=0; i<mRestartingServices.size(); i++) {
9676 ServiceRecord r = mRestartingServices.get(i);
9677 pw.print(" * Restarting "); pw.println(r);
9678 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009679 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009680 needSep = true;
9681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009682
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009683 if (mStoppingServices.size() > 0) {
9684 if (needSep) pw.println(" ");
9685 pw.println(" Stopping services:");
9686 for (int i=0; i<mStoppingServices.size(); i++) {
9687 ServiceRecord r = mStoppingServices.get(i);
9688 pw.print(" * Stopping "); pw.println(r);
9689 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009690 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009691 needSep = true;
9692 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009693
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009694 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009695 if (mServiceConnections.size() > 0) {
9696 if (needSep) pw.println(" ");
9697 pw.println(" Connection bindings to services:");
9698 Iterator<ConnectionRecord> it
9699 = mServiceConnections.values().iterator();
9700 while (it.hasNext()) {
9701 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009702 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009703 r.dump(pw, " ");
9704 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009705 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009706 }
9707 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009708
9709 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009710 }
9711
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009712 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9713 int opti, boolean dumpAll) {
9714 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009715
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009716 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009717 if (mProvidersByClass.size() > 0) {
9718 if (needSep) pw.println(" ");
9719 pw.println(" Published content providers (by class):");
9720 Iterator it = mProvidersByClass.entrySet().iterator();
9721 while (it.hasNext()) {
9722 Map.Entry e = (Map.Entry)it.next();
9723 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009724 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009725 r.dump(pw, " ");
9726 }
9727 needSep = true;
9728 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009729
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009730 if (mProvidersByName.size() > 0) {
9731 pw.println(" ");
9732 pw.println(" Authority to provider mappings:");
9733 Iterator it = mProvidersByName.entrySet().iterator();
9734 while (it.hasNext()) {
9735 Map.Entry e = (Map.Entry)it.next();
9736 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9737 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9738 pw.println(r);
9739 }
9740 needSep = true;
9741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009742 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009743
9744 if (mLaunchingProviders.size() > 0) {
9745 if (needSep) pw.println(" ");
9746 pw.println(" Launching content providers:");
9747 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9748 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9749 pw.println(mLaunchingProviders.get(i));
9750 }
9751 needSep = true;
9752 }
9753
9754 if (mGrantedUriPermissions.size() > 0) {
9755 pw.println();
9756 pw.println("Granted Uri Permissions:");
9757 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9758 int uid = mGrantedUriPermissions.keyAt(i);
9759 HashMap<Uri, UriPermission> perms
9760 = mGrantedUriPermissions.valueAt(i);
9761 pw.print(" * UID "); pw.print(uid);
9762 pw.println(" holds:");
9763 for (UriPermission perm : perms.values()) {
9764 pw.print(" "); pw.println(perm);
9765 perm.dump(pw, " ");
9766 }
9767 }
9768 needSep = true;
9769 }
9770
9771 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009772 }
9773
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009774 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9775 int opti, boolean dumpAll) {
9776 boolean needSep = false;
9777
9778 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009779 if (this.mIntentSenderRecords.size() > 0) {
9780 Iterator<WeakReference<PendingIntentRecord>> it
9781 = mIntentSenderRecords.values().iterator();
9782 while (it.hasNext()) {
9783 WeakReference<PendingIntentRecord> ref = it.next();
9784 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009785 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009786 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009787 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009788 rec.dump(pw, " ");
9789 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009790 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009791 }
9792 }
9793 }
9794 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009795
9796 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009797 }
9798
9799 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009800 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009801 TaskRecord lastTask = null;
9802 for (int i=list.size()-1; i>=0; i--) {
9803 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009804 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009805 if (lastTask != r.task) {
9806 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009807 pw.print(prefix);
9808 pw.print(full ? "* " : " ");
9809 pw.println(lastTask);
9810 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009811 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009813 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009814 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9815 pw.print(" #"); pw.print(i); pw.print(": ");
9816 pw.println(r);
9817 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009818 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009820 }
9821 }
9822
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009823 private static String buildOomTag(String prefix, String space, int val, int base) {
9824 if (val == base) {
9825 if (space == null) return prefix;
9826 return prefix + " ";
9827 }
9828 return prefix + "+" + Integer.toString(val-base);
9829 }
9830
9831 private static final int dumpProcessList(PrintWriter pw,
9832 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009833 String prefix, String normalLabel, String persistentLabel,
9834 boolean inclOomAdj) {
9835 int numPers = 0;
9836 for (int i=list.size()-1; i>=0; i--) {
9837 ProcessRecord r = (ProcessRecord)list.get(i);
9838 if (false) {
9839 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9840 + " #" + i + ":");
9841 r.dump(pw, prefix + " ");
9842 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009843 String oomAdj;
9844 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009845 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009846 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009847 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9848 } else if (r.setAdj >= HOME_APP_ADJ) {
9849 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9850 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9851 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9852 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9853 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9854 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9855 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9856 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9857 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009858 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009859 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009860 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009861 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009862 } else {
9863 oomAdj = Integer.toString(r.setAdj);
9864 }
9865 String schedGroup;
9866 switch (r.setSchedGroup) {
9867 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9868 schedGroup = "B";
9869 break;
9870 case Process.THREAD_GROUP_DEFAULT:
9871 schedGroup = "F";
9872 break;
9873 default:
9874 schedGroup = Integer.toString(r.setSchedGroup);
9875 break;
9876 }
9877 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009878 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009879 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009880 if (r.adjSource != null || r.adjTarget != null) {
9881 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009882 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009883 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009884 } else {
9885 pw.println(String.format("%s%s #%2d: %s",
9886 prefix, (r.persistent ? persistentLabel : normalLabel),
9887 i, r.toString()));
9888 }
9889 if (r.persistent) {
9890 numPers++;
9891 }
9892 }
9893 return numPers;
9894 }
9895
9896 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9897 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009898 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009899 long uptime = SystemClock.uptimeMillis();
9900 long realtime = SystemClock.elapsedRealtime();
9901
9902 if (isCheckinRequest) {
9903 // short checkin version
9904 pw.println(uptime + "," + realtime);
9905 pw.flush();
9906 } else {
9907 pw.println("Applications Memory Usage (kB):");
9908 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9909 }
9910 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9911 ProcessRecord r = (ProcessRecord)list.get(i);
9912 if (r.thread != null) {
9913 if (!isCheckinRequest) {
9914 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9915 pw.flush();
9916 }
9917 try {
9918 r.thread.asBinder().dump(fd, args);
9919 } catch (RemoteException e) {
9920 if (!isCheckinRequest) {
9921 pw.println("Got RemoteException!");
9922 pw.flush();
9923 }
9924 }
9925 }
9926 }
9927 }
9928
9929 /**
9930 * Searches array of arguments for the specified string
9931 * @param args array of argument strings
9932 * @param value value to search for
9933 * @return true if the value is contained in the array
9934 */
9935 private static boolean scanArgs(String[] args, String value) {
9936 if (args != null) {
9937 for (String arg : args) {
9938 if (value.equals(arg)) {
9939 return true;
9940 }
9941 }
9942 }
9943 return false;
9944 }
9945
Dianne Hackborn75b03852009-06-12 15:43:26 -07009946 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009947 int count = mHistory.size();
9948
9949 // convert the token to an entry in the history.
9950 HistoryRecord r = null;
9951 int index = -1;
9952 for (int i=count-1; i>=0; i--) {
9953 Object o = mHistory.get(i);
9954 if (o == token) {
9955 r = (HistoryRecord)o;
9956 index = i;
9957 break;
9958 }
9959 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009960
9961 return index;
9962 }
9963
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009964 private final void killServicesLocked(ProcessRecord app,
9965 boolean allowRestart) {
9966 // Report disconnected services.
9967 if (false) {
9968 // XXX we are letting the client link to the service for
9969 // death notifications.
9970 if (app.services.size() > 0) {
9971 Iterator it = app.services.iterator();
9972 while (it.hasNext()) {
9973 ServiceRecord r = (ServiceRecord)it.next();
9974 if (r.connections.size() > 0) {
9975 Iterator<ConnectionRecord> jt
9976 = r.connections.values().iterator();
9977 while (jt.hasNext()) {
9978 ConnectionRecord c = jt.next();
9979 if (c.binding.client != app) {
9980 try {
9981 //c.conn.connected(r.className, null);
9982 } catch (Exception e) {
9983 // todo: this should be asynchronous!
9984 Log.w(TAG, "Exception thrown disconnected servce "
9985 + r.shortName
9986 + " from app " + app.processName, e);
9987 }
9988 }
9989 }
9990 }
9991 }
9992 }
9993 }
9994
9995 // Clean up any connections this application has to other services.
9996 if (app.connections.size() > 0) {
9997 Iterator<ConnectionRecord> it = app.connections.iterator();
9998 while (it.hasNext()) {
9999 ConnectionRecord r = it.next();
10000 removeConnectionLocked(r, app, null);
10001 }
10002 }
10003 app.connections.clear();
10004
10005 if (app.services.size() != 0) {
10006 // Any services running in the application need to be placed
10007 // back in the pending list.
10008 Iterator it = app.services.iterator();
10009 while (it.hasNext()) {
10010 ServiceRecord sr = (ServiceRecord)it.next();
10011 synchronized (sr.stats.getBatteryStats()) {
10012 sr.stats.stopLaunchedLocked();
10013 }
10014 sr.app = null;
10015 sr.executeNesting = 0;
10016 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010017
10018 boolean hasClients = sr.bindings.size() > 0;
10019 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010020 Iterator<IntentBindRecord> bindings
10021 = sr.bindings.values().iterator();
10022 while (bindings.hasNext()) {
10023 IntentBindRecord b = bindings.next();
10024 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
10025 + ": shouldUnbind=" + b.hasBound);
10026 b.binder = null;
10027 b.requested = b.received = b.hasBound = false;
10028 }
10029 }
10030
10031 if (sr.crashCount >= 2) {
10032 Log.w(TAG, "Service crashed " + sr.crashCount
10033 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010034 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010035 sr.crashCount, sr.shortName, app.pid);
10036 bringDownServiceLocked(sr, true);
10037 } else if (!allowRestart) {
10038 bringDownServiceLocked(sr, true);
10039 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010040 boolean canceled = scheduleServiceRestartLocked(sr, true);
10041
10042 // Should the service remain running? Note that in the
10043 // extreme case of so many attempts to deliver a command
10044 // that it failed, that we also will stop it here.
10045 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10046 if (sr.pendingStarts.size() == 0) {
10047 sr.startRequested = false;
10048 if (!hasClients) {
10049 // Whoops, no reason to restart!
10050 bringDownServiceLocked(sr, true);
10051 }
10052 }
10053 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010054 }
10055 }
10056
10057 if (!allowRestart) {
10058 app.services.clear();
10059 }
10060 }
10061
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010062 // Make sure we have no more records on the stopping list.
10063 int i = mStoppingServices.size();
10064 while (i > 0) {
10065 i--;
10066 ServiceRecord sr = mStoppingServices.get(i);
10067 if (sr.app == app) {
10068 mStoppingServices.remove(i);
10069 }
10070 }
10071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010072 app.executingServices.clear();
10073 }
10074
10075 private final void removeDyingProviderLocked(ProcessRecord proc,
10076 ContentProviderRecord cpr) {
10077 synchronized (cpr) {
10078 cpr.launchingApp = null;
10079 cpr.notifyAll();
10080 }
10081
10082 mProvidersByClass.remove(cpr.info.name);
10083 String names[] = cpr.info.authority.split(";");
10084 for (int j = 0; j < names.length; j++) {
10085 mProvidersByName.remove(names[j]);
10086 }
10087
10088 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10089 while (cit.hasNext()) {
10090 ProcessRecord capp = cit.next();
10091 if (!capp.persistent && capp.thread != null
10092 && capp.pid != 0
10093 && capp.pid != MY_PID) {
10094 Log.i(TAG, "Killing app " + capp.processName
10095 + " (pid " + capp.pid
10096 + ") because provider " + cpr.info.name
10097 + " is in dying process " + proc.processName);
10098 Process.killProcess(capp.pid);
10099 }
10100 }
10101
10102 mLaunchingProviders.remove(cpr);
10103 }
10104
10105 /**
10106 * Main code for cleaning up a process when it has gone away. This is
10107 * called both as a result of the process dying, or directly when stopping
10108 * a process when running in single process mode.
10109 */
10110 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10111 boolean restarting, int index) {
10112 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010113 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010114 }
10115
Dianne Hackborn36124872009-10-08 16:22:03 -070010116 mProcessesToGc.remove(app);
10117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010118 // Dismiss any open dialogs.
10119 if (app.crashDialog != null) {
10120 app.crashDialog.dismiss();
10121 app.crashDialog = null;
10122 }
10123 if (app.anrDialog != null) {
10124 app.anrDialog.dismiss();
10125 app.anrDialog = null;
10126 }
10127 if (app.waitDialog != null) {
10128 app.waitDialog.dismiss();
10129 app.waitDialog = null;
10130 }
10131
10132 app.crashing = false;
10133 app.notResponding = false;
10134
10135 app.resetPackageList();
10136 app.thread = null;
10137 app.forcingToForeground = null;
10138 app.foregroundServices = false;
10139
10140 killServicesLocked(app, true);
10141
10142 boolean restart = false;
10143
10144 int NL = mLaunchingProviders.size();
10145
10146 // Remove published content providers.
10147 if (!app.pubProviders.isEmpty()) {
10148 Iterator it = app.pubProviders.values().iterator();
10149 while (it.hasNext()) {
10150 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10151 cpr.provider = null;
10152 cpr.app = null;
10153
10154 // See if someone is waiting for this provider... in which
10155 // case we don't remove it, but just let it restart.
10156 int i = 0;
10157 if (!app.bad) {
10158 for (; i<NL; i++) {
10159 if (mLaunchingProviders.get(i) == cpr) {
10160 restart = true;
10161 break;
10162 }
10163 }
10164 } else {
10165 i = NL;
10166 }
10167
10168 if (i >= NL) {
10169 removeDyingProviderLocked(app, cpr);
10170 NL = mLaunchingProviders.size();
10171 }
10172 }
10173 app.pubProviders.clear();
10174 }
10175
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010176 // Take care of any launching providers waiting for this process.
10177 if (checkAppInLaunchingProvidersLocked(app, false)) {
10178 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010179 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010181 // Unregister from connected content providers.
10182 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010183 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010184 while (it.hasNext()) {
10185 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10186 cpr.clients.remove(app);
10187 }
10188 app.conProviders.clear();
10189 }
10190
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010191 // At this point there may be remaining entries in mLaunchingProviders
10192 // where we were the only one waiting, so they are no longer of use.
10193 // Look for these and clean up if found.
10194 // XXX Commented out for now. Trying to figure out a way to reproduce
10195 // the actual situation to identify what is actually going on.
10196 if (false) {
10197 for (int i=0; i<NL; i++) {
10198 ContentProviderRecord cpr = (ContentProviderRecord)
10199 mLaunchingProviders.get(i);
10200 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10201 synchronized (cpr) {
10202 cpr.launchingApp = null;
10203 cpr.notifyAll();
10204 }
10205 }
10206 }
10207 }
10208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010209 skipCurrentReceiverLocked(app);
10210
10211 // Unregister any receivers.
10212 if (app.receivers.size() > 0) {
10213 Iterator<ReceiverList> it = app.receivers.iterator();
10214 while (it.hasNext()) {
10215 removeReceiverLocked(it.next());
10216 }
10217 app.receivers.clear();
10218 }
10219
Christopher Tate181fafa2009-05-14 11:12:14 -070010220 // If the app is undergoing backup, tell the backup manager about it
10221 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10222 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10223 try {
10224 IBackupManager bm = IBackupManager.Stub.asInterface(
10225 ServiceManager.getService(Context.BACKUP_SERVICE));
10226 bm.agentDisconnected(app.info.packageName);
10227 } catch (RemoteException e) {
10228 // can't happen; backup manager is local
10229 }
10230 }
10231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010232 // If the caller is restarting this app, then leave it in its
10233 // current lists and let the caller take care of it.
10234 if (restarting) {
10235 return;
10236 }
10237
10238 if (!app.persistent) {
10239 if (DEBUG_PROCESSES) Log.v(TAG,
10240 "Removing non-persistent process during cleanup: " + app);
10241 mProcessNames.remove(app.processName, app.info.uid);
10242 } else if (!app.removed) {
10243 // This app is persistent, so we need to keep its record around.
10244 // If it is not already on the pending app list, add it there
10245 // and start a new process for it.
10246 app.thread = null;
10247 app.forcingToForeground = null;
10248 app.foregroundServices = false;
10249 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10250 mPersistentStartingProcesses.add(app);
10251 restart = true;
10252 }
10253 }
10254 mProcessesOnHold.remove(app);
10255
The Android Open Source Project4df24232009-03-05 14:34:35 -080010256 if (app == mHomeProcess) {
10257 mHomeProcess = null;
10258 }
10259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010260 if (restart) {
10261 // We have components that still need to be running in the
10262 // process, so re-launch it.
10263 mProcessNames.put(app.processName, app.info.uid, app);
10264 startProcessLocked(app, "restart", app.processName);
10265 } else if (app.pid > 0 && app.pid != MY_PID) {
10266 // Goodbye!
10267 synchronized (mPidsSelfLocked) {
10268 mPidsSelfLocked.remove(app.pid);
10269 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10270 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010271 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010272 }
10273 }
10274
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010275 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10276 // Look through the content providers we are waiting to have launched,
10277 // and if any run in this process then either schedule a restart of
10278 // the process or kill the client waiting for it if this process has
10279 // gone bad.
10280 int NL = mLaunchingProviders.size();
10281 boolean restart = false;
10282 for (int i=0; i<NL; i++) {
10283 ContentProviderRecord cpr = (ContentProviderRecord)
10284 mLaunchingProviders.get(i);
10285 if (cpr.launchingApp == app) {
10286 if (!alwaysBad && !app.bad) {
10287 restart = true;
10288 } else {
10289 removeDyingProviderLocked(app, cpr);
10290 NL = mLaunchingProviders.size();
10291 }
10292 }
10293 }
10294 return restart;
10295 }
10296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010297 // =========================================================
10298 // SERVICES
10299 // =========================================================
10300
10301 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10302 ActivityManager.RunningServiceInfo info =
10303 new ActivityManager.RunningServiceInfo();
10304 info.service = r.name;
10305 if (r.app != null) {
10306 info.pid = r.app.pid;
10307 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010308 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010309 info.process = r.processName;
10310 info.foreground = r.isForeground;
10311 info.activeSince = r.createTime;
10312 info.started = r.startRequested;
10313 info.clientCount = r.connections.size();
10314 info.crashCount = r.crashCount;
10315 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010316 if (r.isForeground) {
10317 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10318 }
10319 if (r.startRequested) {
10320 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10321 }
Dan Egnor42471dd2010-01-07 17:25:22 -080010322 if (r.app != null && r.app.pid == MY_PID) {
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010323 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10324 }
10325 if (r.app != null && r.app.persistent) {
10326 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10327 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010328 for (ConnectionRecord conn : r.connections.values()) {
10329 if (conn.clientLabel != 0) {
10330 info.clientPackage = conn.binding.client.info.packageName;
10331 info.clientLabel = conn.clientLabel;
10332 break;
10333 }
10334 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010335 return info;
10336 }
10337
10338 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10339 int flags) {
10340 synchronized (this) {
10341 ArrayList<ActivityManager.RunningServiceInfo> res
10342 = new ArrayList<ActivityManager.RunningServiceInfo>();
10343
10344 if (mServices.size() > 0) {
10345 Iterator<ServiceRecord> it = mServices.values().iterator();
10346 while (it.hasNext() && res.size() < maxNum) {
10347 res.add(makeRunningServiceInfoLocked(it.next()));
10348 }
10349 }
10350
10351 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10352 ServiceRecord r = mRestartingServices.get(i);
10353 ActivityManager.RunningServiceInfo info =
10354 makeRunningServiceInfoLocked(r);
10355 info.restarting = r.nextRestartTime;
10356 res.add(info);
10357 }
10358
10359 return res;
10360 }
10361 }
10362
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010363 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10364 synchronized (this) {
10365 ServiceRecord r = mServices.get(name);
10366 if (r != null) {
10367 for (ConnectionRecord conn : r.connections.values()) {
10368 if (conn.clientIntent != null) {
10369 return conn.clientIntent;
10370 }
10371 }
10372 }
10373 }
10374 return null;
10375 }
10376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010377 private final ServiceRecord findServiceLocked(ComponentName name,
10378 IBinder token) {
10379 ServiceRecord r = mServices.get(name);
10380 return r == token ? r : null;
10381 }
10382
10383 private final class ServiceLookupResult {
10384 final ServiceRecord record;
10385 final String permission;
10386
10387 ServiceLookupResult(ServiceRecord _record, String _permission) {
10388 record = _record;
10389 permission = _permission;
10390 }
10391 };
10392
10393 private ServiceLookupResult findServiceLocked(Intent service,
10394 String resolvedType) {
10395 ServiceRecord r = null;
10396 if (service.getComponent() != null) {
10397 r = mServices.get(service.getComponent());
10398 }
10399 if (r == null) {
10400 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10401 r = mServicesByIntent.get(filter);
10402 }
10403
10404 if (r == null) {
10405 try {
10406 ResolveInfo rInfo =
10407 ActivityThread.getPackageManager().resolveService(
10408 service, resolvedType, 0);
10409 ServiceInfo sInfo =
10410 rInfo != null ? rInfo.serviceInfo : null;
10411 if (sInfo == null) {
10412 return null;
10413 }
10414
10415 ComponentName name = new ComponentName(
10416 sInfo.applicationInfo.packageName, sInfo.name);
10417 r = mServices.get(name);
10418 } catch (RemoteException ex) {
10419 // pm is in same process, this will never happen.
10420 }
10421 }
10422 if (r != null) {
10423 int callingPid = Binder.getCallingPid();
10424 int callingUid = Binder.getCallingUid();
10425 if (checkComponentPermission(r.permission,
10426 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10427 != PackageManager.PERMISSION_GRANTED) {
10428 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10429 + " from pid=" + callingPid
10430 + ", uid=" + callingUid
10431 + " requires " + r.permission);
10432 return new ServiceLookupResult(null, r.permission);
10433 }
10434 return new ServiceLookupResult(r, null);
10435 }
10436 return null;
10437 }
10438
10439 private class ServiceRestarter implements Runnable {
10440 private ServiceRecord mService;
10441
10442 void setService(ServiceRecord service) {
10443 mService = service;
10444 }
10445
10446 public void run() {
10447 synchronized(ActivityManagerService.this) {
10448 performServiceRestartLocked(mService);
10449 }
10450 }
10451 }
10452
10453 private ServiceLookupResult retrieveServiceLocked(Intent service,
10454 String resolvedType, int callingPid, int callingUid) {
10455 ServiceRecord r = null;
10456 if (service.getComponent() != null) {
10457 r = mServices.get(service.getComponent());
10458 }
10459 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10460 r = mServicesByIntent.get(filter);
10461 if (r == null) {
10462 try {
10463 ResolveInfo rInfo =
10464 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010465 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010466 ServiceInfo sInfo =
10467 rInfo != null ? rInfo.serviceInfo : null;
10468 if (sInfo == null) {
10469 Log.w(TAG, "Unable to start service " + service +
10470 ": not found");
10471 return null;
10472 }
10473
10474 ComponentName name = new ComponentName(
10475 sInfo.applicationInfo.packageName, sInfo.name);
10476 r = mServices.get(name);
10477 if (r == null) {
10478 filter = new Intent.FilterComparison(service.cloneFilter());
10479 ServiceRestarter res = new ServiceRestarter();
10480 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10481 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10482 synchronized (stats) {
10483 ss = stats.getServiceStatsLocked(
10484 sInfo.applicationInfo.uid, sInfo.packageName,
10485 sInfo.name);
10486 }
Dianne Hackbornb1c4a2a2010-01-19 15:36:42 -080010487 r = new ServiceRecord(this, ss, name, filter, sInfo, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010488 res.setService(r);
10489 mServices.put(name, r);
10490 mServicesByIntent.put(filter, r);
10491
10492 // Make sure this component isn't in the pending list.
10493 int N = mPendingServices.size();
10494 for (int i=0; i<N; i++) {
10495 ServiceRecord pr = mPendingServices.get(i);
10496 if (pr.name.equals(name)) {
10497 mPendingServices.remove(i);
10498 i--;
10499 N--;
10500 }
10501 }
10502 }
10503 } catch (RemoteException ex) {
10504 // pm is in same process, this will never happen.
10505 }
10506 }
10507 if (r != null) {
10508 if (checkComponentPermission(r.permission,
10509 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10510 != PackageManager.PERMISSION_GRANTED) {
10511 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10512 + " from pid=" + Binder.getCallingPid()
10513 + ", uid=" + Binder.getCallingUid()
10514 + " requires " + r.permission);
10515 return new ServiceLookupResult(null, r.permission);
10516 }
10517 return new ServiceLookupResult(r, null);
10518 }
10519 return null;
10520 }
10521
10522 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10523 long now = SystemClock.uptimeMillis();
10524 if (r.executeNesting == 0 && r.app != null) {
10525 if (r.app.executingServices.size() == 0) {
10526 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10527 msg.obj = r.app;
10528 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10529 }
10530 r.app.executingServices.add(r);
10531 }
10532 r.executeNesting++;
10533 r.executingStart = now;
10534 }
10535
10536 private final void sendServiceArgsLocked(ServiceRecord r,
10537 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010538 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010539 if (N == 0) {
10540 return;
10541 }
10542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010543 int i = 0;
10544 while (i < N) {
10545 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010546 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010547 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010548 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010549 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010550 // If somehow we got a dummy start at the front, then
10551 // just drop it here.
10552 i++;
10553 continue;
10554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010555 bumpServiceExecutingLocked(r);
10556 if (!oomAdjusted) {
10557 oomAdjusted = true;
10558 updateOomAdjLocked(r.app);
10559 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010560 int flags = 0;
10561 if (si.deliveryCount > 0) {
10562 flags |= Service.START_FLAG_RETRY;
10563 }
10564 if (si.doneExecutingCount > 0) {
10565 flags |= Service.START_FLAG_REDELIVERY;
10566 }
10567 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10568 si.deliveredTime = SystemClock.uptimeMillis();
10569 r.deliveredStarts.add(si);
10570 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010571 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010572 } catch (RemoteException e) {
10573 // Remote process gone... we'll let the normal cleanup take
10574 // care of this.
10575 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010576 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010577 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010578 break;
10579 }
10580 }
10581 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010582 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010583 } else {
10584 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010585 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010586 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010587 }
10588 }
10589 }
10590
10591 private final boolean requestServiceBindingLocked(ServiceRecord r,
10592 IntentBindRecord i, boolean rebind) {
10593 if (r.app == null || r.app.thread == null) {
10594 // If service is not currently running, can't yet bind.
10595 return false;
10596 }
10597 if ((!i.requested || rebind) && i.apps.size() > 0) {
10598 try {
10599 bumpServiceExecutingLocked(r);
10600 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10601 + ": shouldUnbind=" + i.hasBound);
10602 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10603 if (!rebind) {
10604 i.requested = true;
10605 }
10606 i.hasBound = true;
10607 i.doRebind = false;
10608 } catch (RemoteException e) {
10609 return false;
10610 }
10611 }
10612 return true;
10613 }
10614
10615 private final void requestServiceBindingsLocked(ServiceRecord r) {
10616 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10617 while (bindings.hasNext()) {
10618 IntentBindRecord i = bindings.next();
10619 if (!requestServiceBindingLocked(r, i, false)) {
10620 break;
10621 }
10622 }
10623 }
10624
10625 private final void realStartServiceLocked(ServiceRecord r,
10626 ProcessRecord app) throws RemoteException {
10627 if (app.thread == null) {
10628 throw new RemoteException();
10629 }
10630
10631 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010632 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010633
10634 app.services.add(r);
10635 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010636 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010637
10638 boolean created = false;
10639 try {
10640 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10641 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010642 mStringBuilder.setLength(0);
10643 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010644 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010645 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010646 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010647 synchronized (r.stats.getBatteryStats()) {
10648 r.stats.startLaunchedLocked();
10649 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010650 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010651 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010652 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010653 created = true;
10654 } finally {
10655 if (!created) {
10656 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010657 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010658 }
10659 }
10660
10661 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010662
10663 // If the service is in the started state, and there are no
10664 // pending arguments, then fake up one so its onStartCommand() will
10665 // be called.
10666 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10667 r.lastStartId++;
10668 if (r.lastStartId < 1) {
10669 r.lastStartId = 1;
10670 }
10671 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10672 }
10673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010674 sendServiceArgsLocked(r, true);
10675 }
10676
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010677 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10678 boolean allowCancel) {
10679 boolean canceled = false;
10680
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010681 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010682 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010683 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010684
10685 // Any delivered but not yet finished starts should be put back
10686 // on the pending list.
10687 final int N = r.deliveredStarts.size();
10688 if (N > 0) {
10689 for (int i=N-1; i>=0; i--) {
10690 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10691 if (si.intent == null) {
10692 // We'll generate this again if needed.
10693 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10694 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10695 r.pendingStarts.add(0, si);
10696 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10697 dur *= 2;
10698 if (minDuration < dur) minDuration = dur;
10699 if (resetTime < dur) resetTime = dur;
10700 } else {
10701 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10702 + r.name);
10703 canceled = true;
10704 }
10705 }
10706 r.deliveredStarts.clear();
10707 }
10708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010709 r.totalRestartCount++;
10710 if (r.restartDelay == 0) {
10711 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010712 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010713 } else {
10714 // If it has been a "reasonably long time" since the service
10715 // was started, then reset our restart duration back to
10716 // the beginning, so we don't infinitely increase the duration
10717 // on a service that just occasionally gets killed (which is
10718 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010719 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010720 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010721 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010722 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010723 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010724 if (r.restartDelay < minDuration) {
10725 r.restartDelay = minDuration;
10726 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010727 }
10728 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010729
10730 r.nextRestartTime = now + r.restartDelay;
10731
10732 // Make sure that we don't end up restarting a bunch of services
10733 // all at the same time.
10734 boolean repeat;
10735 do {
10736 repeat = false;
10737 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10738 ServiceRecord r2 = mRestartingServices.get(i);
10739 if (r2 != r && r.nextRestartTime
10740 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10741 && r.nextRestartTime
10742 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10743 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10744 r.restartDelay = r.nextRestartTime - now;
10745 repeat = true;
10746 break;
10747 }
10748 }
10749 } while (repeat);
10750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010751 if (!mRestartingServices.contains(r)) {
10752 mRestartingServices.add(r);
10753 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010754
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010755 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010757 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010758 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010759 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10760 Log.w(TAG, "Scheduling restart of crashed service "
10761 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010762 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010763 r.shortName, r.restartDelay);
10764
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010765 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010766 }
10767
10768 final void performServiceRestartLocked(ServiceRecord r) {
10769 if (!mRestartingServices.contains(r)) {
10770 return;
10771 }
10772 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10773 }
10774
10775 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10776 if (r.restartDelay == 0) {
10777 return false;
10778 }
10779 r.resetRestartCounter();
10780 mRestartingServices.remove(r);
10781 mHandler.removeCallbacks(r.restarter);
10782 return true;
10783 }
10784
10785 private final boolean bringUpServiceLocked(ServiceRecord r,
10786 int intentFlags, boolean whileRestarting) {
10787 //Log.i(TAG, "Bring up service:");
10788 //r.dump(" ");
10789
Dianne Hackborn36124872009-10-08 16:22:03 -070010790 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010791 sendServiceArgsLocked(r, false);
10792 return true;
10793 }
10794
10795 if (!whileRestarting && r.restartDelay > 0) {
10796 // If waiting for a restart, then do nothing.
10797 return true;
10798 }
10799
10800 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10801 + " " + r.intent);
10802
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010803 // We are now bringing the service up, so no longer in the
10804 // restarting state.
10805 mRestartingServices.remove(r);
10806
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010807 final String appName = r.processName;
10808 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10809 if (app != null && app.thread != null) {
10810 try {
10811 realStartServiceLocked(r, app);
10812 return true;
10813 } catch (RemoteException e) {
10814 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10815 }
10816
10817 // If a dead object exception was thrown -- fall through to
10818 // restart the application.
10819 }
10820
Dianne Hackborn36124872009-10-08 16:22:03 -070010821 // Not running -- get it started, and enqueue this service record
10822 // to be executed when the app comes up.
10823 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10824 "service", r.name, false) == null) {
10825 Log.w(TAG, "Unable to launch app "
10826 + r.appInfo.packageName + "/"
10827 + r.appInfo.uid + " for service "
10828 + r.intent.getIntent() + ": process is bad");
10829 bringDownServiceLocked(r, true);
10830 return false;
10831 }
10832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010833 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010834 mPendingServices.add(r);
10835 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010836
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010837 return true;
10838 }
10839
10840 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10841 //Log.i(TAG, "Bring down service:");
10842 //r.dump(" ");
10843
10844 // Does it still need to run?
10845 if (!force && r.startRequested) {
10846 return;
10847 }
10848 if (r.connections.size() > 0) {
10849 if (!force) {
10850 // XXX should probably keep a count of the number of auto-create
10851 // connections directly in the service.
10852 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10853 while (it.hasNext()) {
10854 ConnectionRecord cr = it.next();
10855 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10856 return;
10857 }
10858 }
10859 }
10860
10861 // Report to all of the connections that the service is no longer
10862 // available.
10863 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10864 while (it.hasNext()) {
10865 ConnectionRecord c = it.next();
10866 try {
10867 // todo: shouldn't be a synchronous call!
10868 c.conn.connected(r.name, null);
10869 } catch (Exception e) {
10870 Log.w(TAG, "Failure disconnecting service " + r.name +
10871 " to connection " + c.conn.asBinder() +
10872 " (in " + c.binding.client.processName + ")", e);
10873 }
10874 }
10875 }
10876
10877 // Tell the service that it has been unbound.
10878 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10879 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10880 while (it.hasNext()) {
10881 IntentBindRecord ibr = it.next();
10882 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10883 + ": hasBound=" + ibr.hasBound);
10884 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10885 try {
10886 bumpServiceExecutingLocked(r);
10887 updateOomAdjLocked(r.app);
10888 ibr.hasBound = false;
10889 r.app.thread.scheduleUnbindService(r,
10890 ibr.intent.getIntent());
10891 } catch (Exception e) {
10892 Log.w(TAG, "Exception when unbinding service "
10893 + r.shortName, e);
10894 serviceDoneExecutingLocked(r, true);
10895 }
10896 }
10897 }
10898 }
10899
10900 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10901 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010902 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010903 System.identityHashCode(r), r.shortName,
10904 (r.app != null) ? r.app.pid : -1);
10905
10906 mServices.remove(r.name);
10907 mServicesByIntent.remove(r.intent);
10908 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10909 r.totalRestartCount = 0;
10910 unscheduleServiceRestartLocked(r);
10911
10912 // Also make sure it is not on the pending list.
10913 int N = mPendingServices.size();
10914 for (int i=0; i<N; i++) {
10915 if (mPendingServices.get(i) == r) {
10916 mPendingServices.remove(i);
10917 if (DEBUG_SERVICE) Log.v(
10918 TAG, "Removed pending service: " + r.shortName);
10919 i--;
10920 N--;
10921 }
10922 }
10923
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010924 r.cancelNotification();
10925 r.isForeground = false;
10926 r.foregroundId = 0;
10927 r.foregroundNoti = null;
10928
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010929 // Clear start entries.
10930 r.deliveredStarts.clear();
10931 r.pendingStarts.clear();
10932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010933 if (r.app != null) {
10934 synchronized (r.stats.getBatteryStats()) {
10935 r.stats.stopLaunchedLocked();
10936 }
10937 r.app.services.remove(r);
10938 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010939 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010940 if (DEBUG_SERVICE) Log.v(TAG,
10941 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010942 bumpServiceExecutingLocked(r);
10943 mStoppingServices.add(r);
10944 updateOomAdjLocked(r.app);
10945 r.app.thread.scheduleStopService(r);
10946 } catch (Exception e) {
10947 Log.w(TAG, "Exception when stopping service "
10948 + r.shortName, e);
10949 serviceDoneExecutingLocked(r, true);
10950 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010951 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010952 } else {
10953 if (DEBUG_SERVICE) Log.v(
10954 TAG, "Removed service that has no process: " + r.shortName);
10955 }
10956 } else {
10957 if (DEBUG_SERVICE) Log.v(
10958 TAG, "Removed service that is not running: " + r.shortName);
10959 }
10960 }
10961
10962 ComponentName startServiceLocked(IApplicationThread caller,
10963 Intent service, String resolvedType,
10964 int callingPid, int callingUid) {
10965 synchronized(this) {
10966 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10967 + " type=" + resolvedType + " args=" + service.getExtras());
10968
10969 if (caller != null) {
10970 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10971 if (callerApp == null) {
10972 throw new SecurityException(
10973 "Unable to find app for caller " + caller
10974 + " (pid=" + Binder.getCallingPid()
10975 + ") when starting service " + service);
10976 }
10977 }
10978
10979 ServiceLookupResult res =
10980 retrieveServiceLocked(service, resolvedType,
10981 callingPid, callingUid);
10982 if (res == null) {
10983 return null;
10984 }
10985 if (res.record == null) {
10986 return new ComponentName("!", res.permission != null
10987 ? res.permission : "private to package");
10988 }
10989 ServiceRecord r = res.record;
10990 if (unscheduleServiceRestartLocked(r)) {
10991 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10992 + r.shortName);
10993 }
10994 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010995 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010996 r.lastStartId++;
10997 if (r.lastStartId < 1) {
10998 r.lastStartId = 1;
10999 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011000 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011001 r.lastActivity = SystemClock.uptimeMillis();
11002 synchronized (r.stats.getBatteryStats()) {
11003 r.stats.startRunningLocked();
11004 }
11005 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
11006 return new ComponentName("!", "Service process is bad");
11007 }
11008 return r.name;
11009 }
11010 }
11011
11012 public ComponentName startService(IApplicationThread caller, Intent service,
11013 String resolvedType) {
11014 // Refuse possible leaked file descriptors
11015 if (service != null && service.hasFileDescriptors() == true) {
11016 throw new IllegalArgumentException("File descriptors passed in Intent");
11017 }
11018
11019 synchronized(this) {
11020 final int callingPid = Binder.getCallingPid();
11021 final int callingUid = Binder.getCallingUid();
11022 final long origId = Binder.clearCallingIdentity();
11023 ComponentName res = startServiceLocked(caller, service,
11024 resolvedType, callingPid, callingUid);
11025 Binder.restoreCallingIdentity(origId);
11026 return res;
11027 }
11028 }
11029
11030 ComponentName startServiceInPackage(int uid,
11031 Intent service, String resolvedType) {
11032 synchronized(this) {
11033 final long origId = Binder.clearCallingIdentity();
11034 ComponentName res = startServiceLocked(null, service,
11035 resolvedType, -1, uid);
11036 Binder.restoreCallingIdentity(origId);
11037 return res;
11038 }
11039 }
11040
11041 public int stopService(IApplicationThread caller, Intent service,
11042 String resolvedType) {
11043 // Refuse possible leaked file descriptors
11044 if (service != null && service.hasFileDescriptors() == true) {
11045 throw new IllegalArgumentException("File descriptors passed in Intent");
11046 }
11047
11048 synchronized(this) {
11049 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11050 + " type=" + resolvedType);
11051
11052 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11053 if (caller != null && callerApp == null) {
11054 throw new SecurityException(
11055 "Unable to find app for caller " + caller
11056 + " (pid=" + Binder.getCallingPid()
11057 + ") when stopping service " + service);
11058 }
11059
11060 // If this service is active, make sure it is stopped.
11061 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11062 if (r != null) {
11063 if (r.record != null) {
11064 synchronized (r.record.stats.getBatteryStats()) {
11065 r.record.stats.stopRunningLocked();
11066 }
11067 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011068 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011069 final long origId = Binder.clearCallingIdentity();
11070 bringDownServiceLocked(r.record, false);
11071 Binder.restoreCallingIdentity(origId);
11072 return 1;
11073 }
11074 return -1;
11075 }
11076 }
11077
11078 return 0;
11079 }
11080
11081 public IBinder peekService(Intent service, String resolvedType) {
11082 // Refuse possible leaked file descriptors
11083 if (service != null && service.hasFileDescriptors() == true) {
11084 throw new IllegalArgumentException("File descriptors passed in Intent");
11085 }
11086
11087 IBinder ret = null;
11088
11089 synchronized(this) {
11090 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11091
11092 if (r != null) {
11093 // r.record is null if findServiceLocked() failed the caller permission check
11094 if (r.record == null) {
11095 throw new SecurityException(
11096 "Permission Denial: Accessing service " + r.record.name
11097 + " from pid=" + Binder.getCallingPid()
11098 + ", uid=" + Binder.getCallingUid()
11099 + " requires " + r.permission);
11100 }
11101 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11102 if (ib != null) {
11103 ret = ib.binder;
11104 }
11105 }
11106 }
11107
11108 return ret;
11109 }
11110
11111 public boolean stopServiceToken(ComponentName className, IBinder token,
11112 int startId) {
11113 synchronized(this) {
11114 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11115 + " " + token + " startId=" + startId);
11116 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011117 if (r != null) {
11118 if (startId >= 0) {
11119 // Asked to only stop if done with all work. Note that
11120 // to avoid leaks, we will take this as dropping all
11121 // start items up to and including this one.
11122 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11123 if (si != null) {
11124 while (r.deliveredStarts.size() > 0) {
11125 if (r.deliveredStarts.remove(0) == si) {
11126 break;
11127 }
11128 }
11129 }
11130
11131 if (r.lastStartId != startId) {
11132 return false;
11133 }
11134
11135 if (r.deliveredStarts.size() > 0) {
11136 Log.w(TAG, "stopServiceToken startId " + startId
11137 + " is last, but have " + r.deliveredStarts.size()
11138 + " remaining args");
11139 }
11140 }
11141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011142 synchronized (r.stats.getBatteryStats()) {
11143 r.stats.stopRunningLocked();
11144 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011145 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011146 }
11147 final long origId = Binder.clearCallingIdentity();
11148 bringDownServiceLocked(r, false);
11149 Binder.restoreCallingIdentity(origId);
11150 return true;
11151 }
11152 }
11153 return false;
11154 }
11155
11156 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011157 int id, Notification notification, boolean removeNotification) {
11158 final long origId = Binder.clearCallingIdentity();
11159 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011160 synchronized(this) {
11161 ServiceRecord r = findServiceLocked(className, token);
11162 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011163 if (id != 0) {
11164 if (notification == null) {
11165 throw new IllegalArgumentException("null notification");
11166 }
11167 if (r.foregroundId != id) {
11168 r.cancelNotification();
11169 r.foregroundId = id;
11170 }
11171 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11172 r.foregroundNoti = notification;
11173 r.isForeground = true;
11174 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011175 if (r.app != null) {
11176 updateServiceForegroundLocked(r.app, true);
11177 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011178 } else {
11179 if (r.isForeground) {
11180 r.isForeground = false;
11181 if (r.app != null) {
11182 updateServiceForegroundLocked(r.app, true);
11183 }
11184 }
11185 if (removeNotification) {
11186 r.cancelNotification();
11187 r.foregroundId = 0;
11188 r.foregroundNoti = null;
11189 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011190 }
11191 }
11192 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011193 } finally {
11194 Binder.restoreCallingIdentity(origId);
11195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011196 }
11197
11198 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11199 boolean anyForeground = false;
11200 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11201 if (sr.isForeground) {
11202 anyForeground = true;
11203 break;
11204 }
11205 }
11206 if (anyForeground != proc.foregroundServices) {
11207 proc.foregroundServices = anyForeground;
11208 if (oomAdj) {
11209 updateOomAdjLocked();
11210 }
11211 }
11212 }
11213
11214 public int bindService(IApplicationThread caller, IBinder token,
11215 Intent service, String resolvedType,
11216 IServiceConnection connection, int flags) {
11217 // Refuse possible leaked file descriptors
11218 if (service != null && service.hasFileDescriptors() == true) {
11219 throw new IllegalArgumentException("File descriptors passed in Intent");
11220 }
11221
11222 synchronized(this) {
11223 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11224 + " type=" + resolvedType + " conn=" + connection.asBinder()
11225 + " flags=0x" + Integer.toHexString(flags));
11226 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11227 if (callerApp == null) {
11228 throw new SecurityException(
11229 "Unable to find app for caller " + caller
11230 + " (pid=" + Binder.getCallingPid()
11231 + ") when binding service " + service);
11232 }
11233
11234 HistoryRecord activity = null;
11235 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011236 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011237 if (aindex < 0) {
11238 Log.w(TAG, "Binding with unknown activity: " + token);
11239 return 0;
11240 }
11241 activity = (HistoryRecord)mHistory.get(aindex);
11242 }
11243
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011244 int clientLabel = 0;
11245 PendingIntent clientIntent = null;
11246
11247 if (callerApp.info.uid == Process.SYSTEM_UID) {
11248 // Hacky kind of thing -- allow system stuff to tell us
11249 // what they are, so we can report this elsewhere for
11250 // others to know why certain services are running.
11251 try {
11252 clientIntent = (PendingIntent)service.getParcelableExtra(
11253 Intent.EXTRA_CLIENT_INTENT);
11254 } catch (RuntimeException e) {
11255 }
11256 if (clientIntent != null) {
11257 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11258 if (clientLabel != 0) {
11259 // There are no useful extras in the intent, trash them.
11260 // System code calling with this stuff just needs to know
11261 // this will happen.
11262 service = service.cloneFilter();
11263 }
11264 }
11265 }
11266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011267 ServiceLookupResult res =
11268 retrieveServiceLocked(service, resolvedType,
11269 Binder.getCallingPid(), Binder.getCallingUid());
11270 if (res == null) {
11271 return 0;
11272 }
11273 if (res.record == null) {
11274 return -1;
11275 }
11276 ServiceRecord s = res.record;
11277
11278 final long origId = Binder.clearCallingIdentity();
11279
11280 if (unscheduleServiceRestartLocked(s)) {
11281 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11282 + s.shortName);
11283 }
11284
11285 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11286 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011287 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011288
11289 IBinder binder = connection.asBinder();
11290 s.connections.put(binder, c);
11291 b.connections.add(c);
11292 if (activity != null) {
11293 if (activity.connections == null) {
11294 activity.connections = new HashSet<ConnectionRecord>();
11295 }
11296 activity.connections.add(c);
11297 }
11298 b.client.connections.add(c);
11299 mServiceConnections.put(binder, c);
11300
11301 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11302 s.lastActivity = SystemClock.uptimeMillis();
11303 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11304 return 0;
11305 }
11306 }
11307
11308 if (s.app != null) {
11309 // This could have made the service more important.
11310 updateOomAdjLocked(s.app);
11311 }
11312
11313 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11314 + ": received=" + b.intent.received
11315 + " apps=" + b.intent.apps.size()
11316 + " doRebind=" + b.intent.doRebind);
11317
11318 if (s.app != null && b.intent.received) {
11319 // Service is already running, so we can immediately
11320 // publish the connection.
11321 try {
11322 c.conn.connected(s.name, b.intent.binder);
11323 } catch (Exception e) {
11324 Log.w(TAG, "Failure sending service " + s.shortName
11325 + " to connection " + c.conn.asBinder()
11326 + " (in " + c.binding.client.processName + ")", e);
11327 }
11328
11329 // If this is the first app connected back to this binding,
11330 // and the service had previously asked to be told when
11331 // rebound, then do so.
11332 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11333 requestServiceBindingLocked(s, b.intent, true);
11334 }
11335 } else if (!b.intent.requested) {
11336 requestServiceBindingLocked(s, b.intent, false);
11337 }
11338
11339 Binder.restoreCallingIdentity(origId);
11340 }
11341
11342 return 1;
11343 }
11344
11345 private void removeConnectionLocked(
11346 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11347 IBinder binder = c.conn.asBinder();
11348 AppBindRecord b = c.binding;
11349 ServiceRecord s = b.service;
11350 s.connections.remove(binder);
11351 b.connections.remove(c);
11352 if (c.activity != null && c.activity != skipAct) {
11353 if (c.activity.connections != null) {
11354 c.activity.connections.remove(c);
11355 }
11356 }
11357 if (b.client != skipApp) {
11358 b.client.connections.remove(c);
11359 }
11360 mServiceConnections.remove(binder);
11361
11362 if (b.connections.size() == 0) {
11363 b.intent.apps.remove(b.client);
11364 }
11365
11366 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11367 + ": shouldUnbind=" + b.intent.hasBound);
11368 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11369 && b.intent.hasBound) {
11370 try {
11371 bumpServiceExecutingLocked(s);
11372 updateOomAdjLocked(s.app);
11373 b.intent.hasBound = false;
11374 // Assume the client doesn't want to know about a rebind;
11375 // we will deal with that later if it asks for one.
11376 b.intent.doRebind = false;
11377 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11378 } catch (Exception e) {
11379 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11380 serviceDoneExecutingLocked(s, true);
11381 }
11382 }
11383
11384 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11385 bringDownServiceLocked(s, false);
11386 }
11387 }
11388
11389 public boolean unbindService(IServiceConnection connection) {
11390 synchronized (this) {
11391 IBinder binder = connection.asBinder();
11392 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11393 ConnectionRecord r = mServiceConnections.get(binder);
11394 if (r == null) {
11395 Log.w(TAG, "Unbind failed: could not find connection for "
11396 + connection.asBinder());
11397 return false;
11398 }
11399
11400 final long origId = Binder.clearCallingIdentity();
11401
11402 removeConnectionLocked(r, null, null);
11403
11404 if (r.binding.service.app != null) {
11405 // This could have made the service less important.
11406 updateOomAdjLocked(r.binding.service.app);
11407 }
11408
11409 Binder.restoreCallingIdentity(origId);
11410 }
11411
11412 return true;
11413 }
11414
11415 public void publishService(IBinder token, Intent intent, IBinder service) {
11416 // Refuse possible leaked file descriptors
11417 if (intent != null && intent.hasFileDescriptors() == true) {
11418 throw new IllegalArgumentException("File descriptors passed in Intent");
11419 }
11420
11421 synchronized(this) {
11422 if (!(token instanceof ServiceRecord)) {
11423 throw new IllegalArgumentException("Invalid service token");
11424 }
11425 ServiceRecord r = (ServiceRecord)token;
11426
11427 final long origId = Binder.clearCallingIdentity();
11428
11429 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11430 + " " + intent + ": " + service);
11431 if (r != null) {
11432 Intent.FilterComparison filter
11433 = new Intent.FilterComparison(intent);
11434 IntentBindRecord b = r.bindings.get(filter);
11435 if (b != null && !b.received) {
11436 b.binder = service;
11437 b.requested = true;
11438 b.received = true;
11439 if (r.connections.size() > 0) {
11440 Iterator<ConnectionRecord> it
11441 = r.connections.values().iterator();
11442 while (it.hasNext()) {
11443 ConnectionRecord c = it.next();
11444 if (!filter.equals(c.binding.intent.intent)) {
11445 if (DEBUG_SERVICE) Log.v(
11446 TAG, "Not publishing to: " + c);
11447 if (DEBUG_SERVICE) Log.v(
11448 TAG, "Bound intent: " + c.binding.intent.intent);
11449 if (DEBUG_SERVICE) Log.v(
11450 TAG, "Published intent: " + intent);
11451 continue;
11452 }
11453 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11454 try {
11455 c.conn.connected(r.name, service);
11456 } catch (Exception e) {
11457 Log.w(TAG, "Failure sending service " + r.name +
11458 " to connection " + c.conn.asBinder() +
11459 " (in " + c.binding.client.processName + ")", e);
11460 }
11461 }
11462 }
11463 }
11464
11465 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11466
11467 Binder.restoreCallingIdentity(origId);
11468 }
11469 }
11470 }
11471
11472 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11473 // Refuse possible leaked file descriptors
11474 if (intent != null && intent.hasFileDescriptors() == true) {
11475 throw new IllegalArgumentException("File descriptors passed in Intent");
11476 }
11477
11478 synchronized(this) {
11479 if (!(token instanceof ServiceRecord)) {
11480 throw new IllegalArgumentException("Invalid service token");
11481 }
11482 ServiceRecord r = (ServiceRecord)token;
11483
11484 final long origId = Binder.clearCallingIdentity();
11485
11486 if (r != null) {
11487 Intent.FilterComparison filter
11488 = new Intent.FilterComparison(intent);
11489 IntentBindRecord b = r.bindings.get(filter);
11490 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11491 + " at " + b + ": apps="
11492 + (b != null ? b.apps.size() : 0));
11493 if (b != null) {
11494 if (b.apps.size() > 0) {
11495 // Applications have already bound since the last
11496 // unbind, so just rebind right here.
11497 requestServiceBindingLocked(r, b, true);
11498 } else {
11499 // Note to tell the service the next time there is
11500 // a new client.
11501 b.doRebind = true;
11502 }
11503 }
11504
11505 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11506
11507 Binder.restoreCallingIdentity(origId);
11508 }
11509 }
11510 }
11511
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011512 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011513 synchronized(this) {
11514 if (!(token instanceof ServiceRecord)) {
11515 throw new IllegalArgumentException("Invalid service token");
11516 }
11517 ServiceRecord r = (ServiceRecord)token;
11518 boolean inStopping = mStoppingServices.contains(token);
11519 if (r != null) {
11520 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11521 + ": nesting=" + r.executeNesting
11522 + ", inStopping=" + inStopping);
11523 if (r != token) {
11524 Log.w(TAG, "Done executing service " + r.name
11525 + " with incorrect token: given " + token
11526 + ", expected " + r);
11527 return;
11528 }
11529
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011530 if (type == 1) {
11531 // This is a call from a service start... take care of
11532 // book-keeping.
11533 r.callStart = true;
11534 switch (res) {
11535 case Service.START_STICKY_COMPATIBILITY:
11536 case Service.START_STICKY: {
11537 // We are done with the associated start arguments.
11538 r.findDeliveredStart(startId, true);
11539 // Don't stop if killed.
11540 r.stopIfKilled = false;
11541 break;
11542 }
11543 case Service.START_NOT_STICKY: {
11544 // We are done with the associated start arguments.
11545 r.findDeliveredStart(startId, true);
11546 if (r.lastStartId == startId) {
11547 // There is no more work, and this service
11548 // doesn't want to hang around if killed.
11549 r.stopIfKilled = true;
11550 }
11551 break;
11552 }
11553 case Service.START_REDELIVER_INTENT: {
11554 // We'll keep this item until they explicitly
11555 // call stop for it, but keep track of the fact
11556 // that it was delivered.
11557 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11558 if (si != null) {
11559 si.deliveryCount = 0;
11560 si.doneExecutingCount++;
11561 // Don't stop if killed.
11562 r.stopIfKilled = true;
11563 }
11564 break;
11565 }
11566 default:
11567 throw new IllegalArgumentException(
11568 "Unknown service start result: " + res);
11569 }
11570 if (res == Service.START_STICKY_COMPATIBILITY) {
11571 r.callStart = false;
11572 }
11573 }
11574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011575 final long origId = Binder.clearCallingIdentity();
11576 serviceDoneExecutingLocked(r, inStopping);
11577 Binder.restoreCallingIdentity(origId);
11578 } else {
11579 Log.w(TAG, "Done executing unknown service " + r.name
11580 + " with token " + token);
11581 }
11582 }
11583 }
11584
11585 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11586 r.executeNesting--;
11587 if (r.executeNesting <= 0 && r.app != null) {
11588 r.app.executingServices.remove(r);
11589 if (r.app.executingServices.size() == 0) {
11590 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11591 }
11592 if (inStopping) {
11593 mStoppingServices.remove(r);
11594 }
11595 updateOomAdjLocked(r.app);
11596 }
11597 }
11598
11599 void serviceTimeout(ProcessRecord proc) {
11600 synchronized(this) {
11601 if (proc.executingServices.size() == 0 || proc.thread == null) {
11602 return;
11603 }
11604 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11605 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11606 ServiceRecord timeout = null;
11607 long nextTime = 0;
11608 while (it.hasNext()) {
11609 ServiceRecord sr = it.next();
11610 if (sr.executingStart < maxTime) {
11611 timeout = sr;
11612 break;
11613 }
11614 if (sr.executingStart > nextTime) {
11615 nextTime = sr.executingStart;
11616 }
11617 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011618 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011619 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnor42471dd2010-01-07 17:25:22 -080011620 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011621 } else {
11622 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11623 msg.obj = proc;
11624 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11625 }
11626 }
11627 }
11628
11629 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011630 // BACKUP AND RESTORE
11631 // =========================================================
11632
11633 // Cause the target app to be launched if necessary and its backup agent
11634 // instantiated. The backup agent will invoke backupAgentCreated() on the
11635 // activity manager to announce its creation.
11636 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11637 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11638 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11639
11640 synchronized(this) {
11641 // !!! TODO: currently no check here that we're already bound
11642 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11643 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11644 synchronized (stats) {
11645 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11646 }
11647
11648 BackupRecord r = new BackupRecord(ss, app, backupMode);
11649 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11650 // startProcessLocked() returns existing proc's record if it's already running
11651 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011652 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011653 if (proc == null) {
11654 Log.e(TAG, "Unable to start backup agent process " + r);
11655 return false;
11656 }
11657
11658 r.app = proc;
11659 mBackupTarget = r;
11660 mBackupAppName = app.packageName;
11661
Christopher Tate6fa95972009-06-05 18:43:55 -070011662 // Try not to kill the process during backup
11663 updateOomAdjLocked(proc);
11664
Christopher Tate181fafa2009-05-14 11:12:14 -070011665 // If the process is already attached, schedule the creation of the backup agent now.
11666 // If it is not yet live, this will be done when it attaches to the framework.
11667 if (proc.thread != null) {
11668 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11669 try {
11670 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11671 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011672 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011673 }
11674 } else {
11675 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11676 }
11677 // Invariants: at this point, the target app process exists and the application
11678 // is either already running or in the process of coming up. mBackupTarget and
11679 // mBackupAppName describe the app, so that when it binds back to the AM we
11680 // know that it's scheduled for a backup-agent operation.
11681 }
11682
11683 return true;
11684 }
11685
11686 // A backup agent has just come up
11687 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11688 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11689 + " = " + agent);
11690
11691 synchronized(this) {
11692 if (!agentPackageName.equals(mBackupAppName)) {
11693 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11694 return;
11695 }
11696
Christopher Tate043dadc2009-06-02 16:11:00 -070011697 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011698 try {
11699 IBackupManager bm = IBackupManager.Stub.asInterface(
11700 ServiceManager.getService(Context.BACKUP_SERVICE));
11701 bm.agentConnected(agentPackageName, agent);
11702 } catch (RemoteException e) {
11703 // can't happen; the backup manager service is local
11704 } catch (Exception e) {
11705 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11706 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011707 } finally {
11708 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011709 }
11710 }
11711 }
11712
11713 // done with this agent
11714 public void unbindBackupAgent(ApplicationInfo appInfo) {
11715 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011716 if (appInfo == null) {
11717 Log.w(TAG, "unbind backup agent for null app");
11718 return;
11719 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011720
11721 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011722 if (mBackupAppName == null) {
11723 Log.w(TAG, "Unbinding backup agent with no active backup");
11724 return;
11725 }
11726
Christopher Tate181fafa2009-05-14 11:12:14 -070011727 if (!mBackupAppName.equals(appInfo.packageName)) {
11728 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11729 return;
11730 }
11731
Christopher Tate6fa95972009-06-05 18:43:55 -070011732 ProcessRecord proc = mBackupTarget.app;
11733 mBackupTarget = null;
11734 mBackupAppName = null;
11735
11736 // Not backing this app up any more; reset its OOM adjustment
11737 updateOomAdjLocked(proc);
11738
Christopher Tatec7b31e32009-06-10 15:49:30 -070011739 // If the app crashed during backup, 'thread' will be null here
11740 if (proc.thread != null) {
11741 try {
11742 proc.thread.scheduleDestroyBackupAgent(appInfo);
11743 } catch (Exception e) {
11744 Log.e(TAG, "Exception when unbinding backup agent:");
11745 e.printStackTrace();
11746 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011747 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011748 }
11749 }
11750 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011751 // BROADCASTS
11752 // =========================================================
11753
11754 private final List getStickies(String action, IntentFilter filter,
11755 List cur) {
11756 final ContentResolver resolver = mContext.getContentResolver();
11757 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11758 if (list == null) {
11759 return cur;
11760 }
11761 int N = list.size();
11762 for (int i=0; i<N; i++) {
11763 Intent intent = list.get(i);
11764 if (filter.match(resolver, intent, true, TAG) >= 0) {
11765 if (cur == null) {
11766 cur = new ArrayList<Intent>();
11767 }
11768 cur.add(intent);
11769 }
11770 }
11771 return cur;
11772 }
11773
11774 private final void scheduleBroadcastsLocked() {
11775 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11776 + mBroadcastsScheduled);
11777
11778 if (mBroadcastsScheduled) {
11779 return;
11780 }
11781 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11782 mBroadcastsScheduled = true;
11783 }
11784
11785 public Intent registerReceiver(IApplicationThread caller,
11786 IIntentReceiver receiver, IntentFilter filter, String permission) {
11787 synchronized(this) {
11788 ProcessRecord callerApp = null;
11789 if (caller != null) {
11790 callerApp = getRecordForAppLocked(caller);
11791 if (callerApp == null) {
11792 throw new SecurityException(
11793 "Unable to find app for caller " + caller
11794 + " (pid=" + Binder.getCallingPid()
11795 + ") when registering receiver " + receiver);
11796 }
11797 }
11798
11799 List allSticky = null;
11800
11801 // Look for any matching sticky broadcasts...
11802 Iterator actions = filter.actionsIterator();
11803 if (actions != null) {
11804 while (actions.hasNext()) {
11805 String action = (String)actions.next();
11806 allSticky = getStickies(action, filter, allSticky);
11807 }
11808 } else {
11809 allSticky = getStickies(null, filter, allSticky);
11810 }
11811
11812 // The first sticky in the list is returned directly back to
11813 // the client.
11814 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11815
11816 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11817 + ": " + sticky);
11818
11819 if (receiver == null) {
11820 return sticky;
11821 }
11822
11823 ReceiverList rl
11824 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11825 if (rl == null) {
11826 rl = new ReceiverList(this, callerApp,
11827 Binder.getCallingPid(),
11828 Binder.getCallingUid(), receiver);
11829 if (rl.app != null) {
11830 rl.app.receivers.add(rl);
11831 } else {
11832 try {
11833 receiver.asBinder().linkToDeath(rl, 0);
11834 } catch (RemoteException e) {
11835 return sticky;
11836 }
11837 rl.linkedToDeath = true;
11838 }
11839 mRegisteredReceivers.put(receiver.asBinder(), rl);
11840 }
11841 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11842 rl.add(bf);
11843 if (!bf.debugCheck()) {
11844 Log.w(TAG, "==> For Dynamic broadast");
11845 }
11846 mReceiverResolver.addFilter(bf);
11847
11848 // Enqueue broadcasts for all existing stickies that match
11849 // this filter.
11850 if (allSticky != null) {
11851 ArrayList receivers = new ArrayList();
11852 receivers.add(bf);
11853
11854 int N = allSticky.size();
11855 for (int i=0; i<N; i++) {
11856 Intent intent = (Intent)allSticky.get(i);
11857 BroadcastRecord r = new BroadcastRecord(intent, null,
11858 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011859 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011860 if (mParallelBroadcasts.size() == 0) {
11861 scheduleBroadcastsLocked();
11862 }
11863 mParallelBroadcasts.add(r);
11864 }
11865 }
11866
11867 return sticky;
11868 }
11869 }
11870
11871 public void unregisterReceiver(IIntentReceiver receiver) {
11872 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11873
11874 boolean doNext = false;
11875
11876 synchronized(this) {
11877 ReceiverList rl
11878 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11879 if (rl != null) {
11880 if (rl.curBroadcast != null) {
11881 BroadcastRecord r = rl.curBroadcast;
11882 doNext = finishReceiverLocked(
11883 receiver.asBinder(), r.resultCode, r.resultData,
11884 r.resultExtras, r.resultAbort, true);
11885 }
11886
11887 if (rl.app != null) {
11888 rl.app.receivers.remove(rl);
11889 }
11890 removeReceiverLocked(rl);
11891 if (rl.linkedToDeath) {
11892 rl.linkedToDeath = false;
11893 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11894 }
11895 }
11896 }
11897
11898 if (!doNext) {
11899 return;
11900 }
11901
11902 final long origId = Binder.clearCallingIdentity();
11903 processNextBroadcast(false);
11904 trimApplications();
11905 Binder.restoreCallingIdentity(origId);
11906 }
11907
11908 void removeReceiverLocked(ReceiverList rl) {
11909 mRegisteredReceivers.remove(rl.receiver.asBinder());
11910 int N = rl.size();
11911 for (int i=0; i<N; i++) {
11912 mReceiverResolver.removeFilter(rl.get(i));
11913 }
11914 }
11915
11916 private final int broadcastIntentLocked(ProcessRecord callerApp,
11917 String callerPackage, Intent intent, String resolvedType,
11918 IIntentReceiver resultTo, int resultCode, String resultData,
11919 Bundle map, String requiredPermission,
11920 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11921 intent = new Intent(intent);
11922
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011923 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011924 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11925 + " ordered=" + ordered);
11926 if ((resultTo != null) && !ordered) {
11927 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11928 }
11929
11930 // Handle special intents: if this broadcast is from the package
11931 // manager about a package being removed, we need to remove all of
11932 // its activities from the history stack.
11933 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11934 intent.getAction());
11935 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11936 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080011937 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011938 || uidRemoved) {
11939 if (checkComponentPermission(
11940 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11941 callingPid, callingUid, -1)
11942 == PackageManager.PERMISSION_GRANTED) {
11943 if (uidRemoved) {
11944 final Bundle intentExtras = intent.getExtras();
11945 final int uid = intentExtras != null
11946 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11947 if (uid >= 0) {
11948 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11949 synchronized (bs) {
11950 bs.removeUidStatsLocked(uid);
11951 }
11952 }
11953 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011954 // If resources are unvailble just force stop all
11955 // those packages and flush the attribute cache as well.
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080011956 if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011957 String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
11958 if (list != null && (list.length > 0)) {
11959 for (String pkg : list) {
11960 forceStopPackageLocked(pkg, -1, false, true);
11961 }
11962 }
11963 } else {
11964 Uri data = intent.getData();
11965 String ssp;
11966 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11967 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11968 forceStopPackageLocked(ssp,
11969 intent.getIntExtra(Intent.EXTRA_UID, -1), false, true);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011971 }
11972 }
11973 }
11974 } else {
11975 String msg = "Permission Denial: " + intent.getAction()
11976 + " broadcast from " + callerPackage + " (pid=" + callingPid
11977 + ", uid=" + callingUid + ")"
11978 + " requires "
11979 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11980 Log.w(TAG, msg);
11981 throw new SecurityException(msg);
11982 }
11983 }
11984
11985 /*
11986 * If this is the time zone changed action, queue up a message that will reset the timezone
11987 * of all currently running processes. This message will get queued up before the broadcast
11988 * happens.
11989 */
11990 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11991 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11992 }
11993
Dianne Hackborn854060af2009-07-09 18:14:31 -070011994 /*
11995 * Prevent non-system code (defined here to be non-persistent
11996 * processes) from sending protected broadcasts.
11997 */
11998 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11999 || callingUid == Process.SHELL_UID || callingUid == 0) {
12000 // Always okay.
12001 } else if (callerApp == null || !callerApp.persistent) {
12002 try {
12003 if (ActivityThread.getPackageManager().isProtectedBroadcast(
12004 intent.getAction())) {
12005 String msg = "Permission Denial: not allowed to send broadcast "
12006 + intent.getAction() + " from pid="
12007 + callingPid + ", uid=" + callingUid;
12008 Log.w(TAG, msg);
12009 throw new SecurityException(msg);
12010 }
12011 } catch (RemoteException e) {
12012 Log.w(TAG, "Remote exception", e);
12013 return BROADCAST_SUCCESS;
12014 }
12015 }
12016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012017 // Add to the sticky list if requested.
12018 if (sticky) {
12019 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
12020 callingPid, callingUid)
12021 != PackageManager.PERMISSION_GRANTED) {
12022 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
12023 + callingPid + ", uid=" + callingUid
12024 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12025 Log.w(TAG, msg);
12026 throw new SecurityException(msg);
12027 }
12028 if (requiredPermission != null) {
12029 Log.w(TAG, "Can't broadcast sticky intent " + intent
12030 + " and enforce permission " + requiredPermission);
12031 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
12032 }
12033 if (intent.getComponent() != null) {
12034 throw new SecurityException(
12035 "Sticky broadcasts can't target a specific component");
12036 }
12037 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12038 if (list == null) {
12039 list = new ArrayList<Intent>();
12040 mStickyBroadcasts.put(intent.getAction(), list);
12041 }
12042 int N = list.size();
12043 int i;
12044 for (i=0; i<N; i++) {
12045 if (intent.filterEquals(list.get(i))) {
12046 // This sticky already exists, replace it.
12047 list.set(i, new Intent(intent));
12048 break;
12049 }
12050 }
12051 if (i >= N) {
12052 list.add(new Intent(intent));
12053 }
12054 }
12055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012056 // Figure out who all will receive this broadcast.
12057 List receivers = null;
12058 List<BroadcastFilter> registeredReceivers = null;
12059 try {
12060 if (intent.getComponent() != null) {
12061 // Broadcast is going to one specific receiver class...
12062 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012063 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012064 if (ai != null) {
12065 receivers = new ArrayList();
12066 ResolveInfo ri = new ResolveInfo();
12067 ri.activityInfo = ai;
12068 receivers.add(ri);
12069 }
12070 } else {
12071 // Need to resolve the intent to interested receivers...
12072 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12073 == 0) {
12074 receivers =
12075 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012076 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012077 }
Mihai Preda074edef2009-05-18 17:13:31 +020012078 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012079 }
12080 } catch (RemoteException ex) {
12081 // pm is in same process, this will never happen.
12082 }
12083
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012084 final boolean replacePending =
12085 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12086
12087 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12088 + " replacePending=" + replacePending);
12089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012090 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12091 if (!ordered && NR > 0) {
12092 // If we are not serializing this broadcast, then send the
12093 // registered receivers separately so they don't wait for the
12094 // components to be launched.
12095 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12096 callerPackage, callingPid, callingUid, requiredPermission,
12097 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012098 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012099 if (DEBUG_BROADCAST) Log.v(
12100 TAG, "Enqueueing parallel broadcast " + r
12101 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012102 boolean replaced = false;
12103 if (replacePending) {
12104 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12105 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12106 if (DEBUG_BROADCAST) Log.v(TAG,
12107 "***** DROPPING PARALLEL: " + intent);
12108 mParallelBroadcasts.set(i, r);
12109 replaced = true;
12110 break;
12111 }
12112 }
12113 }
12114 if (!replaced) {
12115 mParallelBroadcasts.add(r);
12116 scheduleBroadcastsLocked();
12117 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012118 registeredReceivers = null;
12119 NR = 0;
12120 }
12121
12122 // Merge into one list.
12123 int ir = 0;
12124 if (receivers != null) {
12125 // A special case for PACKAGE_ADDED: do not allow the package
12126 // being added to see this broadcast. This prevents them from
12127 // using this as a back door to get run as soon as they are
12128 // installed. Maybe in the future we want to have a special install
12129 // broadcast or such for apps, but we'd like to deliberately make
12130 // this decision.
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012131 String skipPackages[] = null;
12132 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
12133 || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
12134 || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12135 Uri data = intent.getData();
12136 if (data != null) {
12137 String pkgName = data.getSchemeSpecificPart();
12138 if (pkgName != null) {
12139 skipPackages = new String[] { pkgName };
12140 }
12141 }
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080012142 } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012143 skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
The Android Open Source Project10592532009-03-18 17:39:46 -070012144 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012145 if (skipPackages != null && (skipPackages.length > 0)) {
12146 for (String skipPackage : skipPackages) {
12147 if (skipPackage != null) {
12148 int NT = receivers.size();
12149 for (int it=0; it<NT; it++) {
12150 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12151 if (curt.activityInfo.packageName.equals(skipPackage)) {
12152 receivers.remove(it);
12153 it--;
12154 NT--;
12155 }
12156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012157 }
12158 }
12159 }
12160
12161 int NT = receivers != null ? receivers.size() : 0;
12162 int it = 0;
12163 ResolveInfo curt = null;
12164 BroadcastFilter curr = null;
12165 while (it < NT && ir < NR) {
12166 if (curt == null) {
12167 curt = (ResolveInfo)receivers.get(it);
12168 }
12169 if (curr == null) {
12170 curr = registeredReceivers.get(ir);
12171 }
12172 if (curr.getPriority() >= curt.priority) {
12173 // Insert this broadcast record into the final list.
12174 receivers.add(it, curr);
12175 ir++;
12176 curr = null;
12177 it++;
12178 NT++;
12179 } else {
12180 // Skip to the next ResolveInfo in the final list.
12181 it++;
12182 curt = null;
12183 }
12184 }
12185 }
12186 while (ir < NR) {
12187 if (receivers == null) {
12188 receivers = new ArrayList();
12189 }
12190 receivers.add(registeredReceivers.get(ir));
12191 ir++;
12192 }
12193
12194 if ((receivers != null && receivers.size() > 0)
12195 || resultTo != null) {
12196 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12197 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012198 receivers, resultTo, resultCode, resultData, map, ordered,
12199 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012200 if (DEBUG_BROADCAST) Log.v(
12201 TAG, "Enqueueing ordered broadcast " + r
12202 + ": prev had " + mOrderedBroadcasts.size());
12203 if (DEBUG_BROADCAST) {
12204 int seq = r.intent.getIntExtra("seq", -1);
12205 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12206 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012207 boolean replaced = false;
12208 if (replacePending) {
12209 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12210 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12211 if (DEBUG_BROADCAST) Log.v(TAG,
12212 "***** DROPPING ORDERED: " + intent);
12213 mOrderedBroadcasts.set(i, r);
12214 replaced = true;
12215 break;
12216 }
12217 }
12218 }
12219 if (!replaced) {
12220 mOrderedBroadcasts.add(r);
12221 scheduleBroadcastsLocked();
12222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012223 }
12224
12225 return BROADCAST_SUCCESS;
12226 }
12227
12228 public final int broadcastIntent(IApplicationThread caller,
12229 Intent intent, String resolvedType, IIntentReceiver resultTo,
12230 int resultCode, String resultData, Bundle map,
12231 String requiredPermission, boolean serialized, boolean sticky) {
12232 // Refuse possible leaked file descriptors
12233 if (intent != null && intent.hasFileDescriptors() == true) {
12234 throw new IllegalArgumentException("File descriptors passed in Intent");
12235 }
12236
12237 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012238 int flags = intent.getFlags();
12239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012240 if (!mSystemReady) {
12241 // if the caller really truly claims to know what they're doing, go
12242 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012243 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12244 intent = new Intent(intent);
12245 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12246 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12247 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12248 + " before boot completion");
12249 throw new IllegalStateException("Cannot broadcast before boot completed");
12250 }
12251 }
12252
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012253 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12254 throw new IllegalArgumentException(
12255 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12256 }
12257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012258 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12259 final int callingPid = Binder.getCallingPid();
12260 final int callingUid = Binder.getCallingUid();
12261 final long origId = Binder.clearCallingIdentity();
12262 int res = broadcastIntentLocked(callerApp,
12263 callerApp != null ? callerApp.info.packageName : null,
12264 intent, resolvedType, resultTo,
12265 resultCode, resultData, map, requiredPermission, serialized,
12266 sticky, callingPid, callingUid);
12267 Binder.restoreCallingIdentity(origId);
12268 return res;
12269 }
12270 }
12271
12272 int broadcastIntentInPackage(String packageName, int uid,
12273 Intent intent, String resolvedType, IIntentReceiver resultTo,
12274 int resultCode, String resultData, Bundle map,
12275 String requiredPermission, boolean serialized, boolean sticky) {
12276 synchronized(this) {
12277 final long origId = Binder.clearCallingIdentity();
12278 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12279 resultTo, resultCode, resultData, map, requiredPermission,
12280 serialized, sticky, -1, uid);
12281 Binder.restoreCallingIdentity(origId);
12282 return res;
12283 }
12284 }
12285
12286 public final void unbroadcastIntent(IApplicationThread caller,
12287 Intent intent) {
12288 // Refuse possible leaked file descriptors
12289 if (intent != null && intent.hasFileDescriptors() == true) {
12290 throw new IllegalArgumentException("File descriptors passed in Intent");
12291 }
12292
12293 synchronized(this) {
12294 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12295 != PackageManager.PERMISSION_GRANTED) {
12296 String msg = "Permission Denial: unbroadcastIntent() from pid="
12297 + Binder.getCallingPid()
12298 + ", uid=" + Binder.getCallingUid()
12299 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12300 Log.w(TAG, msg);
12301 throw new SecurityException(msg);
12302 }
12303 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12304 if (list != null) {
12305 int N = list.size();
12306 int i;
12307 for (i=0; i<N; i++) {
12308 if (intent.filterEquals(list.get(i))) {
12309 list.remove(i);
12310 break;
12311 }
12312 }
12313 }
12314 }
12315 }
12316
12317 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12318 String resultData, Bundle resultExtras, boolean resultAbort,
12319 boolean explicit) {
12320 if (mOrderedBroadcasts.size() == 0) {
12321 if (explicit) {
12322 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12323 }
12324 return false;
12325 }
12326 BroadcastRecord r = mOrderedBroadcasts.get(0);
12327 if (r.receiver == null) {
12328 if (explicit) {
12329 Log.w(TAG, "finishReceiver called but none active");
12330 }
12331 return false;
12332 }
12333 if (r.receiver != receiver) {
12334 Log.w(TAG, "finishReceiver called but active receiver is different");
12335 return false;
12336 }
12337 int state = r.state;
12338 r.state = r.IDLE;
12339 if (state == r.IDLE) {
12340 if (explicit) {
12341 Log.w(TAG, "finishReceiver called but state is IDLE");
12342 }
12343 }
12344 r.receiver = null;
12345 r.intent.setComponent(null);
12346 if (r.curApp != null) {
12347 r.curApp.curReceiver = null;
12348 }
12349 if (r.curFilter != null) {
12350 r.curFilter.receiverList.curBroadcast = null;
12351 }
12352 r.curFilter = null;
12353 r.curApp = null;
12354 r.curComponent = null;
12355 r.curReceiver = null;
12356 mPendingBroadcast = null;
12357
12358 r.resultCode = resultCode;
12359 r.resultData = resultData;
12360 r.resultExtras = resultExtras;
12361 r.resultAbort = resultAbort;
12362
12363 // We will process the next receiver right now if this is finishing
12364 // an app receiver (which is always asynchronous) or after we have
12365 // come back from calling a receiver.
12366 return state == BroadcastRecord.APP_RECEIVE
12367 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12368 }
12369
12370 public void finishReceiver(IBinder who, int resultCode, String resultData,
12371 Bundle resultExtras, boolean resultAbort) {
12372 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12373
12374 // Refuse possible leaked file descriptors
12375 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12376 throw new IllegalArgumentException("File descriptors passed in Bundle");
12377 }
12378
12379 boolean doNext;
12380
12381 final long origId = Binder.clearCallingIdentity();
12382
12383 synchronized(this) {
12384 doNext = finishReceiverLocked(
12385 who, resultCode, resultData, resultExtras, resultAbort, true);
12386 }
12387
12388 if (doNext) {
12389 processNextBroadcast(false);
12390 }
12391 trimApplications();
12392
12393 Binder.restoreCallingIdentity(origId);
12394 }
12395
12396 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12397 if (r.nextReceiver > 0) {
12398 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12399 if (curReceiver instanceof BroadcastFilter) {
12400 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012401 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012402 System.identityHashCode(r),
12403 r.intent.getAction(),
12404 r.nextReceiver - 1,
12405 System.identityHashCode(bf));
12406 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012407 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012408 System.identityHashCode(r),
12409 r.intent.getAction(),
12410 r.nextReceiver - 1,
12411 ((ResolveInfo)curReceiver).toString());
12412 }
12413 } else {
12414 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12415 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012416 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012417 System.identityHashCode(r),
12418 r.intent.getAction(),
12419 r.nextReceiver,
12420 "NONE");
12421 }
12422 }
12423
12424 private final void broadcastTimeout() {
12425 synchronized (this) {
12426 if (mOrderedBroadcasts.size() == 0) {
12427 return;
12428 }
12429 long now = SystemClock.uptimeMillis();
12430 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012431 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012432 if (DEBUG_BROADCAST) Log.v(TAG,
12433 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012434 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012435 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012436 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012437 return;
12438 }
12439
12440 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012441 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012442 r.anrCount++;
12443
12444 // Current receiver has passed its expiration date.
12445 if (r.nextReceiver <= 0) {
12446 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12447 return;
12448 }
12449
12450 ProcessRecord app = null;
12451
12452 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12453 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12454 logBroadcastReceiverDiscard(r);
12455 if (curReceiver instanceof BroadcastFilter) {
12456 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12457 if (bf.receiverList.pid != 0
12458 && bf.receiverList.pid != MY_PID) {
12459 synchronized (this.mPidsSelfLocked) {
12460 app = this.mPidsSelfLocked.get(
12461 bf.receiverList.pid);
12462 }
12463 }
12464 } else {
12465 app = r.curApp;
12466 }
12467
12468 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012469 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012470 }
12471
12472 if (mPendingBroadcast == r) {
12473 mPendingBroadcast = null;
12474 }
12475
12476 // Move on to the next receiver.
12477 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12478 r.resultExtras, r.resultAbort, true);
12479 scheduleBroadcastsLocked();
12480 }
12481 }
12482
12483 private final void processCurBroadcastLocked(BroadcastRecord r,
12484 ProcessRecord app) throws RemoteException {
12485 if (app.thread == null) {
12486 throw new RemoteException();
12487 }
12488 r.receiver = app.thread.asBinder();
12489 r.curApp = app;
12490 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012491 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012492
12493 // Tell the application to launch this receiver.
12494 r.intent.setComponent(r.curComponent);
12495
12496 boolean started = false;
12497 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012498 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012499 "Delivering to component " + r.curComponent
12500 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012501 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012502 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12503 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12504 started = true;
12505 } finally {
12506 if (!started) {
12507 r.receiver = null;
12508 r.curApp = null;
12509 app.curReceiver = null;
12510 }
12511 }
12512
12513 }
12514
12515 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012516 Intent intent, int resultCode, String data, Bundle extras,
12517 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012518 if (app != null && app.thread != null) {
12519 // If we have an app thread, do the call through that so it is
12520 // correctly ordered with other one-way calls.
12521 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012522 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012523 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012524 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012525 }
12526 }
12527
12528 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12529 BroadcastFilter filter, boolean ordered) {
12530 boolean skip = false;
12531 if (filter.requiredPermission != null) {
12532 int perm = checkComponentPermission(filter.requiredPermission,
12533 r.callingPid, r.callingUid, -1);
12534 if (perm != PackageManager.PERMISSION_GRANTED) {
12535 Log.w(TAG, "Permission Denial: broadcasting "
12536 + r.intent.toString()
12537 + " from " + r.callerPackage + " (pid="
12538 + r.callingPid + ", uid=" + r.callingUid + ")"
12539 + " requires " + filter.requiredPermission
12540 + " due to registered receiver " + filter);
12541 skip = true;
12542 }
12543 }
12544 if (r.requiredPermission != null) {
12545 int perm = checkComponentPermission(r.requiredPermission,
12546 filter.receiverList.pid, filter.receiverList.uid, -1);
12547 if (perm != PackageManager.PERMISSION_GRANTED) {
12548 Log.w(TAG, "Permission Denial: receiving "
12549 + r.intent.toString()
12550 + " to " + filter.receiverList.app
12551 + " (pid=" + filter.receiverList.pid
12552 + ", uid=" + filter.receiverList.uid + ")"
12553 + " requires " + r.requiredPermission
12554 + " due to sender " + r.callerPackage
12555 + " (uid " + r.callingUid + ")");
12556 skip = true;
12557 }
12558 }
12559
12560 if (!skip) {
12561 // If this is not being sent as an ordered broadcast, then we
12562 // don't want to touch the fields that keep track of the current
12563 // state of ordered broadcasts.
12564 if (ordered) {
12565 r.receiver = filter.receiverList.receiver.asBinder();
12566 r.curFilter = filter;
12567 filter.receiverList.curBroadcast = r;
12568 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012569 if (filter.receiverList.app != null) {
12570 // Bump hosting application to no longer be in background
12571 // scheduling class. Note that we can't do that if there
12572 // isn't an app... but we can only be in that case for
12573 // things that directly call the IActivityManager API, which
12574 // are already core system stuff so don't matter for this.
12575 r.curApp = filter.receiverList.app;
12576 filter.receiverList.app.curReceiver = r;
12577 updateOomAdjLocked();
12578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012579 }
12580 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012581 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012582 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012583 Log.i(TAG, "Delivering to " + filter.receiverList.app
12584 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012585 }
12586 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12587 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012588 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012589 if (ordered) {
12590 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12591 }
12592 } catch (RemoteException e) {
12593 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12594 if (ordered) {
12595 r.receiver = null;
12596 r.curFilter = null;
12597 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012598 if (filter.receiverList.app != null) {
12599 filter.receiverList.app.curReceiver = null;
12600 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012601 }
12602 }
12603 }
12604 }
12605
Dianne Hackborn12527f92009-11-11 17:39:50 -080012606 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12607 if (r.callingUid < 0) {
12608 // This was from a registerReceiver() call; ignore it.
12609 return;
12610 }
12611 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12612 MAX_BROADCAST_HISTORY-1);
12613 r.finishTime = SystemClock.uptimeMillis();
12614 mBroadcastHistory[0] = r;
12615 }
12616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012617 private final void processNextBroadcast(boolean fromMsg) {
12618 synchronized(this) {
12619 BroadcastRecord r;
12620
12621 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12622 + mParallelBroadcasts.size() + " broadcasts, "
12623 + mOrderedBroadcasts.size() + " serialized broadcasts");
12624
12625 updateCpuStats();
12626
12627 if (fromMsg) {
12628 mBroadcastsScheduled = false;
12629 }
12630
12631 // First, deliver any non-serialized broadcasts right away.
12632 while (mParallelBroadcasts.size() > 0) {
12633 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012634 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012635 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012636 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12637 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012638 for (int i=0; i<N; i++) {
12639 Object target = r.receivers.get(i);
12640 if (DEBUG_BROADCAST) Log.v(TAG,
12641 "Delivering non-serialized to registered "
12642 + target + ": " + r);
12643 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12644 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012645 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012646 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12647 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012648 }
12649
12650 // Now take care of the next serialized one...
12651
12652 // If we are waiting for a process to come up to handle the next
12653 // broadcast, then do nothing at this point. Just in case, we
12654 // check that the process we're waiting for still exists.
12655 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012656 if (DEBUG_BROADCAST_LIGHT) {
12657 Log.v(TAG, "processNextBroadcast: waiting for "
12658 + mPendingBroadcast.curApp);
12659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012660
12661 boolean isDead;
12662 synchronized (mPidsSelfLocked) {
12663 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12664 }
12665 if (!isDead) {
12666 // It's still alive, so keep waiting
12667 return;
12668 } else {
12669 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12670 + " died before responding to broadcast");
12671 mPendingBroadcast = null;
12672 }
12673 }
12674
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012675 boolean looped = false;
12676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012677 do {
12678 if (mOrderedBroadcasts.size() == 0) {
12679 // No more broadcasts pending, so all done!
12680 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012681 if (looped) {
12682 // If we had finished the last ordered broadcast, then
12683 // make sure all processes have correct oom and sched
12684 // adjustments.
12685 updateOomAdjLocked();
12686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012687 return;
12688 }
12689 r = mOrderedBroadcasts.get(0);
12690 boolean forceReceive = false;
12691
12692 // Ensure that even if something goes awry with the timeout
12693 // detection, we catch "hung" broadcasts here, discard them,
12694 // and continue to make progress.
12695 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12696 long now = SystemClock.uptimeMillis();
12697 if (r.dispatchTime > 0) {
12698 if ((numReceivers > 0) &&
12699 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12700 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12701 + " now=" + now
12702 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012703 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012704 + " intent=" + r.intent
12705 + " numReceivers=" + numReceivers
12706 + " nextReceiver=" + r.nextReceiver
12707 + " state=" + r.state);
12708 broadcastTimeout(); // forcibly finish this broadcast
12709 forceReceive = true;
12710 r.state = BroadcastRecord.IDLE;
12711 }
12712 }
12713
12714 if (r.state != BroadcastRecord.IDLE) {
12715 if (DEBUG_BROADCAST) Log.d(TAG,
12716 "processNextBroadcast() called when not idle (state="
12717 + r.state + ")");
12718 return;
12719 }
12720
12721 if (r.receivers == null || r.nextReceiver >= numReceivers
12722 || r.resultAbort || forceReceive) {
12723 // No more receivers for this broadcast! Send the final
12724 // result if requested...
12725 if (r.resultTo != null) {
12726 try {
12727 if (DEBUG_BROADCAST) {
12728 int seq = r.intent.getIntExtra("seq", -1);
12729 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12730 + " seq=" + seq + " app=" + r.callerApp);
12731 }
12732 performReceive(r.callerApp, r.resultTo,
12733 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012734 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012735 } catch (RemoteException e) {
12736 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12737 }
12738 }
12739
12740 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12741 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12742
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012743 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12744 + r);
12745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012746 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012747 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012748 mOrderedBroadcasts.remove(0);
12749 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012750 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012751 continue;
12752 }
12753 } while (r == null);
12754
12755 // Get the next receiver...
12756 int recIdx = r.nextReceiver++;
12757
12758 // Keep track of when this receiver started, and make sure there
12759 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012760 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012761 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012762 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012763
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012764 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12765 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012766 if (DEBUG_BROADCAST) Log.v(TAG,
12767 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012768 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012769 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012770 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012771 }
12772
12773 Object nextReceiver = r.receivers.get(recIdx);
12774 if (nextReceiver instanceof BroadcastFilter) {
12775 // Simple case: this is a registered receiver who gets
12776 // a direct call.
12777 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12778 if (DEBUG_BROADCAST) Log.v(TAG,
12779 "Delivering serialized to registered "
12780 + filter + ": " + r);
12781 deliverToRegisteredReceiver(r, filter, r.ordered);
12782 if (r.receiver == null || !r.ordered) {
12783 // The receiver has already finished, so schedule to
12784 // process the next one.
12785 r.state = BroadcastRecord.IDLE;
12786 scheduleBroadcastsLocked();
12787 }
12788 return;
12789 }
12790
12791 // Hard case: need to instantiate the receiver, possibly
12792 // starting its application process to host it.
12793
12794 ResolveInfo info =
12795 (ResolveInfo)nextReceiver;
12796
12797 boolean skip = false;
12798 int perm = checkComponentPermission(info.activityInfo.permission,
12799 r.callingPid, r.callingUid,
12800 info.activityInfo.exported
12801 ? -1 : info.activityInfo.applicationInfo.uid);
12802 if (perm != PackageManager.PERMISSION_GRANTED) {
12803 Log.w(TAG, "Permission Denial: broadcasting "
12804 + r.intent.toString()
12805 + " from " + r.callerPackage + " (pid=" + r.callingPid
12806 + ", uid=" + r.callingUid + ")"
12807 + " requires " + info.activityInfo.permission
12808 + " due to receiver " + info.activityInfo.packageName
12809 + "/" + info.activityInfo.name);
12810 skip = true;
12811 }
12812 if (r.callingUid != Process.SYSTEM_UID &&
12813 r.requiredPermission != null) {
12814 try {
12815 perm = ActivityThread.getPackageManager().
12816 checkPermission(r.requiredPermission,
12817 info.activityInfo.applicationInfo.packageName);
12818 } catch (RemoteException e) {
12819 perm = PackageManager.PERMISSION_DENIED;
12820 }
12821 if (perm != PackageManager.PERMISSION_GRANTED) {
12822 Log.w(TAG, "Permission Denial: receiving "
12823 + r.intent + " to "
12824 + info.activityInfo.applicationInfo.packageName
12825 + " requires " + r.requiredPermission
12826 + " due to sender " + r.callerPackage
12827 + " (uid " + r.callingUid + ")");
12828 skip = true;
12829 }
12830 }
12831 if (r.curApp != null && r.curApp.crashing) {
12832 // If the target process is crashing, just skip it.
12833 skip = true;
12834 }
12835
12836 if (skip) {
12837 r.receiver = null;
12838 r.curFilter = null;
12839 r.state = BroadcastRecord.IDLE;
12840 scheduleBroadcastsLocked();
12841 return;
12842 }
12843
12844 r.state = BroadcastRecord.APP_RECEIVE;
12845 String targetProcess = info.activityInfo.processName;
12846 r.curComponent = new ComponentName(
12847 info.activityInfo.applicationInfo.packageName,
12848 info.activityInfo.name);
12849 r.curReceiver = info.activityInfo;
12850
12851 // Is this receiver's application already running?
12852 ProcessRecord app = getProcessRecordLocked(targetProcess,
12853 info.activityInfo.applicationInfo.uid);
12854 if (app != null && app.thread != null) {
12855 try {
12856 processCurBroadcastLocked(r, app);
12857 return;
12858 } catch (RemoteException e) {
12859 Log.w(TAG, "Exception when sending broadcast to "
12860 + r.curComponent, e);
12861 }
12862
12863 // If a dead object exception was thrown -- fall through to
12864 // restart the application.
12865 }
12866
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012867 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012868 if ((r.curApp=startProcessLocked(targetProcess,
12869 info.activityInfo.applicationInfo, true,
12870 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012871 "broadcast", r.curComponent,
12872 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12873 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012874 // Ah, this recipient is unavailable. Finish it if necessary,
12875 // and mark the broadcast record as ready for the next.
12876 Log.w(TAG, "Unable to launch app "
12877 + info.activityInfo.applicationInfo.packageName + "/"
12878 + info.activityInfo.applicationInfo.uid + " for broadcast "
12879 + r.intent + ": process is bad");
12880 logBroadcastReceiverDiscard(r);
12881 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12882 r.resultExtras, r.resultAbort, true);
12883 scheduleBroadcastsLocked();
12884 r.state = BroadcastRecord.IDLE;
12885 return;
12886 }
12887
12888 mPendingBroadcast = r;
12889 }
12890 }
12891
12892 // =========================================================
12893 // INSTRUMENTATION
12894 // =========================================================
12895
12896 public boolean startInstrumentation(ComponentName className,
12897 String profileFile, int flags, Bundle arguments,
12898 IInstrumentationWatcher watcher) {
12899 // Refuse possible leaked file descriptors
12900 if (arguments != null && arguments.hasFileDescriptors()) {
12901 throw new IllegalArgumentException("File descriptors passed in Bundle");
12902 }
12903
12904 synchronized(this) {
12905 InstrumentationInfo ii = null;
12906 ApplicationInfo ai = null;
12907 try {
12908 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012909 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012910 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012911 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012912 } catch (PackageManager.NameNotFoundException e) {
12913 }
12914 if (ii == null) {
12915 reportStartInstrumentationFailure(watcher, className,
12916 "Unable to find instrumentation info for: " + className);
12917 return false;
12918 }
12919 if (ai == null) {
12920 reportStartInstrumentationFailure(watcher, className,
12921 "Unable to find instrumentation target package: " + ii.targetPackage);
12922 return false;
12923 }
12924
12925 int match = mContext.getPackageManager().checkSignatures(
12926 ii.targetPackage, ii.packageName);
12927 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12928 String msg = "Permission Denial: starting instrumentation "
12929 + className + " from pid="
12930 + Binder.getCallingPid()
12931 + ", uid=" + Binder.getCallingPid()
12932 + " not allowed because package " + ii.packageName
12933 + " does not have a signature matching the target "
12934 + ii.targetPackage;
12935 reportStartInstrumentationFailure(watcher, className, msg);
12936 throw new SecurityException(msg);
12937 }
12938
12939 final long origId = Binder.clearCallingIdentity();
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012940 forceStopPackageLocked(ii.targetPackage, -1, true, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012941 ProcessRecord app = addAppLocked(ai);
12942 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012943 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012944 app.instrumentationProfileFile = profileFile;
12945 app.instrumentationArguments = arguments;
12946 app.instrumentationWatcher = watcher;
12947 app.instrumentationResultClass = className;
12948 Binder.restoreCallingIdentity(origId);
12949 }
12950
12951 return true;
12952 }
12953
12954 /**
12955 * Report errors that occur while attempting to start Instrumentation. Always writes the
12956 * error to the logs, but if somebody is watching, send the report there too. This enables
12957 * the "am" command to report errors with more information.
12958 *
12959 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12960 * @param cn The component name of the instrumentation.
12961 * @param report The error report.
12962 */
12963 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12964 ComponentName cn, String report) {
12965 Log.w(TAG, report);
12966 try {
12967 if (watcher != null) {
12968 Bundle results = new Bundle();
12969 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12970 results.putString("Error", report);
12971 watcher.instrumentationStatus(cn, -1, results);
12972 }
12973 } catch (RemoteException e) {
12974 Log.w(TAG, e);
12975 }
12976 }
12977
12978 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12979 if (app.instrumentationWatcher != null) {
12980 try {
12981 // NOTE: IInstrumentationWatcher *must* be oneway here
12982 app.instrumentationWatcher.instrumentationFinished(
12983 app.instrumentationClass,
12984 resultCode,
12985 results);
12986 } catch (RemoteException e) {
12987 }
12988 }
12989 app.instrumentationWatcher = null;
12990 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012991 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012992 app.instrumentationProfileFile = null;
12993 app.instrumentationArguments = null;
12994
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012995 forceStopPackageLocked(app.processName, -1, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012996 }
12997
12998 public void finishInstrumentation(IApplicationThread target,
12999 int resultCode, Bundle results) {
13000 // Refuse possible leaked file descriptors
13001 if (results != null && results.hasFileDescriptors()) {
13002 throw new IllegalArgumentException("File descriptors passed in Intent");
13003 }
13004
13005 synchronized(this) {
13006 ProcessRecord app = getRecordForAppLocked(target);
13007 if (app == null) {
13008 Log.w(TAG, "finishInstrumentation: no app for " + target);
13009 return;
13010 }
13011 final long origId = Binder.clearCallingIdentity();
13012 finishInstrumentationLocked(app, resultCode, results);
13013 Binder.restoreCallingIdentity(origId);
13014 }
13015 }
13016
13017 // =========================================================
13018 // CONFIGURATION
13019 // =========================================================
13020
13021 public ConfigurationInfo getDeviceConfigurationInfo() {
13022 ConfigurationInfo config = new ConfigurationInfo();
13023 synchronized (this) {
13024 config.reqTouchScreen = mConfiguration.touchscreen;
13025 config.reqKeyboardType = mConfiguration.keyboard;
13026 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013027 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
13028 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013029 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
13030 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013031 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
13032 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013033 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
13034 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070013035 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013036 }
13037 return config;
13038 }
13039
13040 public Configuration getConfiguration() {
13041 Configuration ci;
13042 synchronized(this) {
13043 ci = new Configuration(mConfiguration);
13044 }
13045 return ci;
13046 }
13047
13048 public void updateConfiguration(Configuration values) {
13049 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13050 "updateConfiguration()");
13051
13052 synchronized(this) {
13053 if (values == null && mWindowManager != null) {
13054 // sentinel: fetch the current configuration from the window manager
13055 values = mWindowManager.computeNewConfiguration();
13056 }
13057
13058 final long origId = Binder.clearCallingIdentity();
13059 updateConfigurationLocked(values, null);
13060 Binder.restoreCallingIdentity(origId);
13061 }
13062 }
13063
13064 /**
13065 * Do either or both things: (1) change the current configuration, and (2)
13066 * make sure the given activity is running with the (now) current
13067 * configuration. Returns true if the activity has been left running, or
13068 * false if <var>starting</var> is being destroyed to match the new
13069 * configuration.
13070 */
13071 public boolean updateConfigurationLocked(Configuration values,
13072 HistoryRecord starting) {
13073 int changes = 0;
13074
13075 boolean kept = true;
13076
13077 if (values != null) {
13078 Configuration newConfig = new Configuration(mConfiguration);
13079 changes = newConfig.updateFrom(values);
13080 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013081 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013082 Log.i(TAG, "Updating configuration to: " + values);
13083 }
13084
Doug Zongker2bec3d42009-12-04 12:52:44 -080013085 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013086
13087 if (values.locale != null) {
13088 saveLocaleLocked(values.locale,
13089 !values.locale.equals(mConfiguration.locale),
13090 values.userSetLocale);
13091 }
13092
13093 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013094 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013095
13096 AttributeCache ac = AttributeCache.instance();
13097 if (ac != null) {
13098 ac.updateConfiguration(mConfiguration);
13099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013100
13101 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13102 msg.obj = new Configuration(mConfiguration);
13103 mHandler.sendMessage(msg);
13104
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013105 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13106 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013107 try {
13108 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013109 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13110 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013111 app.thread.scheduleConfigurationChanged(mConfiguration);
13112 }
13113 } catch (Exception e) {
13114 }
13115 }
13116 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013117 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13118 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013119 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13120 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013121 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13122 broadcastIntentLocked(null, null,
13123 new Intent(Intent.ACTION_LOCALE_CHANGED),
13124 null, null, 0, null, null,
13125 null, false, false, MY_PID, Process.SYSTEM_UID);
13126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013127 }
13128 }
13129
13130 if (changes != 0 && starting == null) {
13131 // If the configuration changed, and the caller is not already
13132 // in the process of starting an activity, then find the top
13133 // activity to check if its configuration needs to change.
13134 starting = topRunningActivityLocked(null);
13135 }
13136
13137 if (starting != null) {
13138 kept = ensureActivityConfigurationLocked(starting, changes);
13139 if (kept) {
13140 // If this didn't result in the starting activity being
13141 // destroyed, then we need to make sure at this point that all
13142 // other activities are made visible.
13143 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13144 + ", ensuring others are correct.");
13145 ensureActivitiesVisibleLocked(starting, changes);
13146 }
13147 }
13148
13149 return kept;
13150 }
13151
13152 private final boolean relaunchActivityLocked(HistoryRecord r,
13153 int changes, boolean andResume) {
13154 List<ResultInfo> results = null;
13155 List<Intent> newIntents = null;
13156 if (andResume) {
13157 results = r.results;
13158 newIntents = r.newIntents;
13159 }
13160 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13161 + " with results=" + results + " newIntents=" + newIntents
13162 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013163 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13164 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013165 r.task.taskId, r.shortComponentName);
13166
13167 r.startFreezingScreenLocked(r.app, 0);
13168
13169 try {
13170 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13171 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013172 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013173 // Note: don't need to call pauseIfSleepingLocked() here, because
13174 // the caller will only pass in 'andResume' if this activity is
13175 // currently resumed, which implies we aren't sleeping.
13176 } catch (RemoteException e) {
13177 return false;
13178 }
13179
13180 if (andResume) {
13181 r.results = null;
13182 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013183 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013184 }
13185
13186 return true;
13187 }
13188
13189 /**
13190 * Make sure the given activity matches the current configuration. Returns
13191 * false if the activity had to be destroyed. Returns true if the
13192 * configuration is the same, or the activity will remain running as-is
13193 * for whatever reason. Ensures the HistoryRecord is updated with the
13194 * correct configuration and all other bookkeeping is handled.
13195 */
13196 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13197 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013198 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13199 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013200
13201 // Short circuit: if the two configurations are the exact same
13202 // object (the common case), then there is nothing to do.
13203 Configuration newConfig = mConfiguration;
13204 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013205 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13206 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013207 return true;
13208 }
13209
13210 // We don't worry about activities that are finishing.
13211 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013212 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013213 "Configuration doesn't matter in finishing " + r);
13214 r.stopFreezingScreenLocked(false);
13215 return true;
13216 }
13217
13218 // Okay we now are going to make this activity have the new config.
13219 // But then we need to figure out how it needs to deal with that.
13220 Configuration oldConfig = r.configuration;
13221 r.configuration = newConfig;
13222
13223 // If the activity isn't currently running, just leave the new
13224 // configuration and it will pick that up next time it starts.
13225 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013226 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013227 "Configuration doesn't matter not running " + r);
13228 r.stopFreezingScreenLocked(false);
13229 return true;
13230 }
13231
13232 // If the activity isn't persistent, there is a chance we will
13233 // need to restart it.
13234 if (!r.persistent) {
13235
13236 // Figure out what has changed between the two configurations.
13237 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013238 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13239 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013240 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013241 + Integer.toHexString(r.info.configChanges)
13242 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013243 }
13244 if ((changes&(~r.info.configChanges)) != 0) {
13245 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13246 r.configChangeFlags |= changes;
13247 r.startFreezingScreenLocked(r.app, globalChanges);
13248 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013249 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13250 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013251 destroyActivityLocked(r, true);
13252 } else if (r.state == ActivityState.PAUSING) {
13253 // A little annoying: we are waiting for this activity to
13254 // finish pausing. Let's not do anything now, but just
13255 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013256 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13257 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013258 r.configDestroy = true;
13259 return true;
13260 } else if (r.state == ActivityState.RESUMED) {
13261 // Try to optimize this case: the configuration is changing
13262 // and we need to restart the top, resumed activity.
13263 // Instead of doing the normal handshaking, just say
13264 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013265 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13266 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013267 relaunchActivityLocked(r, r.configChangeFlags, true);
13268 r.configChangeFlags = 0;
13269 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013270 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13271 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013272 relaunchActivityLocked(r, r.configChangeFlags, false);
13273 r.configChangeFlags = 0;
13274 }
13275
13276 // All done... tell the caller we weren't able to keep this
13277 // activity around.
13278 return false;
13279 }
13280 }
13281
13282 // Default case: the activity can handle this new configuration, so
13283 // hand it over. Note that we don't need to give it the new
13284 // configuration, since we always send configuration changes to all
13285 // process when they happen so it can just use whatever configuration
13286 // it last got.
13287 if (r.app != null && r.app.thread != null) {
13288 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013289 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013290 r.app.thread.scheduleActivityConfigurationChanged(r);
13291 } catch (RemoteException e) {
13292 // If process died, whatever.
13293 }
13294 }
13295 r.stopFreezingScreenLocked(false);
13296
13297 return true;
13298 }
13299
13300 /**
13301 * Save the locale. You must be inside a synchronized (this) block.
13302 */
13303 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13304 if(isDiff) {
13305 SystemProperties.set("user.language", l.getLanguage());
13306 SystemProperties.set("user.region", l.getCountry());
13307 }
13308
13309 if(isPersist) {
13310 SystemProperties.set("persist.sys.language", l.getLanguage());
13311 SystemProperties.set("persist.sys.country", l.getCountry());
13312 SystemProperties.set("persist.sys.localevar", l.getVariant());
13313 }
13314 }
13315
13316 // =========================================================
13317 // LIFETIME MANAGEMENT
13318 // =========================================================
13319
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013320 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13321 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013322 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013323 // This adjustment has already been computed. If we are calling
13324 // from the top, we may have already computed our adjustment with
13325 // an earlier hidden adjustment that isn't really for us... if
13326 // so, use the new hidden adjustment.
13327 if (!recursed && app.hidden) {
13328 app.curAdj = hiddenAdj;
13329 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013330 return app.curAdj;
13331 }
13332
13333 if (app.thread == null) {
13334 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013335 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013336 return (app.curAdj=EMPTY_APP_ADJ);
13337 }
13338
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013339 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13340 // The max adjustment doesn't allow this app to be anything
13341 // below foreground, so it is not worth doing work for it.
13342 app.adjType = "fixed";
13343 app.adjSeq = mAdjSeq;
13344 app.curRawAdj = app.maxAdj;
13345 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13346 return (app.curAdj=app.maxAdj);
13347 }
13348
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013349 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013350 app.adjSource = null;
13351 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013352 app.empty = false;
13353 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013354
The Android Open Source Project4df24232009-03-05 14:34:35 -080013355 // Determine the importance of the process, starting with most
13356 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013357 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013358 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013359 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013360 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013361 // The last app on the list is the foreground app.
13362 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013363 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013364 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013365 } else if (app.instrumentationClass != null) {
13366 // Don't want to kill running instrumentation.
13367 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013368 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013369 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013370 } else if (app.persistentActivities > 0) {
13371 // Special persistent activities... shouldn't be used these days.
13372 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013373 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013374 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013375 } else if (app.curReceiver != null ||
13376 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13377 // An app that is currently receiving a broadcast also
13378 // counts as being in the foreground.
13379 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013380 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013381 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013382 } else if (app.executingServices.size() > 0) {
13383 // An app that is currently executing a service callback also
13384 // counts as being in the foreground.
13385 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013386 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013387 app.adjType = "exec-service";
13388 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013389 // The user is aware of this app, so make it visible.
13390 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013391 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013392 app.adjType = "foreground-service";
13393 } else if (app.forcingToForeground != null) {
13394 // The user is aware of this app, so make it visible.
13395 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013396 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013397 app.adjType = "force-foreground";
13398 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013399 } else if (app == mHomeProcess) {
13400 // This process is hosting what we currently consider to be the
13401 // home app, so we don't want to let it go into the background.
13402 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013403 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013404 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013405 } else if ((N=app.activities.size()) != 0) {
13406 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013407 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013408 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013409 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013410 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013411 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013412 for (int j=0; j<N; j++) {
13413 if (((HistoryRecord)app.activities.get(j)).visible) {
13414 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013415 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013416 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013417 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013418 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013419 break;
13420 }
13421 }
13422 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013423 // A very not-needed process. If this is lower in the lru list,
13424 // we will push it in to the empty bucket.
13425 app.hidden = true;
13426 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013427 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013428 adj = hiddenAdj;
13429 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013430 }
13431
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013432 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13433
The Android Open Source Project4df24232009-03-05 14:34:35 -080013434 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013435 // there are applications dependent on our services or providers, but
13436 // this gives us a baseline and makes sure we don't get into an
13437 // infinite recursion.
13438 app.adjSeq = mAdjSeq;
13439 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013440
Christopher Tate6fa95972009-06-05 18:43:55 -070013441 if (mBackupTarget != null && app == mBackupTarget.app) {
13442 // If possible we want to avoid killing apps while they're being backed up
13443 if (adj > BACKUP_APP_ADJ) {
13444 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13445 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013446 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013447 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013448 }
13449 }
13450
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013451 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13452 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013453 final long now = SystemClock.uptimeMillis();
13454 // This process is more important if the top activity is
13455 // bound to the service.
13456 Iterator jt = app.services.iterator();
13457 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13458 ServiceRecord s = (ServiceRecord)jt.next();
13459 if (s.startRequested) {
13460 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13461 // This service has seen some activity within
13462 // recent memory, so we will keep its process ahead
13463 // of the background processes.
13464 if (adj > SECONDARY_SERVER_ADJ) {
13465 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013466 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013467 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013468 }
13469 }
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013470 // If we have let the service slide into the background
13471 // state, still have some text describing what it is doing
13472 // even though the service no longer has an impact.
13473 if (adj > SECONDARY_SERVER_ADJ) {
13474 app.adjType = "started-bg-services";
13475 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013476 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013477 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13478 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013479 Iterator<ConnectionRecord> kt
13480 = s.connections.values().iterator();
13481 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13482 // XXX should compute this based on the max of
13483 // all connected clients.
13484 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013485 if (cr.binding.client == app) {
13486 // Binding to ourself is not interesting.
13487 continue;
13488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013489 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13490 ProcessRecord client = cr.binding.client;
13491 int myHiddenAdj = hiddenAdj;
13492 if (myHiddenAdj > client.hiddenAdj) {
13493 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13494 myHiddenAdj = client.hiddenAdj;
13495 } else {
13496 myHiddenAdj = VISIBLE_APP_ADJ;
13497 }
13498 }
13499 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013500 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013501 if (adj > clientAdj) {
13502 adj = clientAdj > VISIBLE_APP_ADJ
13503 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013504 if (!client.hidden) {
13505 app.hidden = false;
13506 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013507 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013508 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13509 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013510 app.adjSource = cr.binding.client;
13511 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013512 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013513 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13514 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13515 schedGroup = Process.THREAD_GROUP_DEFAULT;
13516 }
13517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013518 }
13519 HistoryRecord a = cr.activity;
13520 //if (a != null) {
13521 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13522 //}
13523 if (a != null && adj > FOREGROUND_APP_ADJ &&
13524 (a.state == ActivityState.RESUMED
13525 || a.state == ActivityState.PAUSING)) {
13526 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013527 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013528 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013529 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013530 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13531 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013532 app.adjSource = a;
13533 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013534 }
13535 }
13536 }
13537 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013538
13539 // Finally, f this process has active services running in it, we
13540 // would like to avoid killing it unless it would prevent the current
13541 // application from running. By default we put the process in
13542 // with the rest of the background processes; as we scan through
13543 // its services we may bump it up from there.
13544 if (adj > hiddenAdj) {
13545 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013546 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013547 app.adjType = "bg-services";
13548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013549 }
13550
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013551 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13552 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013553 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013554 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13555 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013556 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13557 if (cpr.clients.size() != 0) {
13558 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13559 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13560 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013561 if (client == app) {
13562 // Being our own client is not interesting.
13563 continue;
13564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013565 int myHiddenAdj = hiddenAdj;
13566 if (myHiddenAdj > client.hiddenAdj) {
13567 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13568 myHiddenAdj = client.hiddenAdj;
13569 } else {
13570 myHiddenAdj = FOREGROUND_APP_ADJ;
13571 }
13572 }
13573 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013574 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013575 if (adj > clientAdj) {
13576 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013577 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013578 if (!client.hidden) {
13579 app.hidden = false;
13580 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013581 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013582 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13583 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013584 app.adjSource = client;
13585 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013586 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013587 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13588 schedGroup = Process.THREAD_GROUP_DEFAULT;
13589 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013590 }
13591 }
13592 // If the provider has external (non-framework) process
13593 // dependencies, ensure that its adjustment is at least
13594 // FOREGROUND_APP_ADJ.
13595 if (cpr.externals != 0) {
13596 if (adj > FOREGROUND_APP_ADJ) {
13597 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013598 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013599 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013600 app.adjType = "provider";
13601 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013602 }
13603 }
13604 }
13605 }
13606
13607 app.curRawAdj = adj;
13608
13609 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13610 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13611 if (adj > app.maxAdj) {
13612 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013613 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13614 schedGroup = Process.THREAD_GROUP_DEFAULT;
13615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013616 }
13617
13618 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013619 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013621 return adj;
13622 }
13623
13624 /**
13625 * Ask a given process to GC right now.
13626 */
13627 final void performAppGcLocked(ProcessRecord app) {
13628 try {
13629 app.lastRequestedGc = SystemClock.uptimeMillis();
13630 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013631 if (app.reportLowMemory) {
13632 app.reportLowMemory = false;
13633 app.thread.scheduleLowMemory();
13634 } else {
13635 app.thread.processInBackground();
13636 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013637 }
13638 } catch (Exception e) {
13639 // whatever.
13640 }
13641 }
13642
13643 /**
13644 * Returns true if things are idle enough to perform GCs.
13645 */
13646 private final boolean canGcNow() {
13647 return mParallelBroadcasts.size() == 0
13648 && mOrderedBroadcasts.size() == 0
13649 && (mSleeping || (mResumedActivity != null &&
13650 mResumedActivity.idle));
13651 }
13652
13653 /**
13654 * Perform GCs on all processes that are waiting for it, but only
13655 * if things are idle.
13656 */
13657 final void performAppGcsLocked() {
13658 final int N = mProcessesToGc.size();
13659 if (N <= 0) {
13660 return;
13661 }
13662 if (canGcNow()) {
13663 while (mProcessesToGc.size() > 0) {
13664 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013665 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13666 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13667 <= SystemClock.uptimeMillis()) {
13668 // To avoid spamming the system, we will GC processes one
13669 // at a time, waiting a few seconds between each.
13670 performAppGcLocked(proc);
13671 scheduleAppGcsLocked();
13672 return;
13673 } else {
13674 // It hasn't been long enough since we last GCed this
13675 // process... put it in the list to wait for its time.
13676 addProcessToGcListLocked(proc);
13677 break;
13678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013679 }
13680 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013681
13682 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013683 }
13684 }
13685
13686 /**
13687 * If all looks good, perform GCs on all processes waiting for them.
13688 */
13689 final void performAppGcsIfAppropriateLocked() {
13690 if (canGcNow()) {
13691 performAppGcsLocked();
13692 return;
13693 }
13694 // Still not idle, wait some more.
13695 scheduleAppGcsLocked();
13696 }
13697
13698 /**
13699 * Schedule the execution of all pending app GCs.
13700 */
13701 final void scheduleAppGcsLocked() {
13702 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013703
13704 if (mProcessesToGc.size() > 0) {
13705 // Schedule a GC for the time to the next process.
13706 ProcessRecord proc = mProcessesToGc.get(0);
13707 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13708
13709 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13710 long now = SystemClock.uptimeMillis();
13711 if (when < (now+GC_TIMEOUT)) {
13712 when = now + GC_TIMEOUT;
13713 }
13714 mHandler.sendMessageAtTime(msg, when);
13715 }
13716 }
13717
13718 /**
13719 * Add a process to the array of processes waiting to be GCed. Keeps the
13720 * list in sorted order by the last GC time. The process can't already be
13721 * on the list.
13722 */
13723 final void addProcessToGcListLocked(ProcessRecord proc) {
13724 boolean added = false;
13725 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13726 if (mProcessesToGc.get(i).lastRequestedGc <
13727 proc.lastRequestedGc) {
13728 added = true;
13729 mProcessesToGc.add(i+1, proc);
13730 break;
13731 }
13732 }
13733 if (!added) {
13734 mProcessesToGc.add(0, proc);
13735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013736 }
13737
13738 /**
13739 * Set up to ask a process to GC itself. This will either do it
13740 * immediately, or put it on the list of processes to gc the next
13741 * time things are idle.
13742 */
13743 final void scheduleAppGcLocked(ProcessRecord app) {
13744 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013745 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013746 return;
13747 }
13748 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013749 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013750 scheduleAppGcsLocked();
13751 }
13752 }
13753
13754 private final boolean updateOomAdjLocked(
13755 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13756 app.hiddenAdj = hiddenAdj;
13757
13758 if (app.thread == null) {
13759 return true;
13760 }
13761
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013762 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013763
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013764 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013765 if (app.curRawAdj != app.setRawAdj) {
13766 if (app.curRawAdj > FOREGROUND_APP_ADJ
13767 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13768 // If this app is transitioning from foreground to
13769 // non-foreground, have it do a gc.
13770 scheduleAppGcLocked(app);
13771 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13772 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13773 // Likewise do a gc when an app is moving in to the
13774 // background (such as a service stopping).
13775 scheduleAppGcLocked(app);
13776 }
13777 app.setRawAdj = app.curRawAdj;
13778 }
13779 if (adj != app.setAdj) {
13780 if (Process.setOomAdj(app.pid, adj)) {
13781 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13782 TAG, "Set app " + app.processName +
13783 " oom adj to " + adj);
13784 app.setAdj = adj;
13785 } else {
13786 return false;
13787 }
13788 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013789 if (app.setSchedGroup != app.curSchedGroup) {
13790 app.setSchedGroup = app.curSchedGroup;
13791 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13792 "Setting process group of " + app.processName
13793 + " to " + app.curSchedGroup);
13794 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013795 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013796 try {
13797 Process.setProcessGroup(app.pid, app.curSchedGroup);
13798 } catch (Exception e) {
13799 Log.w(TAG, "Failed setting process group of " + app.pid
13800 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013801 e.printStackTrace();
13802 } finally {
13803 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013804 }
13805 }
13806 if (false) {
13807 if (app.thread != null) {
13808 try {
13809 app.thread.setSchedulingGroup(app.curSchedGroup);
13810 } catch (RemoteException e) {
13811 }
13812 }
13813 }
13814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013815 }
13816
13817 return true;
13818 }
13819
13820 private final HistoryRecord resumedAppLocked() {
13821 HistoryRecord resumedActivity = mResumedActivity;
13822 if (resumedActivity == null || resumedActivity.app == null) {
13823 resumedActivity = mPausingActivity;
13824 if (resumedActivity == null || resumedActivity.app == null) {
13825 resumedActivity = topRunningActivityLocked(null);
13826 }
13827 }
13828 return resumedActivity;
13829 }
13830
13831 private final boolean updateOomAdjLocked(ProcessRecord app) {
13832 final HistoryRecord TOP_ACT = resumedAppLocked();
13833 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13834 int curAdj = app.curAdj;
13835 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13836 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13837
13838 mAdjSeq++;
13839
13840 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13841 if (res) {
13842 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13843 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13844 if (nowHidden != wasHidden) {
13845 // Changed to/from hidden state, so apps after it in the LRU
13846 // list may also be changed.
13847 updateOomAdjLocked();
13848 }
13849 }
13850 return res;
13851 }
13852
13853 private final boolean updateOomAdjLocked() {
13854 boolean didOomAdj = true;
13855 final HistoryRecord TOP_ACT = resumedAppLocked();
13856 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13857
13858 if (false) {
13859 RuntimeException e = new RuntimeException();
13860 e.fillInStackTrace();
13861 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13862 }
13863
13864 mAdjSeq++;
13865
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013866 // Let's determine how many processes we have running vs.
13867 // how many slots we have for background processes; we may want
13868 // to put multiple processes in a slot of there are enough of
13869 // them.
13870 int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
13871 int factor = (mLruProcesses.size()-4)/numSlots;
13872 if (factor < 1) factor = 1;
13873 int step = 0;
13874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013875 // First try updating the OOM adjustment for each of the
13876 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013877 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013878 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13879 while (i > 0) {
13880 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013881 ProcessRecord app = mLruProcesses.get(i);
13882 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013883 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013884 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013885 && app.curAdj == curHiddenAdj) {
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013886 step++;
13887 if (step >= factor) {
13888 step = 0;
13889 curHiddenAdj++;
13890 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013891 }
13892 } else {
13893 didOomAdj = false;
13894 }
13895 }
13896
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013897 // If we return false, we will fall back on killing processes to
13898 // have a fixed limit. Do this if a limit has been requested; else
13899 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013900 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13901 }
13902
13903 private final void trimApplications() {
13904 synchronized (this) {
13905 int i;
13906
13907 // First remove any unused application processes whose package
13908 // has been removed.
13909 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13910 final ProcessRecord app = mRemovedProcesses.get(i);
13911 if (app.activities.size() == 0
13912 && app.curReceiver == null && app.services.size() == 0) {
13913 Log.i(
13914 TAG, "Exiting empty application process "
13915 + app.processName + " ("
13916 + (app.thread != null ? app.thread.asBinder() : null)
13917 + ")\n");
13918 if (app.pid > 0 && app.pid != MY_PID) {
13919 Process.killProcess(app.pid);
13920 } else {
13921 try {
13922 app.thread.scheduleExit();
13923 } catch (Exception e) {
13924 // Ignore exceptions.
13925 }
13926 }
13927 cleanUpApplicationRecordLocked(app, false, -1);
13928 mRemovedProcesses.remove(i);
13929
13930 if (app.persistent) {
13931 if (app.persistent) {
13932 addAppLocked(app.info);
13933 }
13934 }
13935 }
13936 }
13937
13938 // Now try updating the OOM adjustment for each of the
13939 // application processes based on their current state.
13940 // If the setOomAdj() API is not supported, then go with our
13941 // back-up plan...
13942 if (!updateOomAdjLocked()) {
13943
13944 // Count how many processes are running services.
13945 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013946 for (i=mLruProcesses.size()-1; i>=0; i--) {
13947 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013948
13949 if (app.persistent || app.services.size() != 0
13950 || app.curReceiver != null
13951 || app.persistentActivities > 0) {
13952 // Don't count processes holding services against our
13953 // maximum process count.
13954 if (localLOGV) Log.v(
13955 TAG, "Not trimming app " + app + " with services: "
13956 + app.services);
13957 numServiceProcs++;
13958 }
13959 }
13960
13961 int curMaxProcs = mProcessLimit;
13962 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13963 if (mAlwaysFinishActivities) {
13964 curMaxProcs = 1;
13965 }
13966 curMaxProcs += numServiceProcs;
13967
13968 // Quit as many processes as we can to get down to the desired
13969 // process count. First remove any processes that no longer
13970 // have activites running in them.
13971 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013972 i<mLruProcesses.size()
13973 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013974 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013975 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013976 // Quit an application only if it is not currently
13977 // running any activities.
13978 if (!app.persistent && app.activities.size() == 0
13979 && app.curReceiver == null && app.services.size() == 0) {
13980 Log.i(
13981 TAG, "Exiting empty application process "
13982 + app.processName + " ("
13983 + (app.thread != null ? app.thread.asBinder() : null)
13984 + ")\n");
13985 if (app.pid > 0 && app.pid != MY_PID) {
13986 Process.killProcess(app.pid);
13987 } else {
13988 try {
13989 app.thread.scheduleExit();
13990 } catch (Exception e) {
13991 // Ignore exceptions.
13992 }
13993 }
13994 // todo: For now we assume the application is not buggy
13995 // or evil, and will quit as a result of our request.
13996 // Eventually we need to drive this off of the death
13997 // notification, and kill the process if it takes too long.
13998 cleanUpApplicationRecordLocked(app, false, i);
13999 i--;
14000 }
14001 }
14002
14003 // If we still have too many processes, now from the least
14004 // recently used process we start finishing activities.
14005 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014006 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014007 " of " + curMaxProcs + " processes");
14008 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014009 i<mLruProcesses.size()
14010 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014011 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014012 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014013 // Quit the application only if we have a state saved for
14014 // all of its activities.
14015 boolean canQuit = !app.persistent && app.curReceiver == null
14016 && app.services.size() == 0
14017 && app.persistentActivities == 0;
14018 int NUMA = app.activities.size();
14019 int j;
14020 if (Config.LOGV) Log.v(
14021 TAG, "Looking to quit " + app.processName);
14022 for (j=0; j<NUMA && canQuit; j++) {
14023 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14024 if (Config.LOGV) Log.v(
14025 TAG, " " + r.intent.getComponent().flattenToShortString()
14026 + ": frozen=" + r.haveState + ", visible=" + r.visible);
14027 canQuit = (r.haveState || !r.stateNotNeeded)
14028 && !r.visible && r.stopped;
14029 }
14030 if (canQuit) {
14031 // Finish all of the activities, and then the app itself.
14032 for (j=0; j<NUMA; j++) {
14033 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14034 if (!r.finishing) {
14035 destroyActivityLocked(r, false);
14036 }
14037 r.resultTo = null;
14038 }
14039 Log.i(TAG, "Exiting application process "
14040 + app.processName + " ("
14041 + (app.thread != null ? app.thread.asBinder() : null)
14042 + ")\n");
14043 if (app.pid > 0 && app.pid != MY_PID) {
14044 Process.killProcess(app.pid);
14045 } else {
14046 try {
14047 app.thread.scheduleExit();
14048 } catch (Exception e) {
14049 // Ignore exceptions.
14050 }
14051 }
14052 // todo: For now we assume the application is not buggy
14053 // or evil, and will quit as a result of our request.
14054 // Eventually we need to drive this off of the death
14055 // notification, and kill the process if it takes too long.
14056 cleanUpApplicationRecordLocked(app, false, i);
14057 i--;
14058 //dump();
14059 }
14060 }
14061
14062 }
14063
14064 int curMaxActivities = MAX_ACTIVITIES;
14065 if (mAlwaysFinishActivities) {
14066 curMaxActivities = 1;
14067 }
14068
14069 // Finally, if there are too many activities now running, try to
14070 // finish as many as we can to get back down to the limit.
14071 for ( i=0;
14072 i<mLRUActivities.size()
14073 && mLRUActivities.size() > curMaxActivities;
14074 i++) {
14075 final HistoryRecord r
14076 = (HistoryRecord)mLRUActivities.get(i);
14077
14078 // We can finish this one if we have its icicle saved and
14079 // it is not persistent.
14080 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14081 && r.stopped && !r.persistent && !r.finishing) {
14082 final int origSize = mLRUActivities.size();
14083 destroyActivityLocked(r, true);
14084
14085 // This will remove it from the LRU list, so keep
14086 // our index at the same value. Note that this check to
14087 // see if the size changes is just paranoia -- if
14088 // something unexpected happens, we don't want to end up
14089 // in an infinite loop.
14090 if (origSize > mLRUActivities.size()) {
14091 i--;
14092 }
14093 }
14094 }
14095 }
14096 }
14097
14098 /** This method sends the specified signal to each of the persistent apps */
14099 public void signalPersistentProcesses(int sig) throws RemoteException {
14100 if (sig != Process.SIGNAL_USR1) {
14101 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14102 }
14103
14104 synchronized (this) {
14105 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14106 != PackageManager.PERMISSION_GRANTED) {
14107 throw new SecurityException("Requires permission "
14108 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14109 }
14110
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014111 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14112 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014113 if (r.thread != null && r.persistent) {
14114 Process.sendSignal(r.pid, sig);
14115 }
14116 }
14117 }
14118 }
14119
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014120 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014121 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014122
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014123 try {
14124 synchronized (this) {
14125 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14126 // its own permission.
14127 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14128 != PackageManager.PERMISSION_GRANTED) {
14129 throw new SecurityException("Requires permission "
14130 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014131 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014132
14133 if (start && fd == null) {
14134 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014135 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014136
14137 ProcessRecord proc = null;
14138 try {
14139 int pid = Integer.parseInt(process);
14140 synchronized (mPidsSelfLocked) {
14141 proc = mPidsSelfLocked.get(pid);
14142 }
14143 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014144 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014145
14146 if (proc == null) {
14147 HashMap<String, SparseArray<ProcessRecord>> all
14148 = mProcessNames.getMap();
14149 SparseArray<ProcessRecord> procs = all.get(process);
14150 if (procs != null && procs.size() > 0) {
14151 proc = procs.valueAt(0);
14152 }
14153 }
14154
14155 if (proc == null || proc.thread == null) {
14156 throw new IllegalArgumentException("Unknown process: " + process);
14157 }
14158
14159 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14160 if (isSecure) {
14161 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14162 throw new SecurityException("Process not debuggable: " + proc);
14163 }
14164 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014165
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014166 proc.thread.profilerControl(start, path, fd);
14167 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014168 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014169 }
14170 } catch (RemoteException e) {
14171 throw new IllegalStateException("Process disappeared");
14172 } finally {
14173 if (fd != null) {
14174 try {
14175 fd.close();
14176 } catch (IOException e) {
14177 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014178 }
14179 }
14180 }
14181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014182 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14183 public void monitor() {
14184 synchronized (this) { }
14185 }
14186}