blob: c2c6e76e7d994db1b261474ce495f49a8c4a9d21 [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;
95import android.provider.Checkin;
96import android.provider.Settings;
97import android.text.TextUtils;
98import android.util.Config;
99import android.util.EventLog;
100import android.util.Log;
101import android.util.PrintWriterPrinter;
102import android.util.SparseArray;
103import android.view.Gravity;
104import android.view.LayoutInflater;
105import android.view.View;
106import android.view.WindowManager;
107import android.view.WindowManagerPolicy;
108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import java.io.File;
110import java.io.FileDescriptor;
111import java.io.FileInputStream;
112import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200113import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import java.io.PrintWriter;
115import java.lang.IllegalStateException;
116import java.lang.ref.WeakReference;
117import java.util.ArrayList;
118import java.util.HashMap;
119import java.util.HashSet;
120import java.util.Iterator;
121import java.util.List;
122import java.util.Locale;
123import java.util.Map;
124
125public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
126 static final String TAG = "ActivityManager";
127 static final boolean DEBUG = false;
128 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
129 static final boolean DEBUG_SWITCH = localLOGV || false;
130 static final boolean DEBUG_TASKS = localLOGV || false;
131 static final boolean DEBUG_PAUSE = localLOGV || false;
132 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
133 static final boolean DEBUG_TRANSITION = localLOGV || false;
134 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700135 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 static final boolean DEBUG_SERVICE = localLOGV || false;
137 static final boolean DEBUG_VISBILITY = localLOGV || false;
138 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700139 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700141 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700142 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700143 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 static final boolean VALIDATE_TOKENS = false;
145 static final boolean SHOW_ACTIVITY_START_TIME = true;
146
147 // Control over CPU and battery monitoring.
148 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
149 static final boolean MONITOR_CPU_USAGE = true;
150 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
151 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
152 static final boolean MONITOR_THREAD_CPU_USAGE = false;
153
Dianne Hackborn1655be42009-05-08 14:29:01 -0700154 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700155 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 private static final String SYSTEM_SECURE = "ro.secure";
158
159 // This is the maximum number of application processes we would like
160 // to have running. Due to the asynchronous nature of things, we can
161 // temporarily go beyond this limit.
162 static final int MAX_PROCESSES = 2;
163
164 // Set to false to leave processes running indefinitely, relying on
165 // the kernel killing them as resources are required.
166 static final boolean ENFORCE_PROCESS_LIMIT = false;
167
168 // This is the maximum number of activities that we would like to have
169 // running at a given time.
170 static final int MAX_ACTIVITIES = 20;
171
172 // Maximum number of recent tasks that we can remember.
173 static final int MAX_RECENT_TASKS = 20;
174
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700175 // Amount of time after a call to stopAppSwitches() during which we will
176 // prevent further untrusted switches from happening.
177 static final long APP_SWITCH_DELAY_TIME = 5*1000;
178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 // How long until we reset a task when the user returns to it. Currently
180 // 30 minutes.
181 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
182
183 // Set to true to disable the icon that is shown while a new activity
184 // is being started.
185 static final boolean SHOW_APP_STARTING_ICON = true;
186
187 // How long we wait until giving up on the last activity to pause. This
188 // is short because it directly impacts the responsiveness of starting the
189 // next activity.
190 static final int PAUSE_TIMEOUT = 500;
191
192 /**
193 * How long we can hold the launch wake lock before giving up.
194 */
195 static final int LAUNCH_TIMEOUT = 10*1000;
196
197 // How long we wait for a launched process to attach to the activity manager
198 // before we decide it's never going to come up for real.
199 static final int PROC_START_TIMEOUT = 10*1000;
200
201 // How long we wait until giving up on the last activity telling us it
202 // is idle.
203 static final int IDLE_TIMEOUT = 10*1000;
204
205 // How long to wait after going idle before forcing apps to GC.
206 static final int GC_TIMEOUT = 5*1000;
207
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700208 // The minimum amount of time between successive GC requests for a process.
209 static final int GC_MIN_INTERVAL = 60*1000;
210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 // How long we wait until giving up on an activity telling us it has
212 // finished destroying itself.
213 static final int DESTROY_TIMEOUT = 10*1000;
214
215 // How long we allow a receiver to run before giving up on it.
216 static final int BROADCAST_TIMEOUT = 10*1000;
217
218 // How long we wait for a service to finish executing.
219 static final int SERVICE_TIMEOUT = 20*1000;
220
221 // How long a service needs to be running until restarting its process
222 // is no longer considered to be a relaunch of the service.
223 static final int SERVICE_RESTART_DURATION = 5*1000;
224
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700225 // How long a service needs to be running until it will start back at
226 // SERVICE_RESTART_DURATION after being killed.
227 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
228
229 // Multiplying factor to increase restart duration time by, for each time
230 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
231 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
232
233 // The minimum amount of time between restarting services that we allow.
234 // That is, when multiple services are restarting, we won't allow each
235 // to restart less than this amount of time from the last one.
236 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 // Maximum amount of time for there to be no activity on a service before
239 // we consider it non-essential and allow its process to go on the
240 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700241 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242
243 // How long we wait until we timeout on key dispatching.
244 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
245
246 // The minimum time we allow between crashes, for us to consider this
247 // application to be bad and stop and its services and reject broadcasts.
248 static final int MIN_CRASH_INTERVAL = 60*1000;
249
250 // How long we wait until we timeout on key dispatching during instrumentation.
251 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
252
253 // OOM adjustments for processes in various states:
254
255 // This is a process without anything currently running in it. Definitely
256 // the first to go! Value set in system/rootdir/init.rc on startup.
257 // This value is initalized in the constructor, careful when refering to
258 // this static variable externally.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800259 static final int EMPTY_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260
261 // This is a process only hosting activities that are not visible,
262 // so it can be killed without any disruption. Value set in
263 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800264 static final int HIDDEN_APP_MAX_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 static int HIDDEN_APP_MIN_ADJ;
266
The Android Open Source Project4df24232009-03-05 14:34:35 -0800267 // This is a process holding the home application -- we want to try
268 // avoiding killing it, even if it would normally be in the background,
269 // because the user interacts with it so much.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800270 static final int HOME_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800271
Christopher Tate6fa95972009-06-05 18:43:55 -0700272 // This is a process currently hosting a backup operation. Killing it
273 // is not entirely fatal but is generally a bad idea.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800274 static final int BACKUP_APP_ADJ;
Christopher Tate6fa95972009-06-05 18:43:55 -0700275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 // This is a process holding a secondary server -- killing it will not
277 // have much of an impact as far as the user is concerned. Value set in
278 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800279 static final int SECONDARY_SERVER_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 // This is a process only hosting activities that are visible to the
282 // user, so we'd prefer they don't disappear. Value set in
283 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800284 static final int VISIBLE_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285
286 // This is the process running the current foreground app. We'd really
287 // rather not kill it! Value set in system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800288 static final int FOREGROUND_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289
290 // This is a process running a core server, such as telephony. Definitely
291 // don't want to kill it, but doing so is not completely fatal.
292 static final int CORE_SERVER_ADJ = -12;
293
294 // The system process runs at the default adjustment.
295 static final int SYSTEM_ADJ = -16;
296
297 // Memory pages are 4K.
298 static final int PAGE_SIZE = 4*1024;
299
Jacek Surazski82a73df2009-06-17 14:33:18 +0200300 // System property defining error report receiver for system apps
301 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
302
303 // System property defining default error report receiver
304 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 // Corresponding memory levels for above adjustments.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800307 static final int EMPTY_APP_MEM;
308 static final int HIDDEN_APP_MEM;
309 static final int HOME_APP_MEM;
310 static final int BACKUP_APP_MEM;
311 static final int SECONDARY_SERVER_MEM;
312 static final int VISIBLE_APP_MEM;
313 static final int FOREGROUND_APP_MEM;
314
315 // The minimum number of hidden apps we want to be able to keep around,
316 // without empty apps being able to push them out of memory.
317 static final int MIN_HIDDEN_APPS = 2;
318
319 // We put empty content processes after any hidden processes that have
320 // been idle for less than 30 seconds.
321 static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
322
323 // We put empty content processes after any hidden processes that have
324 // been idle for less than 60 seconds.
325 static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
326
327 static {
328 // These values are set in system/rootdir/init.rc on startup.
329 FOREGROUND_APP_ADJ =
330 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
331 VISIBLE_APP_ADJ =
332 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
333 SECONDARY_SERVER_ADJ =
334 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
335 BACKUP_APP_ADJ =
336 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
337 HOME_APP_ADJ =
338 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
339 HIDDEN_APP_MIN_ADJ =
340 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
341 EMPTY_APP_ADJ =
342 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
343 HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
344 FOREGROUND_APP_MEM =
345 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
346 VISIBLE_APP_MEM =
347 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
348 SECONDARY_SERVER_MEM =
349 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
350 BACKUP_APP_MEM =
351 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
352 HOME_APP_MEM =
353 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
354 HIDDEN_APP_MEM =
355 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
356 EMPTY_APP_MEM =
357 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359
Dan Egnor42471dd2010-01-07 17:25:22 -0800360 static final int MY_PID = Process.myPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361
362 static final String[] EMPTY_STRING_ARRAY = new String[0];
363
364 enum ActivityState {
365 INITIALIZING,
366 RESUMED,
367 PAUSING,
368 PAUSED,
369 STOPPING,
370 STOPPED,
371 FINISHING,
372 DESTROYING,
373 DESTROYED
374 }
375
376 /**
377 * The back history of all previous (and possibly still
378 * running) activities. It contains HistoryRecord objects.
379 */
380 final ArrayList mHistory = new ArrayList();
381
382 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700383 * Description of a request to start a new activity, which has been held
384 * due to app switches being disabled.
385 */
386 class PendingActivityLaunch {
387 HistoryRecord r;
388 HistoryRecord sourceRecord;
389 Uri[] grantedUriPermissions;
390 int grantedMode;
391 boolean onlyIfNeeded;
392 }
393
394 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
395 = new ArrayList<PendingActivityLaunch>();
396
397 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 * List of all active broadcasts that are to be executed immediately
399 * (without waiting for another broadcast to finish). Currently this only
400 * contains broadcasts to registered receivers, to avoid spinning up
401 * a bunch of processes to execute IntentReceiver components.
402 */
403 final ArrayList<BroadcastRecord> mParallelBroadcasts
404 = new ArrayList<BroadcastRecord>();
405
406 /**
407 * List of all active broadcasts that are to be executed one at a time.
408 * The object at the top of the list is the currently activity broadcasts;
409 * those after it are waiting for the top to finish..
410 */
411 final ArrayList<BroadcastRecord> mOrderedBroadcasts
412 = new ArrayList<BroadcastRecord>();
413
414 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800415 * Historical data of past broadcasts, for debugging.
416 */
417 static final int MAX_BROADCAST_HISTORY = 100;
418 final BroadcastRecord[] mBroadcastHistory
419 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
420
421 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 * Set when we current have a BROADCAST_INTENT_MSG in flight.
423 */
424 boolean mBroadcastsScheduled = false;
425
426 /**
427 * Set to indicate whether to issue an onUserLeaving callback when a
428 * newly launched activity is being brought in front of us.
429 */
430 boolean mUserLeaving = false;
431
432 /**
433 * When we are in the process of pausing an activity, before starting the
434 * next one, this variable holds the activity that is currently being paused.
435 */
436 HistoryRecord mPausingActivity = null;
437
438 /**
439 * Current activity that is resumed, or null if there is none.
440 */
441 HistoryRecord mResumedActivity = null;
442
443 /**
444 * Activity we have told the window manager to have key focus.
445 */
446 HistoryRecord mFocusedActivity = null;
447
448 /**
449 * This is the last activity that we put into the paused state. This is
450 * used to determine if we need to do an activity transition while sleeping,
451 * when we normally hold the top activity paused.
452 */
453 HistoryRecord mLastPausedActivity = null;
454
455 /**
456 * List of activities that are waiting for a new activity
457 * to become visible before completing whatever operation they are
458 * supposed to do.
459 */
460 final ArrayList mWaitingVisibleActivities = new ArrayList();
461
462 /**
463 * List of activities that are ready to be stopped, but waiting
464 * for the next activity to settle down before doing so. It contains
465 * HistoryRecord objects.
466 */
467 final ArrayList<HistoryRecord> mStoppingActivities
468 = new ArrayList<HistoryRecord>();
469
470 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700471 * Animations that for the current transition have requested not to
472 * be considered for the transition animation.
473 */
474 final ArrayList<HistoryRecord> mNoAnimActivities
475 = new ArrayList<HistoryRecord>();
476
477 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 * List of intents that were used to start the most recent tasks.
479 */
480 final ArrayList<TaskRecord> mRecentTasks
481 = new ArrayList<TaskRecord>();
482
483 /**
484 * List of activities that are ready to be finished, but waiting
485 * for the previous activity to settle down before doing so. It contains
486 * HistoryRecord objects.
487 */
488 final ArrayList mFinishingActivities = new ArrayList();
489
490 /**
491 * All of the applications we currently have running organized by name.
492 * The keys are strings of the application package name (as
493 * returned by the package manager), and the keys are ApplicationRecord
494 * objects.
495 */
496 final ProcessMap<ProcessRecord> mProcessNames
497 = new ProcessMap<ProcessRecord>();
498
499 /**
500 * The last time that various processes have crashed.
501 */
502 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
503
504 /**
505 * Set of applications that we consider to be bad, and will reject
506 * incoming broadcasts from (which the user has no control over).
507 * Processes are added to this set when they have crashed twice within
508 * a minimum amount of time; they are removed from it when they are
509 * later restarted (hopefully due to some user action). The value is the
510 * time it was added to the list.
511 */
512 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
513
514 /**
515 * All of the processes we currently have running organized by pid.
516 * The keys are the pid running the application.
517 *
518 * <p>NOTE: This object is protected by its own lock, NOT the global
519 * activity manager lock!
520 */
521 final SparseArray<ProcessRecord> mPidsSelfLocked
522 = new SparseArray<ProcessRecord>();
523
524 /**
525 * All of the processes that have been forced to be foreground. The key
526 * is the pid of the caller who requested it (we hold a death
527 * link on it).
528 */
529 abstract class ForegroundToken implements IBinder.DeathRecipient {
530 int pid;
531 IBinder token;
532 }
533 final SparseArray<ForegroundToken> mForegroundProcesses
534 = new SparseArray<ForegroundToken>();
535
536 /**
537 * List of records for processes that someone had tried to start before the
538 * system was ready. We don't start them at that point, but ensure they
539 * are started by the time booting is complete.
540 */
541 final ArrayList<ProcessRecord> mProcessesOnHold
542 = new ArrayList<ProcessRecord>();
543
544 /**
545 * List of records for processes that we have started and are waiting
546 * for them to call back. This is really only needed when running in
547 * single processes mode, in which case we do not have a unique pid for
548 * each process.
549 */
550 final ArrayList<ProcessRecord> mStartingProcesses
551 = new ArrayList<ProcessRecord>();
552
553 /**
554 * List of persistent applications that are in the process
555 * of being started.
556 */
557 final ArrayList<ProcessRecord> mPersistentStartingProcesses
558 = new ArrayList<ProcessRecord>();
559
560 /**
561 * Processes that are being forcibly torn down.
562 */
563 final ArrayList<ProcessRecord> mRemovedProcesses
564 = new ArrayList<ProcessRecord>();
565
566 /**
567 * List of running applications, sorted by recent usage.
568 * The first entry in the list is the least recently used.
569 * It contains ApplicationRecord objects. This list does NOT include
570 * any persistent application records (since we never want to exit them).
571 */
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800572 final ArrayList<ProcessRecord> mLruProcesses
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 = new ArrayList<ProcessRecord>();
574
575 /**
576 * List of processes that should gc as soon as things are idle.
577 */
578 final ArrayList<ProcessRecord> mProcessesToGc
579 = new ArrayList<ProcessRecord>();
580
581 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800582 * This is the process holding what we currently consider to be
583 * the "home" activity.
584 */
585 private ProcessRecord mHomeProcess;
586
587 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 * List of running activities, sorted by recent usage.
589 * The first entry in the list is the least recently used.
590 * It contains HistoryRecord objects.
591 */
592 private final ArrayList mLRUActivities = new ArrayList();
593
594 /**
595 * Set of PendingResultRecord objects that are currently active.
596 */
597 final HashSet mPendingResultRecords = new HashSet();
598
599 /**
600 * Set of IntentSenderRecord objects that are currently active.
601 */
602 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
603 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
604
605 /**
606 * Intent broadcast that we have tried to start, but are
607 * waiting for its application's process to be created. We only
608 * need one (instead of a list) because we always process broadcasts
609 * one at a time, so no others can be started while waiting for this
610 * one.
611 */
612 BroadcastRecord mPendingBroadcast = null;
613
614 /**
615 * Keeps track of all IIntentReceivers that have been registered for
616 * broadcasts. Hash keys are the receiver IBinder, hash value is
617 * a ReceiverList.
618 */
619 final HashMap mRegisteredReceivers = new HashMap();
620
621 /**
622 * Resolver for broadcast intents to registered receivers.
623 * Holds BroadcastFilter (subclass of IntentFilter).
624 */
625 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
626 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
627 @Override
628 protected boolean allowFilterResult(
629 BroadcastFilter filter, List<BroadcastFilter> dest) {
630 IBinder target = filter.receiverList.receiver.asBinder();
631 for (int i=dest.size()-1; i>=0; i--) {
632 if (dest.get(i).receiverList.receiver.asBinder() == target) {
633 return false;
634 }
635 }
636 return true;
637 }
638 };
639
640 /**
641 * State of all active sticky broadcasts. Keys are the action of the
642 * sticky Intent, values are an ArrayList of all broadcasted intents with
643 * that action (which should usually be one).
644 */
645 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
646 new HashMap<String, ArrayList<Intent>>();
647
648 /**
649 * All currently running services.
650 */
651 final HashMap<ComponentName, ServiceRecord> mServices =
652 new HashMap<ComponentName, ServiceRecord>();
653
654 /**
655 * All currently running services indexed by the Intent used to start them.
656 */
657 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
658 new HashMap<Intent.FilterComparison, ServiceRecord>();
659
660 /**
661 * All currently bound service connections. Keys are the IBinder of
662 * the client's IServiceConnection.
663 */
664 final HashMap<IBinder, ConnectionRecord> mServiceConnections
665 = new HashMap<IBinder, ConnectionRecord>();
666
667 /**
668 * List of services that we have been asked to start,
669 * but haven't yet been able to. It is used to hold start requests
670 * while waiting for their corresponding application thread to get
671 * going.
672 */
673 final ArrayList<ServiceRecord> mPendingServices
674 = new ArrayList<ServiceRecord>();
675
676 /**
677 * List of services that are scheduled to restart following a crash.
678 */
679 final ArrayList<ServiceRecord> mRestartingServices
680 = new ArrayList<ServiceRecord>();
681
682 /**
683 * List of services that are in the process of being stopped.
684 */
685 final ArrayList<ServiceRecord> mStoppingServices
686 = new ArrayList<ServiceRecord>();
687
688 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700689 * Backup/restore process management
690 */
691 String mBackupAppName = null;
692 BackupRecord mBackupTarget = null;
693
694 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 * List of PendingThumbnailsRecord objects of clients who are still
696 * waiting to receive all of the thumbnails for a task.
697 */
698 final ArrayList mPendingThumbnails = new ArrayList();
699
700 /**
701 * List of HistoryRecord objects that have been finished and must
702 * still report back to a pending thumbnail receiver.
703 */
704 final ArrayList mCancelledThumbnails = new ArrayList();
705
706 /**
707 * All of the currently running global content providers. Keys are a
708 * string containing the provider name and values are a
709 * ContentProviderRecord object containing the data about it. Note
710 * that a single provider may be published under multiple names, so
711 * there may be multiple entries here for a single one in mProvidersByClass.
712 */
713 final HashMap mProvidersByName = new HashMap();
714
715 /**
716 * All of the currently running global content providers. Keys are a
717 * string containing the provider's implementation class and values are a
718 * ContentProviderRecord object containing the data about it.
719 */
720 final HashMap mProvidersByClass = new HashMap();
721
722 /**
723 * List of content providers who have clients waiting for them. The
724 * application is currently being launched and the provider will be
725 * removed from this list once it is published.
726 */
727 final ArrayList mLaunchingProviders = new ArrayList();
728
729 /**
730 * Global set of specific Uri permissions that have been granted.
731 */
732 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
733 = new SparseArray<HashMap<Uri, UriPermission>>();
734
735 /**
736 * Thread-local storage used to carry caller permissions over through
737 * indirect content-provider access.
738 * @see #ActivityManagerService.openContentUri()
739 */
740 private class Identity {
741 public int pid;
742 public int uid;
743
744 Identity(int _pid, int _uid) {
745 pid = _pid;
746 uid = _uid;
747 }
748 }
749 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
750
751 /**
752 * All information we have collected about the runtime performance of
753 * any user id that can impact battery performance.
754 */
755 final BatteryStatsService mBatteryStatsService;
756
757 /**
758 * information about component usage
759 */
760 final UsageStatsService mUsageStatsService;
761
762 /**
763 * Current configuration information. HistoryRecord objects are given
764 * a reference to this object to indicate which configuration they are
765 * currently running in, so this object must be kept immutable.
766 */
767 Configuration mConfiguration = new Configuration();
768
769 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700770 * Hardware-reported OpenGLES version.
771 */
772 final int GL_ES_VERSION;
773
774 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 * List of initialization arguments to pass to all processes when binding applications to them.
776 * For example, references to the commonly used services.
777 */
778 HashMap<String, IBinder> mAppBindArgs;
779
780 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700781 * Temporary to avoid allocations. Protected by main lock.
782 */
783 final StringBuilder mStringBuilder = new StringBuilder(256);
784
785 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 * Used to control how we initialize the service.
787 */
788 boolean mStartRunning = false;
789 ComponentName mTopComponent;
790 String mTopAction;
791 String mTopData;
792 boolean mSystemReady = false;
793 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700794 boolean mWaitingUpdate = false;
795 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796
797 Context mContext;
798
799 int mFactoryTest;
800
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700801 boolean mCheckedForSetup;
802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700804 * The time at which we will allow normal application switches again,
805 * after a call to {@link #stopAppSwitches()}.
806 */
807 long mAppSwitchesAllowedTime;
808
809 /**
810 * This is set to true after the first switch after mAppSwitchesAllowedTime
811 * is set; any switches after that will clear the time.
812 */
813 boolean mDidAppSwitch;
814
815 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 * Set while we are wanting to sleep, to prevent any
817 * activities from being started/resumed.
818 */
819 boolean mSleeping = false;
820
821 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700822 * Set if we are shutting down the system, similar to sleeping.
823 */
824 boolean mShuttingDown = false;
825
826 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 * Set when the system is going to sleep, until we have
828 * successfully paused the current activity and released our wake lock.
829 * At that point the system is allowed to actually sleep.
830 */
831 PowerManager.WakeLock mGoingToSleep;
832
833 /**
834 * We don't want to allow the device to go to sleep while in the process
835 * of launching an activity. This is primarily to allow alarm intent
836 * receivers to launch an activity and get that to run before the device
837 * goes back to sleep.
838 */
839 PowerManager.WakeLock mLaunchingActivity;
840
841 /**
842 * Task identifier that activities are currently being started
843 * in. Incremented each time a new task is created.
844 * todo: Replace this with a TokenSpace class that generates non-repeating
845 * integers that won't wrap.
846 */
847 int mCurTask = 1;
848
849 /**
850 * Current sequence id for oom_adj computation traversal.
851 */
852 int mAdjSeq = 0;
853
854 /**
855 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
856 * is set, indicating the user wants processes started in such a way
857 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
858 * running in each process (thus no pre-initialized process, etc).
859 */
860 boolean mSimpleProcessManagement = false;
861
862 /**
863 * System monitoring: number of processes that died since the last
864 * N procs were started.
865 */
866 int[] mProcDeaths = new int[20];
867
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700868 /**
869 * This is set if we had to do a delayed dexopt of an app before launching
870 * it, to increasing the ANR timeouts in that case.
871 */
872 boolean mDidDexOpt;
873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 String mDebugApp = null;
875 boolean mWaitForDebugger = false;
876 boolean mDebugTransient = false;
877 String mOrigDebugApp = null;
878 boolean mOrigWaitForDebugger = false;
879 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700880 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700882 final RemoteCallbackList<IActivityWatcher> mWatchers
883 = new RemoteCallbackList<IActivityWatcher>();
884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 /**
886 * Callback of last caller to {@link #requestPss}.
887 */
888 Runnable mRequestPssCallback;
889
890 /**
891 * Remaining processes for which we are waiting results from the last
892 * call to {@link #requestPss}.
893 */
894 final ArrayList<ProcessRecord> mRequestPssList
895 = new ArrayList<ProcessRecord>();
896
897 /**
898 * Runtime statistics collection thread. This object's lock is used to
899 * protect all related state.
900 */
901 final Thread mProcessStatsThread;
902
903 /**
904 * Used to collect process stats when showing not responding dialog.
905 * Protected by mProcessStatsThread.
906 */
907 final ProcessStats mProcessStats = new ProcessStats(
908 MONITOR_THREAD_CPU_USAGE);
909 long mLastCpuTime = 0;
910 long mLastWriteTime = 0;
911
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700912 long mInitialStartTime = 0;
913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 /**
915 * Set to true after the system has finished booting.
916 */
917 boolean mBooted = false;
918
919 int mProcessLimit = 0;
920
921 WindowManagerService mWindowManager;
922
923 static ActivityManagerService mSelf;
924 static ActivityThread mSystemThread;
925
926 private final class AppDeathRecipient implements IBinder.DeathRecipient {
927 final ProcessRecord mApp;
928 final int mPid;
929 final IApplicationThread mAppThread;
930
931 AppDeathRecipient(ProcessRecord app, int pid,
932 IApplicationThread thread) {
933 if (localLOGV) Log.v(
934 TAG, "New death recipient " + this
935 + " for thread " + thread.asBinder());
936 mApp = app;
937 mPid = pid;
938 mAppThread = thread;
939 }
940
941 public void binderDied() {
942 if (localLOGV) Log.v(
943 TAG, "Death received in " + this
944 + " for thread " + mAppThread.asBinder());
945 removeRequestedPss(mApp);
946 synchronized(ActivityManagerService.this) {
947 appDiedLocked(mApp, mPid, mAppThread);
948 }
949 }
950 }
951
952 static final int SHOW_ERROR_MSG = 1;
953 static final int SHOW_NOT_RESPONDING_MSG = 2;
954 static final int SHOW_FACTORY_ERROR_MSG = 3;
955 static final int UPDATE_CONFIGURATION_MSG = 4;
956 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
957 static final int WAIT_FOR_DEBUGGER_MSG = 6;
958 static final int BROADCAST_INTENT_MSG = 7;
959 static final int BROADCAST_TIMEOUT_MSG = 8;
960 static final int PAUSE_TIMEOUT_MSG = 9;
961 static final int IDLE_TIMEOUT_MSG = 10;
962 static final int IDLE_NOW_MSG = 11;
963 static final int SERVICE_TIMEOUT_MSG = 12;
964 static final int UPDATE_TIME_ZONE = 13;
965 static final int SHOW_UID_ERROR_MSG = 14;
966 static final int IM_FEELING_LUCKY_MSG = 15;
967 static final int LAUNCH_TIMEOUT_MSG = 16;
968 static final int DESTROY_TIMEOUT_MSG = 17;
969 static final int SERVICE_ERROR_MSG = 18;
970 static final int RESUME_TOP_ACTIVITY_MSG = 19;
971 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700972 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700973 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974
975 AlertDialog mUidAlert;
976
977 final Handler mHandler = new Handler() {
978 //public Handler() {
979 // if (localLOGV) Log.v(TAG, "Handler started!");
980 //}
981
982 public void handleMessage(Message msg) {
983 switch (msg.what) {
984 case SHOW_ERROR_MSG: {
985 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 synchronized (ActivityManagerService.this) {
987 ProcessRecord proc = (ProcessRecord)data.get("app");
988 if (proc != null && proc.crashDialog != null) {
989 Log.e(TAG, "App already has crash dialog: " + proc);
990 return;
991 }
992 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700993 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -0800994 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 d.show();
996 proc.crashDialog = d;
997 } else {
998 // The device is asleep, so just pretend that the user
999 // saw a crash dialog and hit "force quit".
1000 res.set(0);
1001 }
1002 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001003
1004 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 } break;
1006 case SHOW_NOT_RESPONDING_MSG: {
1007 synchronized (ActivityManagerService.this) {
1008 HashMap data = (HashMap) msg.obj;
1009 ProcessRecord proc = (ProcessRecord)data.get("app");
1010 if (proc != null && proc.anrDialog != null) {
1011 Log.e(TAG, "App already has anr dialog: " + proc);
1012 return;
1013 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001014
1015 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1016 null, null, 0, null, null, null,
1017 false, false, MY_PID, Process.SYSTEM_UID);
1018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1020 mContext, proc, (HistoryRecord)data.get("activity"));
1021 d.show();
1022 proc.anrDialog = d;
1023 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001024
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001025 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 } break;
1027 case SHOW_FACTORY_ERROR_MSG: {
1028 Dialog d = new FactoryErrorDialog(
1029 mContext, msg.getData().getCharSequence("msg"));
1030 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001031 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 } break;
1033 case UPDATE_CONFIGURATION_MSG: {
1034 final ContentResolver resolver = mContext.getContentResolver();
1035 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1036 } break;
1037 case GC_BACKGROUND_PROCESSES_MSG: {
1038 synchronized (ActivityManagerService.this) {
1039 performAppGcsIfAppropriateLocked();
1040 }
1041 } break;
1042 case WAIT_FOR_DEBUGGER_MSG: {
1043 synchronized (ActivityManagerService.this) {
1044 ProcessRecord app = (ProcessRecord)msg.obj;
1045 if (msg.arg1 != 0) {
1046 if (!app.waitedForDebugger) {
1047 Dialog d = new AppWaitingForDebuggerDialog(
1048 ActivityManagerService.this,
1049 mContext, app);
1050 app.waitDialog = d;
1051 app.waitedForDebugger = true;
1052 d.show();
1053 }
1054 } else {
1055 if (app.waitDialog != null) {
1056 app.waitDialog.dismiss();
1057 app.waitDialog = null;
1058 }
1059 }
1060 }
1061 } break;
1062 case BROADCAST_INTENT_MSG: {
1063 if (DEBUG_BROADCAST) Log.v(
1064 TAG, "Received BROADCAST_INTENT_MSG");
1065 processNextBroadcast(true);
1066 } break;
1067 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001068 if (mDidDexOpt) {
1069 mDidDexOpt = false;
1070 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1071 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1072 return;
1073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 broadcastTimeout();
1075 } break;
1076 case PAUSE_TIMEOUT_MSG: {
1077 IBinder token = (IBinder)msg.obj;
1078 // We don't at this point know if the activity is fullscreen,
1079 // so we need to be conservative and assume it isn't.
1080 Log.w(TAG, "Activity pause timeout for " + token);
1081 activityPaused(token, null, true);
1082 } break;
1083 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001084 if (mDidDexOpt) {
1085 mDidDexOpt = false;
1086 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1087 nmsg.obj = msg.obj;
1088 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1089 return;
1090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 // We don't at this point know if the activity is fullscreen,
1092 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001093 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001095 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 } break;
1097 case DESTROY_TIMEOUT_MSG: {
1098 IBinder token = (IBinder)msg.obj;
1099 // We don't at this point know if the activity is fullscreen,
1100 // so we need to be conservative and assume it isn't.
1101 Log.w(TAG, "Activity destroy timeout for " + token);
1102 activityDestroyed(token);
1103 } break;
1104 case IDLE_NOW_MSG: {
1105 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001106 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 } break;
1108 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001109 if (mDidDexOpt) {
1110 mDidDexOpt = false;
1111 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1112 nmsg.obj = msg.obj;
1113 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1114 return;
1115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 serviceTimeout((ProcessRecord)msg.obj);
1117 } break;
1118 case UPDATE_TIME_ZONE: {
1119 synchronized (ActivityManagerService.this) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001120 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
1121 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122 if (r.thread != null) {
1123 try {
1124 r.thread.updateTimeZone();
1125 } catch (RemoteException ex) {
1126 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1127 }
1128 }
1129 }
1130 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001131 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 case SHOW_UID_ERROR_MSG: {
1133 // XXX This is a temporary dialog, no need to localize.
1134 AlertDialog d = new BaseErrorDialog(mContext);
1135 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1136 d.setCancelable(false);
1137 d.setTitle("System UIDs Inconsistent");
1138 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1139 d.setButton("I'm Feeling Lucky",
1140 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1141 mUidAlert = d;
1142 d.show();
1143 } break;
1144 case IM_FEELING_LUCKY_MSG: {
1145 if (mUidAlert != null) {
1146 mUidAlert.dismiss();
1147 mUidAlert = null;
1148 }
1149 } break;
1150 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001151 if (mDidDexOpt) {
1152 mDidDexOpt = false;
1153 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1154 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1155 return;
1156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 synchronized (ActivityManagerService.this) {
1158 if (mLaunchingActivity.isHeld()) {
1159 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1160 mLaunchingActivity.release();
1161 }
1162 }
1163 } break;
1164 case SERVICE_ERROR_MSG: {
1165 ServiceRecord srv = (ServiceRecord)msg.obj;
1166 // This needs to be *un*synchronized to avoid deadlock.
1167 Checkin.logEvent(mContext.getContentResolver(),
1168 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1169 srv.name.toShortString());
1170 } break;
1171 case RESUME_TOP_ACTIVITY_MSG: {
1172 synchronized (ActivityManagerService.this) {
1173 resumeTopActivityLocked(null);
1174 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001175 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001177 if (mDidDexOpt) {
1178 mDidDexOpt = false;
1179 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1180 nmsg.obj = msg.obj;
1181 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1182 return;
1183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 ProcessRecord app = (ProcessRecord)msg.obj;
1185 synchronized (ActivityManagerService.this) {
1186 processStartTimedOutLocked(app);
1187 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001188 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001189 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1190 synchronized (ActivityManagerService.this) {
1191 doPendingActivityLaunchesLocked(true);
1192 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001193 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001194 case KILL_APPLICATION_MSG: {
1195 synchronized (ActivityManagerService.this) {
1196 int uid = msg.arg1;
1197 boolean restart = (msg.arg2 == 1);
1198 String pkg = (String) msg.obj;
Dianne Hackborn03abb812010-01-04 18:43:19 -08001199 forceStopPackageLocked(pkg, uid, restart);
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001200 }
1201 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 }
1203 }
1204 };
1205
1206 public static void setSystemProcess() {
1207 try {
1208 ActivityManagerService m = mSelf;
1209
1210 ServiceManager.addService("activity", m);
1211 ServiceManager.addService("meminfo", new MemBinder(m));
1212 if (MONITOR_CPU_USAGE) {
1213 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1214 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 ServiceManager.addService("permission", new PermissionController(m));
1216
1217 ApplicationInfo info =
1218 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001219 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001220 mSystemThread.installSystemApplicationInfo(info);
1221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 synchronized (mSelf) {
1223 ProcessRecord app = mSelf.newProcessRecordLocked(
1224 mSystemThread.getApplicationThread(), info,
1225 info.processName);
1226 app.persistent = true;
Dan Egnor42471dd2010-01-07 17:25:22 -08001227 app.pid = MY_PID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 app.maxAdj = SYSTEM_ADJ;
1229 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1230 synchronized (mSelf.mPidsSelfLocked) {
1231 mSelf.mPidsSelfLocked.put(app.pid, app);
1232 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001233 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 }
1235 } catch (PackageManager.NameNotFoundException e) {
1236 throw new RuntimeException(
1237 "Unable to find android system package", e);
1238 }
1239 }
1240
1241 public void setWindowManager(WindowManagerService wm) {
1242 mWindowManager = wm;
1243 }
1244
1245 public static final Context main(int factoryTest) {
1246 AThread thr = new AThread();
1247 thr.start();
1248
1249 synchronized (thr) {
1250 while (thr.mService == null) {
1251 try {
1252 thr.wait();
1253 } catch (InterruptedException e) {
1254 }
1255 }
1256 }
1257
1258 ActivityManagerService m = thr.mService;
1259 mSelf = m;
1260 ActivityThread at = ActivityThread.systemMain();
1261 mSystemThread = at;
1262 Context context = at.getSystemContext();
1263 m.mContext = context;
1264 m.mFactoryTest = factoryTest;
1265 PowerManager pm =
1266 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1267 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1268 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1269 m.mLaunchingActivity.setReferenceCounted(false);
1270
1271 m.mBatteryStatsService.publish(context);
1272 m.mUsageStatsService.publish(context);
1273
1274 synchronized (thr) {
1275 thr.mReady = true;
1276 thr.notifyAll();
1277 }
1278
1279 m.startRunning(null, null, null, null);
1280
1281 return context;
1282 }
1283
1284 public static ActivityManagerService self() {
1285 return mSelf;
1286 }
1287
1288 static class AThread extends Thread {
1289 ActivityManagerService mService;
1290 boolean mReady = false;
1291
1292 public AThread() {
1293 super("ActivityManager");
1294 }
1295
1296 public void run() {
1297 Looper.prepare();
1298
1299 android.os.Process.setThreadPriority(
1300 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1301
1302 ActivityManagerService m = new ActivityManagerService();
1303
1304 synchronized (this) {
1305 mService = m;
1306 notifyAll();
1307 }
1308
1309 synchronized (this) {
1310 while (!mReady) {
1311 try {
1312 wait();
1313 } catch (InterruptedException e) {
1314 }
1315 }
1316 }
1317
1318 Looper.loop();
1319 }
1320 }
1321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 static class MemBinder extends Binder {
1323 ActivityManagerService mActivityManagerService;
1324 MemBinder(ActivityManagerService activityManagerService) {
1325 mActivityManagerService = activityManagerService;
1326 }
1327
1328 @Override
1329 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1330 ActivityManagerService service = mActivityManagerService;
1331 ArrayList<ProcessRecord> procs;
1332 synchronized (mActivityManagerService) {
1333 if (args != null && args.length > 0
1334 && args[0].charAt(0) != '-') {
1335 procs = new ArrayList<ProcessRecord>();
1336 int pid = -1;
1337 try {
1338 pid = Integer.parseInt(args[0]);
1339 } catch (NumberFormatException e) {
1340
1341 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001342 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1343 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 if (proc.pid == pid) {
1345 procs.add(proc);
1346 } else if (proc.processName.equals(args[0])) {
1347 procs.add(proc);
1348 }
1349 }
1350 if (procs.size() <= 0) {
1351 pw.println("No process found for: " + args[0]);
1352 return;
1353 }
1354 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001355 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 }
1357 }
1358 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1359 }
1360 }
1361
1362 static class CpuBinder extends Binder {
1363 ActivityManagerService mActivityManagerService;
1364 CpuBinder(ActivityManagerService activityManagerService) {
1365 mActivityManagerService = activityManagerService;
1366 }
1367
1368 @Override
1369 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1370 synchronized (mActivityManagerService.mProcessStatsThread) {
1371 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1372 }
1373 }
1374 }
1375
1376 private ActivityManagerService() {
1377 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1378 if (v != null && Integer.getInteger(v) != 0) {
1379 mSimpleProcessManagement = true;
1380 }
1381 v = System.getenv("ANDROID_DEBUG_APP");
1382 if (v != null) {
1383 mSimpleProcessManagement = true;
1384 }
1385
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001386 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 File dataDir = Environment.getDataDirectory();
1389 File systemDir = new File(dataDir, "system");
1390 systemDir.mkdirs();
1391 mBatteryStatsService = new BatteryStatsService(new File(
1392 systemDir, "batterystats.bin").toString());
1393 mBatteryStatsService.getActiveStatistics().readLocked();
1394 mBatteryStatsService.getActiveStatistics().writeLocked();
1395
1396 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001397 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398
Jack Palevichb90d28c2009-07-22 15:35:24 -07001399 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1400 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 mConfiguration.makeDefault();
1403 mProcessStats.init();
1404
1405 // Add ourself to the Watchdog monitors.
1406 Watchdog.getInstance().addMonitor(this);
1407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 mProcessStatsThread = new Thread("ProcessStats") {
1409 public void run() {
1410 while (true) {
1411 try {
1412 try {
1413 synchronized(this) {
1414 final long now = SystemClock.uptimeMillis();
1415 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1416 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1417 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1418 // + ", write delay=" + nextWriteDelay);
1419 if (nextWriteDelay < nextCpuDelay) {
1420 nextCpuDelay = nextWriteDelay;
1421 }
1422 if (nextCpuDelay > 0) {
1423 this.wait(nextCpuDelay);
1424 }
1425 }
1426 } catch (InterruptedException e) {
1427 }
1428
1429 updateCpuStatsNow();
1430 } catch (Exception e) {
1431 Log.e(TAG, "Unexpected exception collecting process stats", e);
1432 }
1433 }
1434 }
1435 };
1436 mProcessStatsThread.start();
1437 }
1438
1439 @Override
1440 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1441 throws RemoteException {
1442 try {
1443 return super.onTransact(code, data, reply, flags);
1444 } catch (RuntimeException e) {
1445 // The activity manager only throws security exceptions, so let's
1446 // log all others.
1447 if (!(e instanceof SecurityException)) {
1448 Log.e(TAG, "Activity Manager Crash", e);
1449 }
1450 throw e;
1451 }
1452 }
1453
1454 void updateCpuStats() {
1455 synchronized (mProcessStatsThread) {
1456 final long now = SystemClock.uptimeMillis();
1457 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1458 mProcessStatsThread.notify();
1459 }
1460 }
1461 }
1462
1463 void updateCpuStatsNow() {
1464 synchronized (mProcessStatsThread) {
1465 final long now = SystemClock.uptimeMillis();
1466 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 if (MONITOR_CPU_USAGE &&
1469 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1470 mLastCpuTime = now;
1471 haveNewCpuStats = true;
1472 mProcessStats.update();
1473 //Log.i(TAG, mProcessStats.printCurrentState());
1474 //Log.i(TAG, "Total CPU usage: "
1475 // + mProcessStats.getTotalCpuPercent() + "%");
1476
1477 // Log the cpu usage if the property is set.
1478 if ("true".equals(SystemProperties.get("events.cpu"))) {
1479 int user = mProcessStats.getLastUserTime();
1480 int system = mProcessStats.getLastSystemTime();
1481 int iowait = mProcessStats.getLastIoWaitTime();
1482 int irq = mProcessStats.getLastIrqTime();
1483 int softIrq = mProcessStats.getLastSoftIrqTime();
1484 int idle = mProcessStats.getLastIdleTime();
1485
1486 int total = user + system + iowait + irq + softIrq + idle;
1487 if (total == 0) total = 1;
1488
Doug Zongker2bec3d42009-12-04 12:52:44 -08001489 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 ((user+system+iowait+irq+softIrq) * 100) / total,
1491 (user * 100) / total,
1492 (system * 100) / total,
1493 (iowait * 100) / total,
1494 (irq * 100) / total,
1495 (softIrq * 100) / total);
1496 }
1497 }
1498
Amith Yamasanie43530a2009-08-21 13:11:37 -07001499 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001500 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001501 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 synchronized(mPidsSelfLocked) {
1503 if (haveNewCpuStats) {
1504 if (mBatteryStatsService.isOnBattery()) {
1505 final int N = mProcessStats.countWorkingStats();
1506 for (int i=0; i<N; i++) {
1507 ProcessStats.Stats st
1508 = mProcessStats.getWorkingStats(i);
1509 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1510 if (pr != null) {
1511 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1512 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001513 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001514 } else {
1515 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001516 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001517 if (ps != null) {
1518 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001519 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 }
1522 }
1523 }
1524 }
1525 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1528 mLastWriteTime = now;
1529 mBatteryStatsService.getActiveStatistics().writeLocked();
1530 }
1531 }
1532 }
1533 }
1534
1535 /**
1536 * Initialize the application bind args. These are passed to each
1537 * process when the bindApplication() IPC is sent to the process. They're
1538 * lazily setup to make sure the services are running when they're asked for.
1539 */
1540 private HashMap<String, IBinder> getCommonServicesLocked() {
1541 if (mAppBindArgs == null) {
1542 mAppBindArgs = new HashMap<String, IBinder>();
1543
1544 // Setup the application init args
1545 mAppBindArgs.put("package", ServiceManager.getService("package"));
1546 mAppBindArgs.put("window", ServiceManager.getService("window"));
1547 mAppBindArgs.put(Context.ALARM_SERVICE,
1548 ServiceManager.getService(Context.ALARM_SERVICE));
1549 }
1550 return mAppBindArgs;
1551 }
1552
1553 private final void setFocusedActivityLocked(HistoryRecord r) {
1554 if (mFocusedActivity != r) {
1555 mFocusedActivity = r;
1556 mWindowManager.setFocusedApp(r, true);
1557 }
1558 }
1559
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001560 private final void updateLruProcessLocked(ProcessRecord app,
1561 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001563 int lrui = mLruProcesses.indexOf(app);
1564 if (lrui >= 0) mLruProcesses.remove(lrui);
1565
1566 int i = mLruProcesses.size()-1;
1567 int skipTop = 0;
1568
1569 // compute the new weight for this process.
1570 if (updateActivityTime) {
1571 app.lastActivityTime = SystemClock.uptimeMillis();
1572 }
1573 if (app.activities.size() > 0) {
1574 // If this process has activities, we more strongly want to keep
1575 // it around.
1576 app.lruWeight = app.lastActivityTime;
1577 } else if (app.pubProviders.size() > 0) {
1578 // If this process contains content providers, we want to keep
1579 // it a little more strongly.
1580 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1581 // Also don't let it kick out the first few "real" hidden processes.
1582 skipTop = MIN_HIDDEN_APPS;
1583 } else {
1584 // If this process doesn't have activities, we less strongly
1585 // want to keep it around, and generally want to avoid getting
1586 // in front of any very recently used activities.
1587 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1588 // Also don't let it kick out the first few "real" hidden processes.
1589 skipTop = MIN_HIDDEN_APPS;
1590 }
1591 while (i >= 0) {
1592 ProcessRecord p = mLruProcesses.get(i);
1593 // If this app shouldn't be in front of the first N background
1594 // apps, then skip over that many that are currently hidden.
1595 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1596 skipTop--;
1597 }
1598 if (p.lruWeight <= app.lruWeight){
1599 mLruProcesses.add(i+1, app);
1600 break;
1601 }
1602 i--;
1603 }
1604 if (i < 0) {
1605 mLruProcesses.add(0, app);
1606 }
1607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 //Log.i(TAG, "Putting proc to front: " + app.processName);
1609 if (oomAdj) {
1610 updateOomAdjLocked();
1611 }
1612 }
1613
1614 private final boolean updateLRUListLocked(HistoryRecord r) {
1615 final boolean hadit = mLRUActivities.remove(r);
1616 mLRUActivities.add(r);
1617 return hadit;
1618 }
1619
1620 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1621 int i = mHistory.size()-1;
1622 while (i >= 0) {
1623 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1624 if (!r.finishing && r != notTop) {
1625 return r;
1626 }
1627 i--;
1628 }
1629 return null;
1630 }
1631
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001632 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1633 int i = mHistory.size()-1;
1634 while (i >= 0) {
1635 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1636 if (!r.finishing && !r.delayedResume && r != notTop) {
1637 return r;
1638 }
1639 i--;
1640 }
1641 return null;
1642 }
1643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 /**
1645 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001646 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 *
1648 * @param token If non-null, any history records matching this token will be skipped.
1649 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1650 *
1651 * @return Returns the HistoryRecord of the next activity on the stack.
1652 */
1653 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1654 int i = mHistory.size()-1;
1655 while (i >= 0) {
1656 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1657 // Note: the taskId check depends on real taskId fields being non-zero
1658 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1659 return r;
1660 }
1661 i--;
1662 }
1663 return null;
1664 }
1665
1666 private final ProcessRecord getProcessRecordLocked(
1667 String processName, int uid) {
1668 if (uid == Process.SYSTEM_UID) {
1669 // The system gets to run in any process. If there are multiple
1670 // processes with the same uid, just pick the first (this
1671 // should never happen).
1672 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1673 processName);
1674 return procs != null ? procs.valueAt(0) : null;
1675 }
1676 ProcessRecord proc = mProcessNames.get(processName, uid);
1677 return proc;
1678 }
1679
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001680 private void ensurePackageDexOpt(String packageName) {
1681 IPackageManager pm = ActivityThread.getPackageManager();
1682 try {
1683 if (pm.performDexOpt(packageName)) {
1684 mDidDexOpt = true;
1685 }
1686 } catch (RemoteException e) {
1687 }
1688 }
1689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 private boolean isNextTransitionForward() {
1691 int transit = mWindowManager.getPendingAppTransition();
1692 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1693 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1694 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1695 }
1696
1697 private final boolean realStartActivityLocked(HistoryRecord r,
1698 ProcessRecord app, boolean andResume, boolean checkConfig)
1699 throws RemoteException {
1700
1701 r.startFreezingScreenLocked(app, 0);
1702 mWindowManager.setAppVisibility(r, true);
1703
1704 // Have the window manager re-evaluate the orientation of
1705 // the screen based on the new activity order. Note that
1706 // as a result of this, it can call back into the activity
1707 // manager with a new orientation. We don't care about that,
1708 // because the activity is not currently running so we are
1709 // just restarting it anyway.
1710 if (checkConfig) {
1711 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001712 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 r.mayFreezeScreenLocked(app) ? r : null);
1714 updateConfigurationLocked(config, r);
1715 }
1716
1717 r.app = app;
1718
1719 if (localLOGV) Log.v(TAG, "Launching: " + r);
1720
1721 int idx = app.activities.indexOf(r);
1722 if (idx < 0) {
1723 app.activities.add(r);
1724 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001725 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726
1727 try {
1728 if (app.thread == null) {
1729 throw new RemoteException();
1730 }
1731 List<ResultInfo> results = null;
1732 List<Intent> newIntents = null;
1733 if (andResume) {
1734 results = r.results;
1735 newIntents = r.newIntents;
1736 }
1737 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1738 + " icicle=" + r.icicle
1739 + " with results=" + results + " newIntents=" + newIntents
1740 + " andResume=" + andResume);
1741 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001742 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 System.identityHashCode(r),
1744 r.task.taskId, r.shortComponentName);
1745 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001746 if (r.isHomeActivity) {
1747 mHomeProcess = app;
1748 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001749 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001751 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 r.info, r.icicle, results, newIntents, !andResume,
1753 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 } catch (RemoteException e) {
1755 if (r.launchFailed) {
1756 // This is the second time we failed -- finish activity
1757 // and give up.
1758 Log.e(TAG, "Second failure launching "
1759 + r.intent.getComponent().flattenToShortString()
1760 + ", giving up", e);
1761 appDiedLocked(app, app.pid, app.thread);
1762 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1763 "2nd-crash");
1764 return false;
1765 }
1766
1767 // This is the first time we failed -- restart process and
1768 // retry.
1769 app.activities.remove(r);
1770 throw e;
1771 }
1772
1773 r.launchFailed = false;
1774 if (updateLRUListLocked(r)) {
1775 Log.w(TAG, "Activity " + r
1776 + " being launched, but already in LRU list");
1777 }
1778
1779 if (andResume) {
1780 // As part of the process of launching, ActivityThread also performs
1781 // a resume.
1782 r.state = ActivityState.RESUMED;
1783 r.icicle = null;
1784 r.haveState = false;
1785 r.stopped = false;
1786 mResumedActivity = r;
1787 r.task.touchActiveTime();
1788 completeResumeLocked(r);
1789 pauseIfSleepingLocked();
1790 } else {
1791 // This activity is not starting in the resumed state... which
1792 // should look like we asked it to pause+stop (but remain visible),
1793 // and it has done so and reported back the current icicle and
1794 // other state.
1795 r.state = ActivityState.STOPPED;
1796 r.stopped = true;
1797 }
1798
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001799 // Launch the new version setup screen if needed. We do this -after-
1800 // launching the initial activity (that is, home), so that it can have
1801 // a chance to initialize itself while in the background, making the
1802 // switch back to it faster and look better.
1803 startSetupActivityLocked();
1804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 return true;
1806 }
1807
1808 private final void startSpecificActivityLocked(HistoryRecord r,
1809 boolean andResume, boolean checkConfig) {
1810 // Is this activity's application already running?
1811 ProcessRecord app = getProcessRecordLocked(r.processName,
1812 r.info.applicationInfo.uid);
1813
1814 if (r.startTime == 0) {
1815 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001816 if (mInitialStartTime == 0) {
1817 mInitialStartTime = r.startTime;
1818 }
1819 } else if (mInitialStartTime == 0) {
1820 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 }
1822
1823 if (app != null && app.thread != null) {
1824 try {
1825 realStartActivityLocked(r, app, andResume, checkConfig);
1826 return;
1827 } catch (RemoteException e) {
1828 Log.w(TAG, "Exception when starting activity "
1829 + r.intent.getComponent().flattenToShortString(), e);
1830 }
1831
1832 // If a dead object exception was thrown -- fall through to
1833 // restart the application.
1834 }
1835
1836 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001837 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 }
1839
1840 private final ProcessRecord startProcessLocked(String processName,
1841 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001842 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1844 // We don't have to do anything more if:
1845 // (1) There is an existing application record; and
1846 // (2) The caller doesn't think it is dead, OR there is no thread
1847 // object attached to it so we know it couldn't have crashed; and
1848 // (3) There is a pid assigned to it, so it is either starting or
1849 // already running.
1850 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1851 + " app=" + app + " knownToBeDead=" + knownToBeDead
1852 + " thread=" + (app != null ? app.thread : null)
1853 + " pid=" + (app != null ? app.pid : -1));
1854 if (app != null &&
1855 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1856 return app;
1857 }
1858
1859 String hostingNameStr = hostingName != null
1860 ? hostingName.flattenToShortString() : null;
1861
1862 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1863 // If we are in the background, then check to see if this process
1864 // is bad. If so, we will just silently fail.
1865 if (mBadProcesses.get(info.processName, info.uid) != null) {
1866 return null;
1867 }
1868 } else {
1869 // When the user is explicitly starting a process, then clear its
1870 // crash count so that we won't make it bad until they see at
1871 // least one crash dialog again, and make the process good again
1872 // if it had been bad.
1873 mProcessCrashTimes.remove(info.processName, info.uid);
1874 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001875 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 info.processName);
1877 mBadProcesses.remove(info.processName, info.uid);
1878 if (app != null) {
1879 app.bad = false;
1880 }
1881 }
1882 }
1883
1884 if (app == null) {
1885 app = newProcessRecordLocked(null, info, processName);
1886 mProcessNames.put(processName, info.uid, app);
1887 } else {
1888 // If this is a new package in the process, add the package to the list
1889 app.addPackage(info.packageName);
1890 }
1891
1892 // If the system is not ready yet, then hold off on starting this
1893 // process until it is.
1894 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001895 && !isAllowedWhileBooting(info)
1896 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 if (!mProcessesOnHold.contains(app)) {
1898 mProcessesOnHold.add(app);
1899 }
1900 return app;
1901 }
1902
1903 startProcessLocked(app, hostingType, hostingNameStr);
1904 return (app.pid != 0) ? app : null;
1905 }
1906
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001907 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1908 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1909 }
1910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 private final void startProcessLocked(ProcessRecord app,
1912 String hostingType, String hostingNameStr) {
1913 if (app.pid > 0 && app.pid != MY_PID) {
1914 synchronized (mPidsSelfLocked) {
1915 mPidsSelfLocked.remove(app.pid);
1916 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1917 }
1918 app.pid = 0;
1919 }
1920
1921 mProcessesOnHold.remove(app);
1922
1923 updateCpuStats();
1924
1925 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1926 mProcDeaths[0] = 0;
1927
1928 try {
1929 int uid = app.info.uid;
1930 int[] gids = null;
1931 try {
1932 gids = mContext.getPackageManager().getPackageGids(
1933 app.info.packageName);
1934 } catch (PackageManager.NameNotFoundException e) {
1935 Log.w(TAG, "Unable to retrieve gids", e);
1936 }
1937 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1938 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1939 && mTopComponent != null
1940 && app.processName.equals(mTopComponent.getPackageName())) {
1941 uid = 0;
1942 }
1943 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1944 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1945 uid = 0;
1946 }
1947 }
1948 int debugFlags = 0;
1949 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1950 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1951 }
1952 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1953 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1954 }
1955 if ("1".equals(SystemProperties.get("debug.assert"))) {
1956 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1957 }
1958 int pid = Process.start("android.app.ActivityThread",
1959 mSimpleProcessManagement ? app.processName : null, uid, uid,
1960 gids, debugFlags, null);
1961 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1962 synchronized (bs) {
1963 if (bs.isOnBattery()) {
1964 app.batteryStats.incStartsLocked();
1965 }
1966 }
1967
Doug Zongker2bec3d42009-12-04 12:52:44 -08001968 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 app.processName, hostingType,
1970 hostingNameStr != null ? hostingNameStr : "");
1971
1972 if (app.persistent) {
1973 Watchdog.getInstance().processStarted(app, app.processName, pid);
1974 }
1975
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001976 StringBuilder buf = mStringBuilder;
1977 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 buf.append("Start proc ");
1979 buf.append(app.processName);
1980 buf.append(" for ");
1981 buf.append(hostingType);
1982 if (hostingNameStr != null) {
1983 buf.append(" ");
1984 buf.append(hostingNameStr);
1985 }
1986 buf.append(": pid=");
1987 buf.append(pid);
1988 buf.append(" uid=");
1989 buf.append(uid);
1990 buf.append(" gids={");
1991 if (gids != null) {
1992 for (int gi=0; gi<gids.length; gi++) {
1993 if (gi != 0) buf.append(", ");
1994 buf.append(gids[gi]);
1995
1996 }
1997 }
1998 buf.append("}");
1999 Log.i(TAG, buf.toString());
2000 if (pid == 0 || pid == MY_PID) {
2001 // Processes are being emulated with threads.
2002 app.pid = MY_PID;
2003 app.removed = false;
2004 mStartingProcesses.add(app);
2005 } else if (pid > 0) {
2006 app.pid = pid;
2007 app.removed = false;
2008 synchronized (mPidsSelfLocked) {
2009 this.mPidsSelfLocked.put(pid, app);
2010 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2011 msg.obj = app;
2012 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2013 }
2014 } else {
2015 app.pid = 0;
2016 RuntimeException e = new RuntimeException(
2017 "Failure starting process " + app.processName
2018 + ": returned pid=" + pid);
2019 Log.e(TAG, e.getMessage(), e);
2020 }
2021 } catch (RuntimeException e) {
2022 // XXX do better error recovery.
2023 app.pid = 0;
2024 Log.e(TAG, "Failure starting process " + app.processName, e);
2025 }
2026 }
2027
2028 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2029 if (mPausingActivity != null) {
2030 RuntimeException e = new RuntimeException();
2031 Log.e(TAG, "Trying to pause when pause is already pending for "
2032 + mPausingActivity, e);
2033 }
2034 HistoryRecord prev = mResumedActivity;
2035 if (prev == null) {
2036 RuntimeException e = new RuntimeException();
2037 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2038 resumeTopActivityLocked(null);
2039 return;
2040 }
2041 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2042 mResumedActivity = null;
2043 mPausingActivity = prev;
2044 mLastPausedActivity = prev;
2045 prev.state = ActivityState.PAUSING;
2046 prev.task.touchActiveTime();
2047
2048 updateCpuStats();
2049
2050 if (prev.app != null && prev.app.thread != null) {
2051 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2052 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002053 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 System.identityHashCode(prev),
2055 prev.shortComponentName);
2056 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2057 prev.configChangeFlags);
2058 updateUsageStats(prev, false);
2059 } catch (Exception e) {
2060 // Ignore exception, if process died other code will cleanup.
2061 Log.w(TAG, "Exception thrown during pause", e);
2062 mPausingActivity = null;
2063 mLastPausedActivity = null;
2064 }
2065 } else {
2066 mPausingActivity = null;
2067 mLastPausedActivity = null;
2068 }
2069
2070 // If we are not going to sleep, we want to ensure the device is
2071 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002072 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 mLaunchingActivity.acquire();
2074 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2075 // To be safe, don't allow the wake lock to be held for too long.
2076 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2077 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2078 }
2079 }
2080
2081
2082 if (mPausingActivity != null) {
2083 // Have the window manager pause its key dispatching until the new
2084 // activity has started. If we're pausing the activity just because
2085 // the screen is being turned off and the UI is sleeping, don't interrupt
2086 // key dispatch; the same activity will pick it up again on wakeup.
2087 if (!uiSleeping) {
2088 prev.pauseKeyDispatchingLocked();
2089 } else {
2090 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2091 }
2092
2093 // Schedule a pause timeout in case the app doesn't respond.
2094 // We don't give it much time because this directly impacts the
2095 // responsiveness seen by the user.
2096 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2097 msg.obj = prev;
2098 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2099 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2100 } else {
2101 // This activity failed to schedule the
2102 // pause, so just treat it as being paused now.
2103 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2104 resumeTopActivityLocked(null);
2105 }
2106 }
2107
2108 private final void completePauseLocked() {
2109 HistoryRecord prev = mPausingActivity;
2110 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2111
2112 if (prev != null) {
2113 if (prev.finishing) {
2114 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2115 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2116 } else if (prev.app != null) {
2117 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2118 if (prev.waitingVisible) {
2119 prev.waitingVisible = false;
2120 mWaitingVisibleActivities.remove(prev);
2121 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2122 TAG, "Complete pause, no longer waiting: " + prev);
2123 }
2124 if (prev.configDestroy) {
2125 // The previous is being paused because the configuration
2126 // is changing, which means it is actually stopping...
2127 // To juggle the fact that we are also starting a new
2128 // instance right now, we need to first completely stop
2129 // the current instance before starting the new one.
2130 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2131 destroyActivityLocked(prev, true);
2132 } else {
2133 mStoppingActivities.add(prev);
2134 if (mStoppingActivities.size() > 3) {
2135 // If we already have a few activities waiting to stop,
2136 // then give up on things going idle and start clearing
2137 // them out.
2138 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2139 Message msg = Message.obtain();
2140 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2141 mHandler.sendMessage(msg);
2142 }
2143 }
2144 } else {
2145 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2146 prev = null;
2147 }
2148 mPausingActivity = null;
2149 }
2150
Dianne Hackborn55280a92009-05-07 15:53:46 -07002151 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 resumeTopActivityLocked(prev);
2153 } else {
2154 if (mGoingToSleep.isHeld()) {
2155 mGoingToSleep.release();
2156 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002157 if (mShuttingDown) {
2158 notifyAll();
2159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 }
2161
2162 if (prev != null) {
2163 prev.resumeKeyDispatchingLocked();
2164 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002165
2166 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2167 long diff = 0;
2168 synchronized (mProcessStatsThread) {
2169 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2170 }
2171 if (diff > 0) {
2172 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2173 synchronized (bsi) {
2174 BatteryStatsImpl.Uid.Proc ps =
2175 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2176 prev.info.packageName);
2177 if (ps != null) {
2178 ps.addForegroundTimeLocked(diff);
2179 }
2180 }
2181 }
2182 }
2183 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 }
2185
2186 /**
2187 * Once we know that we have asked an application to put an activity in
2188 * the resumed state (either by launching it or explicitly telling it),
2189 * this function updates the rest of our state to match that fact.
2190 */
2191 private final void completeResumeLocked(HistoryRecord next) {
2192 next.idle = false;
2193 next.results = null;
2194 next.newIntents = null;
2195
2196 // schedule an idle timeout in case the app doesn't do it for us.
2197 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2198 msg.obj = next;
2199 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2200
2201 if (false) {
2202 // The activity was never told to pause, so just keep
2203 // things going as-is. To maintain our own state,
2204 // we need to emulate it coming back and saying it is
2205 // idle.
2206 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2207 msg.obj = next;
2208 mHandler.sendMessage(msg);
2209 }
2210
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002211 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 next.thumbnail = null;
2214 setFocusedActivityLocked(next);
2215 next.resumeKeyDispatchingLocked();
2216 ensureActivitiesVisibleLocked(null, 0);
2217 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002218 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002219
2220 // Mark the point when the activity is resuming
2221 // TODO: To be more accurate, the mark should be before the onCreate,
2222 // not after the onResume. But for subsequent starts, onResume is fine.
2223 if (next.app != null) {
2224 synchronized (mProcessStatsThread) {
2225 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2226 }
2227 } else {
2228 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002230 }
2231
2232 /**
2233 * Make sure that all activities that need to be visible (that is, they
2234 * currently can be seen by the user) actually are.
2235 */
2236 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2237 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2238 if (DEBUG_VISBILITY) Log.v(
2239 TAG, "ensureActivitiesVisible behind " + top
2240 + " configChanges=0x" + Integer.toHexString(configChanges));
2241
2242 // If the top activity is not fullscreen, then we need to
2243 // make sure any activities under it are now visible.
2244 final int count = mHistory.size();
2245 int i = count-1;
2246 while (mHistory.get(i) != top) {
2247 i--;
2248 }
2249 HistoryRecord r;
2250 boolean behindFullscreen = false;
2251 for (; i>=0; i--) {
2252 r = (HistoryRecord)mHistory.get(i);
2253 if (DEBUG_VISBILITY) Log.v(
2254 TAG, "Make visible? " + r + " finishing=" + r.finishing
2255 + " state=" + r.state);
2256 if (r.finishing) {
2257 continue;
2258 }
2259
2260 final boolean doThisProcess = onlyThisProcess == null
2261 || onlyThisProcess.equals(r.processName);
2262
2263 // First: if this is not the current activity being started, make
2264 // sure it matches the current configuration.
2265 if (r != starting && doThisProcess) {
2266 ensureActivityConfigurationLocked(r, 0);
2267 }
2268
2269 if (r.app == null || r.app.thread == null) {
2270 if (onlyThisProcess == null
2271 || onlyThisProcess.equals(r.processName)) {
2272 // This activity needs to be visible, but isn't even
2273 // running... get it started, but don't resume it
2274 // at this point.
2275 if (DEBUG_VISBILITY) Log.v(
2276 TAG, "Start and freeze screen for " + r);
2277 if (r != starting) {
2278 r.startFreezingScreenLocked(r.app, configChanges);
2279 }
2280 if (!r.visible) {
2281 if (DEBUG_VISBILITY) Log.v(
2282 TAG, "Starting and making visible: " + r);
2283 mWindowManager.setAppVisibility(r, true);
2284 }
2285 if (r != starting) {
2286 startSpecificActivityLocked(r, false, false);
2287 }
2288 }
2289
2290 } else if (r.visible) {
2291 // If this activity is already visible, then there is nothing
2292 // else to do here.
2293 if (DEBUG_VISBILITY) Log.v(
2294 TAG, "Skipping: already visible at " + r);
2295 r.stopFreezingScreenLocked(false);
2296
2297 } else if (onlyThisProcess == null) {
2298 // This activity is not currently visible, but is running.
2299 // Tell it to become visible.
2300 r.visible = true;
2301 if (r.state != ActivityState.RESUMED && r != starting) {
2302 // If this activity is paused, tell it
2303 // to now show its window.
2304 if (DEBUG_VISBILITY) Log.v(
2305 TAG, "Making visible and scheduling visibility: " + r);
2306 try {
2307 mWindowManager.setAppVisibility(r, true);
2308 r.app.thread.scheduleWindowVisibility(r, true);
2309 r.stopFreezingScreenLocked(false);
2310 } catch (Exception e) {
2311 // Just skip on any failure; we'll make it
2312 // visible when it next restarts.
2313 Log.w(TAG, "Exception thrown making visibile: "
2314 + r.intent.getComponent(), e);
2315 }
2316 }
2317 }
2318
2319 // Aggregate current change flags.
2320 configChanges |= r.configChangeFlags;
2321
2322 if (r.fullscreen) {
2323 // At this point, nothing else needs to be shown
2324 if (DEBUG_VISBILITY) Log.v(
2325 TAG, "Stopping: fullscreen at " + r);
2326 behindFullscreen = true;
2327 i--;
2328 break;
2329 }
2330 }
2331
2332 // Now for any activities that aren't visible to the user, make
2333 // sure they no longer are keeping the screen frozen.
2334 while (i >= 0) {
2335 r = (HistoryRecord)mHistory.get(i);
2336 if (DEBUG_VISBILITY) Log.v(
2337 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2338 + " state=" + r.state
2339 + " behindFullscreen=" + behindFullscreen);
2340 if (!r.finishing) {
2341 if (behindFullscreen) {
2342 if (r.visible) {
2343 if (DEBUG_VISBILITY) Log.v(
2344 TAG, "Making invisible: " + r);
2345 r.visible = false;
2346 try {
2347 mWindowManager.setAppVisibility(r, false);
2348 if ((r.state == ActivityState.STOPPING
2349 || r.state == ActivityState.STOPPED)
2350 && r.app != null && r.app.thread != null) {
2351 if (DEBUG_VISBILITY) Log.v(
2352 TAG, "Scheduling invisibility: " + r);
2353 r.app.thread.scheduleWindowVisibility(r, false);
2354 }
2355 } catch (Exception e) {
2356 // Just skip on any failure; we'll make it
2357 // visible when it next restarts.
2358 Log.w(TAG, "Exception thrown making hidden: "
2359 + r.intent.getComponent(), e);
2360 }
2361 } else {
2362 if (DEBUG_VISBILITY) Log.v(
2363 TAG, "Already invisible: " + r);
2364 }
2365 } else if (r.fullscreen) {
2366 if (DEBUG_VISBILITY) Log.v(
2367 TAG, "Now behindFullscreen: " + r);
2368 behindFullscreen = true;
2369 }
2370 }
2371 i--;
2372 }
2373 }
2374
2375 /**
2376 * Version of ensureActivitiesVisible that can easily be called anywhere.
2377 */
2378 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2379 int configChanges) {
2380 HistoryRecord r = topRunningActivityLocked(null);
2381 if (r != null) {
2382 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2383 }
2384 }
2385
2386 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2387 if (resumed) {
2388 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2389 } else {
2390 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2391 }
2392 }
2393
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002394 private boolean startHomeActivityLocked() {
2395 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2396 && mTopAction == null) {
2397 // We are running in factory test mode, but unable to find
2398 // the factory test app, so just sit around displaying the
2399 // error message and don't try to start anything.
2400 return false;
2401 }
2402 Intent intent = new Intent(
2403 mTopAction,
2404 mTopData != null ? Uri.parse(mTopData) : null);
2405 intent.setComponent(mTopComponent);
2406 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2407 intent.addCategory(Intent.CATEGORY_HOME);
2408 }
2409 ActivityInfo aInfo =
2410 intent.resolveActivityInfo(mContext.getPackageManager(),
2411 STOCK_PM_FLAGS);
2412 if (aInfo != null) {
2413 intent.setComponent(new ComponentName(
2414 aInfo.applicationInfo.packageName, aInfo.name));
2415 // Don't do this if the home app is currently being
2416 // instrumented.
2417 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2418 aInfo.applicationInfo.uid);
2419 if (app == null || app.instrumentationClass == null) {
2420 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2421 startActivityLocked(null, intent, null, null, 0, aInfo,
2422 null, null, 0, 0, 0, false, false);
2423 }
2424 }
2425
2426
2427 return true;
2428 }
2429
2430 /**
2431 * Starts the "new version setup screen" if appropriate.
2432 */
2433 private void startSetupActivityLocked() {
2434 // Only do this once per boot.
2435 if (mCheckedForSetup) {
2436 return;
2437 }
2438
2439 // We will show this screen if the current one is a different
2440 // version than the last one shown, and we are not running in
2441 // low-level factory test mode.
2442 final ContentResolver resolver = mContext.getContentResolver();
2443 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2444 Settings.Secure.getInt(resolver,
2445 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2446 mCheckedForSetup = true;
2447
2448 // See if we should be showing the platform update setup UI.
2449 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2450 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2451 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2452
2453 // We don't allow third party apps to replace this.
2454 ResolveInfo ri = null;
2455 for (int i=0; ris != null && i<ris.size(); i++) {
2456 if ((ris.get(i).activityInfo.applicationInfo.flags
2457 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2458 ri = ris.get(i);
2459 break;
2460 }
2461 }
2462
2463 if (ri != null) {
2464 String vers = ri.activityInfo.metaData != null
2465 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2466 : null;
2467 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2468 vers = ri.activityInfo.applicationInfo.metaData.getString(
2469 Intent.METADATA_SETUP_VERSION);
2470 }
2471 String lastVers = Settings.Secure.getString(
2472 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2473 if (vers != null && !vers.equals(lastVers)) {
2474 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2475 intent.setComponent(new ComponentName(
2476 ri.activityInfo.packageName, ri.activityInfo.name));
2477 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2478 null, null, 0, 0, 0, false, false);
2479 }
2480 }
2481 }
2482 }
2483
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002484 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002485 //Log.i(TAG, "**** REPORT RESUME: " + r);
2486
2487 final int identHash = System.identityHashCode(r);
2488 updateUsageStats(r, true);
2489
2490 int i = mWatchers.beginBroadcast();
2491 while (i > 0) {
2492 i--;
2493 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2494 if (w != null) {
2495 try {
2496 w.activityResuming(identHash);
2497 } catch (RemoteException e) {
2498 }
2499 }
2500 }
2501 mWatchers.finishBroadcast();
2502 }
2503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 /**
2505 * Ensure that the top activity in the stack is resumed.
2506 *
2507 * @param prev The previously resumed activity, for when in the process
2508 * of pausing; can be null to call from elsewhere.
2509 *
2510 * @return Returns true if something is being resumed, or false if
2511 * nothing happened.
2512 */
2513 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2514 // Find the first activity that is not finishing.
2515 HistoryRecord next = topRunningActivityLocked(null);
2516
2517 // Remember how we'll process this pause/resume situation, and ensure
2518 // that the state is reset however we wind up proceeding.
2519 final boolean userLeaving = mUserLeaving;
2520 mUserLeaving = false;
2521
2522 if (next == null) {
2523 // There are no more activities! Let's just start up the
2524 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002525 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 }
2527
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002528 next.delayedResume = false;
2529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002530 // If the top activity is the resumed one, nothing to do.
2531 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2532 // Make sure we have executed any pending transitions, since there
2533 // should be nothing left to do at this point.
2534 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002535 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002536 return false;
2537 }
2538
2539 // If we are sleeping, and there is no resumed activity, and the top
2540 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002541 if ((mSleeping || mShuttingDown)
2542 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002543 // Make sure we have executed any pending transitions, since there
2544 // should be nothing left to do at this point.
2545 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002546 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002547 return false;
2548 }
2549
2550 // The activity may be waiting for stop, but that is no longer
2551 // appropriate for it.
2552 mStoppingActivities.remove(next);
2553 mWaitingVisibleActivities.remove(next);
2554
2555 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2556
2557 // If we are currently pausing an activity, then don't do anything
2558 // until that is done.
2559 if (mPausingActivity != null) {
2560 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2561 return false;
2562 }
2563
2564 // We need to start pausing the current activity so the top one
2565 // can be resumed...
2566 if (mResumedActivity != null) {
2567 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2568 startPausingLocked(userLeaving, false);
2569 return true;
2570 }
2571
2572 if (prev != null && prev != next) {
2573 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2574 prev.waitingVisible = true;
2575 mWaitingVisibleActivities.add(prev);
2576 if (DEBUG_SWITCH) Log.v(
2577 TAG, "Resuming top, waiting visible to hide: " + prev);
2578 } else {
2579 // The next activity is already visible, so hide the previous
2580 // activity's windows right now so we can show the new one ASAP.
2581 // We only do this if the previous is finishing, which should mean
2582 // it is on top of the one being resumed so hiding it quickly
2583 // is good. Otherwise, we want to do the normal route of allowing
2584 // the resumed activity to be shown so we can decide if the
2585 // previous should actually be hidden depending on whether the
2586 // new one is found to be full-screen or not.
2587 if (prev.finishing) {
2588 mWindowManager.setAppVisibility(prev, false);
2589 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2590 + prev + ", waitingVisible="
2591 + (prev != null ? prev.waitingVisible : null)
2592 + ", nowVisible=" + next.nowVisible);
2593 } else {
2594 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2595 + prev + ", waitingVisible="
2596 + (prev != null ? prev.waitingVisible : null)
2597 + ", nowVisible=" + next.nowVisible);
2598 }
2599 }
2600 }
2601
2602 // We are starting up the next activity, so tell the window manager
2603 // that the previous one will be hidden soon. This way it can know
2604 // to ignore it when computing the desired screen orientation.
2605 if (prev != null) {
2606 if (prev.finishing) {
2607 if (DEBUG_TRANSITION) Log.v(TAG,
2608 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002609 if (mNoAnimActivities.contains(prev)) {
2610 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2611 } else {
2612 mWindowManager.prepareAppTransition(prev.task == next.task
2613 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2614 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 mWindowManager.setAppWillBeHidden(prev);
2617 mWindowManager.setAppVisibility(prev, false);
2618 } else {
2619 if (DEBUG_TRANSITION) Log.v(TAG,
2620 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002621 if (mNoAnimActivities.contains(next)) {
2622 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2623 } else {
2624 mWindowManager.prepareAppTransition(prev.task == next.task
2625 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2626 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 }
2629 if (false) {
2630 mWindowManager.setAppWillBeHidden(prev);
2631 mWindowManager.setAppVisibility(prev, false);
2632 }
2633 } else if (mHistory.size() > 1) {
2634 if (DEBUG_TRANSITION) Log.v(TAG,
2635 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002636 if (mNoAnimActivities.contains(next)) {
2637 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2638 } else {
2639 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2640 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002641 }
2642
2643 if (next.app != null && next.app.thread != null) {
2644 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2645
2646 // This activity is now becoming visible.
2647 mWindowManager.setAppVisibility(next, true);
2648
2649 HistoryRecord lastResumedActivity = mResumedActivity;
2650 ActivityState lastState = next.state;
2651
2652 updateCpuStats();
2653
2654 next.state = ActivityState.RESUMED;
2655 mResumedActivity = next;
2656 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002657 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 updateLRUListLocked(next);
2659
2660 // Have the window manager re-evaluate the orientation of
2661 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002662 boolean updated;
2663 synchronized (this) {
2664 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2665 mConfiguration,
2666 next.mayFreezeScreenLocked(next.app) ? next : null);
2667 if (config != null) {
2668 /*
2669 * Explicitly restore the locale to the one from the
2670 * old configuration, since the one that comes back from
2671 * the window manager has the default (boot) locale.
2672 *
2673 * It looks like previously the locale picker only worked
2674 * by coincidence: usually it would do its setting of
2675 * the locale after the activity transition, so it didn't
2676 * matter that this lost it. With the synchronized
2677 * block now keeping them from happening at the same time,
2678 * this one always would happen second and undo what the
2679 * locale picker had just done.
2680 */
2681 config.locale = mConfiguration.locale;
2682 next.frozenBeforeDestroy = true;
2683 }
2684 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002686 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 // The configuration update wasn't able to keep the existing
2688 // instance of the activity, and instead started a new one.
2689 // We should be all done, but let's just make sure our activity
2690 // is still at the top and schedule another run if something
2691 // weird happened.
2692 HistoryRecord nextNext = topRunningActivityLocked(null);
2693 if (DEBUG_SWITCH) Log.i(TAG,
2694 "Activity config changed during resume: " + next
2695 + ", new next: " + nextNext);
2696 if (nextNext != next) {
2697 // Do over!
2698 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2699 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002700 setFocusedActivityLocked(next);
2701 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002703 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002704 return true;
2705 }
2706
2707 try {
2708 // Deliver all pending results.
2709 ArrayList a = next.results;
2710 if (a != null) {
2711 final int N = a.size();
2712 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002713 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002714 TAG, "Delivering results to " + next
2715 + ": " + a);
2716 next.app.thread.scheduleSendResult(next, a);
2717 }
2718 }
2719
2720 if (next.newIntents != null) {
2721 next.app.thread.scheduleNewIntent(next.newIntents, next);
2722 }
2723
Doug Zongker2bec3d42009-12-04 12:52:44 -08002724 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002725 System.identityHashCode(next),
2726 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727
2728 next.app.thread.scheduleResumeActivity(next,
2729 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002731 pauseIfSleepingLocked();
2732
2733 } catch (Exception e) {
2734 // Whoops, need to restart this activity!
2735 next.state = lastState;
2736 mResumedActivity = lastResumedActivity;
Dianne Hackborn03abb812010-01-04 18:43:19 -08002737 Log.i(TAG, "Restarting because process died: " + next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002738 if (!next.hasBeenLaunched) {
2739 next.hasBeenLaunched = true;
2740 } else {
2741 if (SHOW_APP_STARTING_ICON) {
2742 mWindowManager.setAppStartingWindow(
2743 next, next.packageName, next.theme,
2744 next.nonLocalizedLabel,
2745 next.labelRes, next.icon, null, true);
2746 }
2747 }
2748 startSpecificActivityLocked(next, true, false);
2749 return true;
2750 }
2751
2752 // From this point on, if something goes wrong there is no way
2753 // to recover the activity.
2754 try {
2755 next.visible = true;
2756 completeResumeLocked(next);
2757 } catch (Exception e) {
2758 // If any exception gets thrown, toss away this
2759 // activity and try the next one.
2760 Log.w(TAG, "Exception thrown during resume of " + next, e);
2761 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2762 "resume-exception");
2763 return true;
2764 }
2765
2766 // Didn't need to use the icicle, and it is now out of date.
2767 next.icicle = null;
2768 next.haveState = false;
2769 next.stopped = false;
2770
2771 } else {
2772 // Whoops, need to restart this activity!
2773 if (!next.hasBeenLaunched) {
2774 next.hasBeenLaunched = true;
2775 } else {
2776 if (SHOW_APP_STARTING_ICON) {
2777 mWindowManager.setAppStartingWindow(
2778 next, next.packageName, next.theme,
2779 next.nonLocalizedLabel,
2780 next.labelRes, next.icon, null, true);
2781 }
2782 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2783 }
2784 startSpecificActivityLocked(next, true, true);
2785 }
2786
2787 return true;
2788 }
2789
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002790 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2791 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002792 final int NH = mHistory.size();
2793
2794 int addPos = -1;
2795
2796 if (!newTask) {
2797 // If starting in an existing task, find where that is...
2798 HistoryRecord next = null;
2799 boolean startIt = true;
2800 for (int i = NH-1; i >= 0; i--) {
2801 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2802 if (p.finishing) {
2803 continue;
2804 }
2805 if (p.task == r.task) {
2806 // Here it is! Now, if this is not yet visible to the
2807 // user, then just add it without starting; it will
2808 // get started when the user navigates back to it.
2809 addPos = i+1;
2810 if (!startIt) {
2811 mHistory.add(addPos, r);
2812 r.inHistory = true;
2813 r.task.numActivities++;
2814 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2815 r.info.screenOrientation, r.fullscreen);
2816 if (VALIDATE_TOKENS) {
2817 mWindowManager.validateAppTokens(mHistory);
2818 }
2819 return;
2820 }
2821 break;
2822 }
2823 if (p.fullscreen) {
2824 startIt = false;
2825 }
2826 next = p;
2827 }
2828 }
2829
2830 // Place a new activity at top of stack, so it is next to interact
2831 // with the user.
2832 if (addPos < 0) {
2833 addPos = mHistory.size();
2834 }
2835
2836 // If we are not placing the new activity frontmost, we do not want
2837 // to deliver the onUserLeaving callback to the actual frontmost
2838 // activity
2839 if (addPos < NH) {
2840 mUserLeaving = false;
2841 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2842 }
2843
2844 // Slot the activity into the history stack and proceed
2845 mHistory.add(addPos, r);
2846 r.inHistory = true;
2847 r.frontOfTask = newTask;
2848 r.task.numActivities++;
2849 if (NH > 0) {
2850 // We want to show the starting preview window if we are
2851 // switching to a new task, or the next activity's process is
2852 // not currently running.
2853 boolean showStartingIcon = newTask;
2854 ProcessRecord proc = r.app;
2855 if (proc == null) {
2856 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2857 }
2858 if (proc == null || proc.thread == null) {
2859 showStartingIcon = true;
2860 }
2861 if (DEBUG_TRANSITION) Log.v(TAG,
2862 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002863 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2864 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2865 mNoAnimActivities.add(r);
2866 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2867 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2868 mNoAnimActivities.remove(r);
2869 } else {
2870 mWindowManager.prepareAppTransition(newTask
2871 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2872 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2873 mNoAnimActivities.remove(r);
2874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002875 mWindowManager.addAppToken(
2876 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2877 boolean doShow = true;
2878 if (newTask) {
2879 // Even though this activity is starting fresh, we still need
2880 // to reset it to make sure we apply affinities to move any
2881 // existing activities from other tasks in to it.
2882 // If the caller has requested that the target task be
2883 // reset, then do so.
2884 if ((r.intent.getFlags()
2885 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2886 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002887 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002888 }
2889 }
2890 if (SHOW_APP_STARTING_ICON && doShow) {
2891 // Figure out if we are transitioning from another activity that is
2892 // "has the same starting icon" as the next one. This allows the
2893 // window manager to keep the previous window it had previously
2894 // created, if it still had one.
2895 HistoryRecord prev = mResumedActivity;
2896 if (prev != null) {
2897 // We don't want to reuse the previous starting preview if:
2898 // (1) The current activity is in a different task.
2899 if (prev.task != r.task) prev = null;
2900 // (2) The current activity is already displayed.
2901 else if (prev.nowVisible) prev = null;
2902 }
2903 mWindowManager.setAppStartingWindow(
2904 r, r.packageName, r.theme, r.nonLocalizedLabel,
2905 r.labelRes, r.icon, prev, showStartingIcon);
2906 }
2907 } else {
2908 // If this is the first activity, don't do any fancy animations,
2909 // because there is nothing for it to animate on top of.
2910 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2911 r.info.screenOrientation, r.fullscreen);
2912 }
2913 if (VALIDATE_TOKENS) {
2914 mWindowManager.validateAppTokens(mHistory);
2915 }
2916
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002917 if (doResume) {
2918 resumeTopActivityLocked(null);
2919 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 }
2921
2922 /**
2923 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002924 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2925 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926 * an instance of that activity in the stack and, if found, finish all
2927 * activities on top of it and return the instance.
2928 *
2929 * @param newR Description of the new activity being started.
2930 * @return Returns the old activity that should be continue to be used,
2931 * or null if none was found.
2932 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002933 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002934 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002936
2937 // First find the requested task.
2938 while (i > 0) {
2939 i--;
2940 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2941 if (r.task.taskId == taskId) {
2942 i++;
2943 break;
2944 }
2945 }
2946
2947 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 while (i > 0) {
2949 i--;
2950 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2951 if (r.finishing) {
2952 continue;
2953 }
2954 if (r.task.taskId != taskId) {
2955 return null;
2956 }
2957 if (r.realActivity.equals(newR.realActivity)) {
2958 // Here it is! Now finish everything in front...
2959 HistoryRecord ret = r;
2960 if (doClear) {
2961 while (i < (mHistory.size()-1)) {
2962 i++;
2963 r = (HistoryRecord)mHistory.get(i);
2964 if (r.finishing) {
2965 continue;
2966 }
2967 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2968 null, "clear")) {
2969 i--;
2970 }
2971 }
2972 }
2973
2974 // Finally, if this is a normal launch mode (that is, not
2975 // expecting onNewIntent()), then we will finish the current
2976 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002977 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2978 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002979 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002980 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002981 if (index >= 0) {
2982 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2983 null, "clear");
2984 }
2985 return null;
2986 }
2987 }
2988
2989 return ret;
2990 }
2991 }
2992
2993 return null;
2994 }
2995
2996 /**
2997 * Find the activity in the history stack within the given task. Returns
2998 * the index within the history at which it's found, or < 0 if not found.
2999 */
3000 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3001 int i = mHistory.size();
3002 while (i > 0) {
3003 i--;
3004 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3005 if (candidate.task.taskId != task) {
3006 break;
3007 }
3008 if (candidate.realActivity.equals(r.realActivity)) {
3009 return i;
3010 }
3011 }
3012
3013 return -1;
3014 }
3015
3016 /**
3017 * Reorder the history stack so that the activity at the given index is
3018 * brought to the front.
3019 */
3020 private final HistoryRecord moveActivityToFrontLocked(int where) {
3021 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3022 int top = mHistory.size();
3023 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3024 mHistory.add(top, newTop);
3025 oldTop.frontOfTask = false;
3026 newTop.frontOfTask = true;
3027 return newTop;
3028 }
3029
3030 /**
3031 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3032 * method will be called at the proper time.
3033 */
3034 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3035 boolean sent = false;
3036 if (r.state == ActivityState.RESUMED
3037 && r.app != null && r.app.thread != null) {
3038 try {
3039 ArrayList<Intent> ar = new ArrayList<Intent>();
3040 ar.add(new Intent(intent));
3041 r.app.thread.scheduleNewIntent(ar, r);
3042 sent = true;
3043 } catch (Exception e) {
3044 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3045 }
3046 }
3047 if (!sent) {
3048 r.addNewIntentLocked(new Intent(intent));
3049 }
3050 }
3051
3052 private final void logStartActivity(int tag, HistoryRecord r,
3053 TaskRecord task) {
3054 EventLog.writeEvent(tag,
3055 System.identityHashCode(r), task.taskId,
3056 r.shortComponentName, r.intent.getAction(),
3057 r.intent.getType(), r.intent.getDataString(),
3058 r.intent.getFlags());
3059 }
3060
3061 private final int startActivityLocked(IApplicationThread caller,
3062 Intent intent, String resolvedType,
3063 Uri[] grantedUriPermissions,
3064 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3065 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003066 int callingPid, int callingUid, boolean onlyIfNeeded,
3067 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003068 Log.i(TAG, "Starting activity: " + intent);
3069
3070 HistoryRecord sourceRecord = null;
3071 HistoryRecord resultRecord = null;
3072 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003073 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003074 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3076 if (index >= 0) {
3077 sourceRecord = (HistoryRecord)mHistory.get(index);
3078 if (requestCode >= 0 && !sourceRecord.finishing) {
3079 resultRecord = sourceRecord;
3080 }
3081 }
3082 }
3083
3084 int launchFlags = intent.getFlags();
3085
3086 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3087 && sourceRecord != null) {
3088 // Transfer the result target from the source activity to the new
3089 // one being started, including any failures.
3090 if (requestCode >= 0) {
3091 return START_FORWARD_AND_REQUEST_CONFLICT;
3092 }
3093 resultRecord = sourceRecord.resultTo;
3094 resultWho = sourceRecord.resultWho;
3095 requestCode = sourceRecord.requestCode;
3096 sourceRecord.resultTo = null;
3097 if (resultRecord != null) {
3098 resultRecord.removeResultsLocked(
3099 sourceRecord, resultWho, requestCode);
3100 }
3101 }
3102
3103 int err = START_SUCCESS;
3104
3105 if (intent.getComponent() == null) {
3106 // We couldn't find a class that can handle the given Intent.
3107 // That's the end of that!
3108 err = START_INTENT_NOT_RESOLVED;
3109 }
3110
3111 if (err == START_SUCCESS && aInfo == null) {
3112 // We couldn't find the specific class specified in the Intent.
3113 // Also the end of the line.
3114 err = START_CLASS_NOT_FOUND;
3115 }
3116
3117 ProcessRecord callerApp = null;
3118 if (err == START_SUCCESS && caller != null) {
3119 callerApp = getRecordForAppLocked(caller);
3120 if (callerApp != null) {
3121 callingPid = callerApp.pid;
3122 callingUid = callerApp.info.uid;
3123 } else {
3124 Log.w(TAG, "Unable to find app for caller " + caller
3125 + " (pid=" + callingPid + ") when starting: "
3126 + intent.toString());
3127 err = START_PERMISSION_DENIED;
3128 }
3129 }
3130
3131 if (err != START_SUCCESS) {
3132 if (resultRecord != null) {
3133 sendActivityResultLocked(-1,
3134 resultRecord, resultWho, requestCode,
3135 Activity.RESULT_CANCELED, null);
3136 }
3137 return err;
3138 }
3139
3140 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3141 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3142 if (perm != PackageManager.PERMISSION_GRANTED) {
3143 if (resultRecord != null) {
3144 sendActivityResultLocked(-1,
3145 resultRecord, resultWho, requestCode,
3146 Activity.RESULT_CANCELED, null);
3147 }
3148 String msg = "Permission Denial: starting " + intent.toString()
3149 + " from " + callerApp + " (pid=" + callingPid
3150 + ", uid=" + callingUid + ")"
3151 + " requires " + aInfo.permission;
3152 Log.w(TAG, msg);
3153 throw new SecurityException(msg);
3154 }
3155
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003156 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 boolean abort = false;
3158 try {
3159 // The Intent we give to the watcher has the extra data
3160 // stripped off, since it can contain private information.
3161 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003162 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 aInfo.applicationInfo.packageName);
3164 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003165 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003166 }
3167
3168 if (abort) {
3169 if (resultRecord != null) {
3170 sendActivityResultLocked(-1,
3171 resultRecord, resultWho, requestCode,
3172 Activity.RESULT_CANCELED, null);
3173 }
3174 // We pretend to the caller that it was really started, but
3175 // they will just get a cancel result.
3176 return START_SUCCESS;
3177 }
3178 }
3179
3180 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3181 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003182 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003184 if (mResumedActivity == null
3185 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3186 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3187 PendingActivityLaunch pal = new PendingActivityLaunch();
3188 pal.r = r;
3189 pal.sourceRecord = sourceRecord;
3190 pal.grantedUriPermissions = grantedUriPermissions;
3191 pal.grantedMode = grantedMode;
3192 pal.onlyIfNeeded = onlyIfNeeded;
3193 mPendingActivityLaunches.add(pal);
3194 return START_SWITCHES_CANCELED;
3195 }
3196 }
3197
3198 if (mDidAppSwitch) {
3199 // This is the second allowed switch since we stopped switches,
3200 // so now just generally allow switches. Use case: user presses
3201 // home (switches disabled, switch to home, mDidAppSwitch now true);
3202 // user taps a home icon (coming from home so allowed, we hit here
3203 // and now allow anyone to switch again).
3204 mAppSwitchesAllowedTime = 0;
3205 } else {
3206 mDidAppSwitch = true;
3207 }
3208
3209 doPendingActivityLaunchesLocked(false);
3210
3211 return startActivityUncheckedLocked(r, sourceRecord,
3212 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3213 }
3214
3215 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3216 final int N = mPendingActivityLaunches.size();
3217 if (N <= 0) {
3218 return;
3219 }
3220 for (int i=0; i<N; i++) {
3221 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3222 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3223 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3224 doResume && i == (N-1));
3225 }
3226 mPendingActivityLaunches.clear();
3227 }
3228
3229 private final int startActivityUncheckedLocked(HistoryRecord r,
3230 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3231 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3232 final Intent intent = r.intent;
3233 final int callingUid = r.launchedFromUid;
3234
3235 int launchFlags = intent.getFlags();
3236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 // We'll invoke onUserLeaving before onPause only if the launching
3238 // activity did not explicitly state that this is an automated launch.
3239 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3240 if (DEBUG_USER_LEAVING) Log.v(TAG,
3241 "startActivity() => mUserLeaving=" + mUserLeaving);
3242
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003243 // If the caller has asked not to resume at this point, we make note
3244 // of this in the record so that we can skip it when trying to find
3245 // the top running activity.
3246 if (!doResume) {
3247 r.delayedResume = true;
3248 }
3249
3250 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3251 != 0 ? r : null;
3252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003253 // If the onlyIfNeeded flag is set, then we can do this if the activity
3254 // being launched is the same as the one making the call... or, as
3255 // a special case, if we do not know the caller then we count the
3256 // current top activity as the caller.
3257 if (onlyIfNeeded) {
3258 HistoryRecord checkedCaller = sourceRecord;
3259 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003260 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003261 }
3262 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3263 // Caller is not the same as launcher, so always needed.
3264 onlyIfNeeded = false;
3265 }
3266 }
3267
3268 if (grantedUriPermissions != null && callingUid > 0) {
3269 for (int i=0; i<grantedUriPermissions.length; i++) {
3270 grantUriPermissionLocked(callingUid, r.packageName,
3271 grantedUriPermissions[i], grantedMode, r);
3272 }
3273 }
3274
3275 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3276 intent, r);
3277
3278 if (sourceRecord == null) {
3279 // This activity is not being started from another... in this
3280 // case we -always- start a new task.
3281 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3282 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3283 + intent);
3284 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3285 }
3286 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3287 // The original activity who is starting us is running as a single
3288 // instance... this new activity it is starting must go on its
3289 // own task.
3290 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3291 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3292 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3293 // The activity being started is a single instance... it always
3294 // gets launched into its own task.
3295 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3296 }
3297
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003298 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003299 // For whatever reason this activity is being launched into a new
3300 // task... yet the caller has requested a result back. Well, that
3301 // is pretty messed up, so instead immediately send back a cancel
3302 // and let the new task continue launched as normal without a
3303 // dependency on its originator.
3304 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3305 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003306 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 Activity.RESULT_CANCELED, null);
3308 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 }
3310
3311 boolean addingToTask = false;
3312 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3313 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3314 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3315 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3316 // If bring to front is requested, and no result is requested, and
3317 // we can find a task that was started with this same
3318 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003319 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 // See if there is a task to bring to the front. If this is
3321 // a SINGLE_INSTANCE activity, there can be one and only one
3322 // instance of it in the history, and it is always in its own
3323 // unique task, so we do a special search.
3324 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3325 ? findTaskLocked(intent, r.info)
3326 : findActivityLocked(intent, r.info);
3327 if (taskTop != null) {
3328 if (taskTop.task.intent == null) {
3329 // This task was started because of movement of
3330 // the activity based on affinity... now that we
3331 // are actually launching it, we can assign the
3332 // base intent.
3333 taskTop.task.setIntent(intent, r.info);
3334 }
3335 // If the target task is not in the front, then we need
3336 // to bring it to the front... except... well, with
3337 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3338 // to have the same behavior as if a new instance was
3339 // being started, which means not bringing it to the front
3340 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003341 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 if (curTop.task != taskTop.task) {
3343 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3344 boolean callerAtFront = sourceRecord == null
3345 || curTop.task == sourceRecord.task;
3346 if (callerAtFront) {
3347 // We really do want to push this one into the
3348 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003349 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 }
3351 }
3352 // If the caller has requested that the target task be
3353 // reset, then do so.
3354 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3355 taskTop = resetTaskIfNeededLocked(taskTop, r);
3356 }
3357 if (onlyIfNeeded) {
3358 // We don't need to start a new activity, and
3359 // the client said not to do anything if that
3360 // is the case, so this is it! And for paranoia, make
3361 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003362 if (doResume) {
3363 resumeTopActivityLocked(null);
3364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 return START_RETURN_INTENT_TO_CALLER;
3366 }
3367 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3368 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3369 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3370 // In this situation we want to remove all activities
3371 // from the task up to the one being started. In most
3372 // cases this means we are resetting the task to its
3373 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003374 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003375 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 if (top != null) {
3377 if (top.frontOfTask) {
3378 // Activity aliases may mean we use different
3379 // intents for the top activity, so make sure
3380 // the task now has the identity of the new
3381 // intent.
3382 top.task.setIntent(r.intent, r.info);
3383 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003384 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003385 deliverNewIntentLocked(top, r.intent);
3386 } else {
3387 // A special case: we need to
3388 // start the activity because it is not currently
3389 // running, and the caller has asked to clear the
3390 // current task to have this activity at the top.
3391 addingToTask = true;
3392 // Now pretend like this activity is being started
3393 // by the top of its task, so it is put in the
3394 // right place.
3395 sourceRecord = taskTop;
3396 }
3397 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3398 // In this case the top activity on the task is the
3399 // same as the one being launched, so we take that
3400 // as a request to bring the task to the foreground.
3401 // If the top activity in the task is the root
3402 // activity, deliver this new intent to it if it
3403 // desires.
3404 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3405 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003406 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 if (taskTop.frontOfTask) {
3408 taskTop.task.setIntent(r.intent, r.info);
3409 }
3410 deliverNewIntentLocked(taskTop, r.intent);
3411 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3412 // In this case we are launching the root activity
3413 // of the task, but with a different intent. We
3414 // should start a new instance on top.
3415 addingToTask = true;
3416 sourceRecord = taskTop;
3417 }
3418 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3419 // In this case an activity is being launched in to an
3420 // existing task, without resetting that task. This
3421 // is typically the situation of launching an activity
3422 // from a notification or shortcut. We want to place
3423 // the new activity on top of the current task.
3424 addingToTask = true;
3425 sourceRecord = taskTop;
3426 } else if (!taskTop.task.rootWasReset) {
3427 // In this case we are launching in to an existing task
3428 // that has not yet been started from its front door.
3429 // The current task has been brought to the front.
3430 // Ideally, we'd probably like to place this new task
3431 // at the bottom of its stack, but that's a little hard
3432 // to do with the current organization of the code so
3433 // for now we'll just drop it.
3434 taskTop.task.setIntent(r.intent, r.info);
3435 }
3436 if (!addingToTask) {
3437 // We didn't do anything... but it was needed (a.k.a., client
3438 // don't use that intent!) And for paranoia, make
3439 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003440 if (doResume) {
3441 resumeTopActivityLocked(null);
3442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003443 return START_TASK_TO_FRONT;
3444 }
3445 }
3446 }
3447 }
3448
3449 //String uri = r.intent.toURI();
3450 //Intent intent2 = new Intent(uri);
3451 //Log.i(TAG, "Given intent: " + r.intent);
3452 //Log.i(TAG, "URI is: " + uri);
3453 //Log.i(TAG, "To intent: " + intent2);
3454
3455 if (r.packageName != null) {
3456 // If the activity being launched is the same as the one currently
3457 // at the top, then we need to check if it should only be launched
3458 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003459 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3460 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003461 if (top.realActivity.equals(r.realActivity)) {
3462 if (top.app != null && top.app.thread != null) {
3463 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3464 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3465 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003466 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003467 // For paranoia, make sure we have correctly
3468 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003469 if (doResume) {
3470 resumeTopActivityLocked(null);
3471 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 if (onlyIfNeeded) {
3473 // We don't need to start a new activity, and
3474 // the client said not to do anything if that
3475 // is the case, so this is it!
3476 return START_RETURN_INTENT_TO_CALLER;
3477 }
3478 deliverNewIntentLocked(top, r.intent);
3479 return START_DELIVERED_TO_TOP;
3480 }
3481 }
3482 }
3483 }
3484
3485 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003486 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003487 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003488 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 Activity.RESULT_CANCELED, null);
3490 }
3491 return START_CLASS_NOT_FOUND;
3492 }
3493
3494 boolean newTask = false;
3495
3496 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003497 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3499 // todo: should do better management of integers.
3500 mCurTask++;
3501 if (mCurTask <= 0) {
3502 mCurTask = 1;
3503 }
3504 r.task = new TaskRecord(mCurTask, r.info, intent,
3505 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3506 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3507 + " in new task " + r.task);
3508 newTask = true;
3509 addRecentTask(r.task);
3510
3511 } else if (sourceRecord != null) {
3512 if (!addingToTask &&
3513 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3514 // In this case, we are adding the activity to an existing
3515 // task, but the caller has asked to clear that task if the
3516 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003517 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003518 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003520 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 deliverNewIntentLocked(top, r.intent);
3522 // For paranoia, make sure we have correctly
3523 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003524 if (doResume) {
3525 resumeTopActivityLocked(null);
3526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 return START_DELIVERED_TO_TOP;
3528 }
3529 } else if (!addingToTask &&
3530 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3531 // In this case, we are launching an activity in our own task
3532 // that may already be running somewhere in the history, and
3533 // we want to shuffle it to the front of the stack if so.
3534 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3535 if (where >= 0) {
3536 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003537 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003539 if (doResume) {
3540 resumeTopActivityLocked(null);
3541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 return START_DELIVERED_TO_TOP;
3543 }
3544 }
3545 // An existing activity is starting this new activity, so we want
3546 // to keep the new one in the same task as the one that is starting
3547 // it.
3548 r.task = sourceRecord.task;
3549 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3550 + " in existing task " + r.task);
3551
3552 } else {
3553 // This not being started from an existing activity, and not part
3554 // of a new task... just put it in the top task, though these days
3555 // this case should never happen.
3556 final int N = mHistory.size();
3557 HistoryRecord prev =
3558 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3559 r.task = prev != null
3560 ? prev.task
3561 : new TaskRecord(mCurTask, r.info, intent,
3562 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3563 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3564 + " in new guessed " + r.task);
3565 }
3566 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003567 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003569 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003570 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 return START_SUCCESS;
3572 }
3573
3574 public final int startActivity(IApplicationThread caller,
3575 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3576 int grantedMode, IBinder resultTo,
3577 String resultWho, int requestCode, boolean onlyIfNeeded,
3578 boolean debug) {
3579 // Refuse possible leaked file descriptors
3580 if (intent != null && intent.hasFileDescriptors()) {
3581 throw new IllegalArgumentException("File descriptors passed in Intent");
3582 }
3583
The Android Open Source Project4df24232009-03-05 14:34:35 -08003584 final boolean componentSpecified = intent.getComponent() != null;
3585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003586 // Don't modify the client's object!
3587 intent = new Intent(intent);
3588
3589 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003590 ActivityInfo aInfo;
3591 try {
3592 ResolveInfo rInfo =
3593 ActivityThread.getPackageManager().resolveIntent(
3594 intent, resolvedType,
3595 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003596 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 aInfo = rInfo != null ? rInfo.activityInfo : null;
3598 } catch (RemoteException e) {
3599 aInfo = null;
3600 }
3601
3602 if (aInfo != null) {
3603 // Store the found target back into the intent, because now that
3604 // we have it we never want to do this again. For example, if the
3605 // user navigates back to this point in the history, we should
3606 // always restart the exact same activity.
3607 intent.setComponent(new ComponentName(
3608 aInfo.applicationInfo.packageName, aInfo.name));
3609
3610 // Don't debug things in the system process
3611 if (debug) {
3612 if (!aInfo.processName.equals("system")) {
3613 setDebugApp(aInfo.processName, true, false);
3614 }
3615 }
3616 }
3617
3618 synchronized(this) {
3619 final long origId = Binder.clearCallingIdentity();
3620 int res = startActivityLocked(caller, intent, resolvedType,
3621 grantedUriPermissions, grantedMode, aInfo,
3622 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003623 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 Binder.restoreCallingIdentity(origId);
3625 return res;
3626 }
3627 }
3628
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003629 public int startActivityIntentSender(IApplicationThread caller,
3630 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003631 IBinder resultTo, String resultWho, int requestCode,
3632 int flagsMask, int flagsValues) {
3633 // Refuse possible leaked file descriptors
3634 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3635 throw new IllegalArgumentException("File descriptors passed in Intent");
3636 }
3637
3638 IIntentSender sender = intent.getTarget();
3639 if (!(sender instanceof PendingIntentRecord)) {
3640 throw new IllegalArgumentException("Bad PendingIntent object");
3641 }
3642
3643 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003644
3645 synchronized (this) {
3646 // If this is coming from the currently resumed activity, it is
3647 // effectively saying that app switches are allowed at this point.
3648 if (mResumedActivity != null
3649 && mResumedActivity.info.applicationInfo.uid ==
3650 Binder.getCallingUid()) {
3651 mAppSwitchesAllowedTime = 0;
3652 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003653 }
3654
3655 return pir.sendInner(0, fillInIntent, resolvedType,
3656 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3657 }
3658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003659 public boolean startNextMatchingActivity(IBinder callingActivity,
3660 Intent intent) {
3661 // Refuse possible leaked file descriptors
3662 if (intent != null && intent.hasFileDescriptors() == true) {
3663 throw new IllegalArgumentException("File descriptors passed in Intent");
3664 }
3665
3666 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003667 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003668 if (index < 0) {
3669 return false;
3670 }
3671 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3672 if (r.app == null || r.app.thread == null) {
3673 // The caller is not running... d'oh!
3674 return false;
3675 }
3676 intent = new Intent(intent);
3677 // The caller is not allowed to change the data.
3678 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3679 // And we are resetting to find the next component...
3680 intent.setComponent(null);
3681
3682 ActivityInfo aInfo = null;
3683 try {
3684 List<ResolveInfo> resolves =
3685 ActivityThread.getPackageManager().queryIntentActivities(
3686 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003687 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688
3689 // Look for the original activity in the list...
3690 final int N = resolves != null ? resolves.size() : 0;
3691 for (int i=0; i<N; i++) {
3692 ResolveInfo rInfo = resolves.get(i);
3693 if (rInfo.activityInfo.packageName.equals(r.packageName)
3694 && rInfo.activityInfo.name.equals(r.info.name)) {
3695 // We found the current one... the next matching is
3696 // after it.
3697 i++;
3698 if (i<N) {
3699 aInfo = resolves.get(i).activityInfo;
3700 }
3701 break;
3702 }
3703 }
3704 } catch (RemoteException e) {
3705 }
3706
3707 if (aInfo == null) {
3708 // Nobody who is next!
3709 return false;
3710 }
3711
3712 intent.setComponent(new ComponentName(
3713 aInfo.applicationInfo.packageName, aInfo.name));
3714 intent.setFlags(intent.getFlags()&~(
3715 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3716 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3717 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3718 Intent.FLAG_ACTIVITY_NEW_TASK));
3719
3720 // Okay now we need to start the new activity, replacing the
3721 // currently running activity. This is a little tricky because
3722 // we want to start the new one as if the current one is finished,
3723 // but not finish the current one first so that there is no flicker.
3724 // And thus...
3725 final boolean wasFinishing = r.finishing;
3726 r.finishing = true;
3727
3728 // Propagate reply information over to the new activity.
3729 final HistoryRecord resultTo = r.resultTo;
3730 final String resultWho = r.resultWho;
3731 final int requestCode = r.requestCode;
3732 r.resultTo = null;
3733 if (resultTo != null) {
3734 resultTo.removeResultsLocked(r, resultWho, requestCode);
3735 }
3736
3737 final long origId = Binder.clearCallingIdentity();
3738 // XXX we are not dealing with propagating grantedUriPermissions...
3739 // those are not yet exposed to user code, so there is no need.
3740 int res = startActivityLocked(r.app.thread, intent,
3741 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003742 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003743 Binder.restoreCallingIdentity(origId);
3744
3745 r.finishing = wasFinishing;
3746 if (res != START_SUCCESS) {
3747 return false;
3748 }
3749 return true;
3750 }
3751 }
3752
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003753 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 Intent intent, String resolvedType, IBinder resultTo,
3755 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003756
3757 // This is so super not safe, that only the system (or okay root)
3758 // can do it.
3759 final int callingUid = Binder.getCallingUid();
3760 if (callingUid != 0 && callingUid != Process.myUid()) {
3761 throw new SecurityException(
3762 "startActivityInPackage only available to the system");
3763 }
3764
The Android Open Source Project4df24232009-03-05 14:34:35 -08003765 final boolean componentSpecified = intent.getComponent() != null;
3766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 // Don't modify the client's object!
3768 intent = new Intent(intent);
3769
3770 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003771 ActivityInfo aInfo;
3772 try {
3773 ResolveInfo rInfo =
3774 ActivityThread.getPackageManager().resolveIntent(
3775 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003776 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003777 aInfo = rInfo != null ? rInfo.activityInfo : null;
3778 } catch (RemoteException e) {
3779 aInfo = null;
3780 }
3781
3782 if (aInfo != null) {
3783 // Store the found target back into the intent, because now that
3784 // we have it we never want to do this again. For example, if the
3785 // user navigates back to this point in the history, we should
3786 // always restart the exact same activity.
3787 intent.setComponent(new ComponentName(
3788 aInfo.applicationInfo.packageName, aInfo.name));
3789 }
3790
3791 synchronized(this) {
3792 return startActivityLocked(null, intent, resolvedType,
3793 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003794 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003795 }
3796 }
3797
3798 private final void addRecentTask(TaskRecord task) {
3799 // Remove any existing entries that are the same kind of task.
3800 int N = mRecentTasks.size();
3801 for (int i=0; i<N; i++) {
3802 TaskRecord tr = mRecentTasks.get(i);
3803 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3804 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3805 mRecentTasks.remove(i);
3806 i--;
3807 N--;
3808 if (task.intent == null) {
3809 // If the new recent task we are adding is not fully
3810 // specified, then replace it with the existing recent task.
3811 task = tr;
3812 }
3813 }
3814 }
3815 if (N >= MAX_RECENT_TASKS) {
3816 mRecentTasks.remove(N-1);
3817 }
3818 mRecentTasks.add(0, task);
3819 }
3820
3821 public void setRequestedOrientation(IBinder token,
3822 int requestedOrientation) {
3823 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003824 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003825 if (index < 0) {
3826 return;
3827 }
3828 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3829 final long origId = Binder.clearCallingIdentity();
3830 mWindowManager.setAppOrientation(r, requestedOrientation);
3831 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003832 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003833 r.mayFreezeScreenLocked(r.app) ? r : null);
3834 if (config != null) {
3835 r.frozenBeforeDestroy = true;
3836 if (!updateConfigurationLocked(config, r)) {
3837 resumeTopActivityLocked(null);
3838 }
3839 }
3840 Binder.restoreCallingIdentity(origId);
3841 }
3842 }
3843
3844 public int getRequestedOrientation(IBinder token) {
3845 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003846 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003847 if (index < 0) {
3848 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3849 }
3850 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3851 return mWindowManager.getAppOrientation(r);
3852 }
3853 }
3854
3855 private final void stopActivityLocked(HistoryRecord r) {
3856 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3857 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3858 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3859 if (!r.finishing) {
3860 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3861 "no-history");
3862 }
3863 } else if (r.app != null && r.app.thread != null) {
3864 if (mFocusedActivity == r) {
3865 setFocusedActivityLocked(topRunningActivityLocked(null));
3866 }
3867 r.resumeKeyDispatchingLocked();
3868 try {
3869 r.stopped = false;
3870 r.state = ActivityState.STOPPING;
3871 if (DEBUG_VISBILITY) Log.v(
3872 TAG, "Stopping visible=" + r.visible + " for " + r);
3873 if (!r.visible) {
3874 mWindowManager.setAppVisibility(r, false);
3875 }
3876 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3877 } catch (Exception e) {
3878 // Maybe just ignore exceptions here... if the process
3879 // has crashed, our death notification will clean things
3880 // up.
3881 Log.w(TAG, "Exception thrown during pause", e);
3882 // Just in case, assume it to be stopped.
3883 r.stopped = true;
3884 r.state = ActivityState.STOPPED;
3885 if (r.configDestroy) {
3886 destroyActivityLocked(r, true);
3887 }
3888 }
3889 }
3890 }
3891
3892 /**
3893 * @return Returns true if the activity is being finished, false if for
3894 * some reason it is being left as-is.
3895 */
3896 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3897 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003898 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899 TAG, "Finishing activity: token=" + token
3900 + ", result=" + resultCode + ", data=" + resultData);
3901
Dianne Hackborn75b03852009-06-12 15:43:26 -07003902 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 if (index < 0) {
3904 return false;
3905 }
3906 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3907
3908 // Is this the last activity left?
3909 boolean lastActivity = true;
3910 for (int i=mHistory.size()-1; i>=0; i--) {
3911 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3912 if (!p.finishing && p != r) {
3913 lastActivity = false;
3914 break;
3915 }
3916 }
3917
3918 // If this is the last activity, but it is the home activity, then
3919 // just don't finish it.
3920 if (lastActivity) {
3921 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3922 return false;
3923 }
3924 }
3925
3926 finishActivityLocked(r, index, resultCode, resultData, reason);
3927 return true;
3928 }
3929
3930 /**
3931 * @return Returns true if this activity has been removed from the history
3932 * list, or false if it is still in the list and will be removed later.
3933 */
3934 private final boolean finishActivityLocked(HistoryRecord r, int index,
3935 int resultCode, Intent resultData, String reason) {
3936 if (r.finishing) {
3937 Log.w(TAG, "Duplicate finish request for " + r);
3938 return false;
3939 }
3940
3941 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003942 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003943 System.identityHashCode(r),
3944 r.task.taskId, r.shortComponentName, reason);
3945 r.task.numActivities--;
3946 if (r.frontOfTask && index < (mHistory.size()-1)) {
3947 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3948 if (next.task == r.task) {
3949 next.frontOfTask = true;
3950 }
3951 }
3952
3953 r.pauseKeyDispatchingLocked();
3954 if (mFocusedActivity == r) {
3955 setFocusedActivityLocked(topRunningActivityLocked(null));
3956 }
3957
3958 // send the result
3959 HistoryRecord resultTo = r.resultTo;
3960 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003961 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3962 + " who=" + r.resultWho + " req=" + r.requestCode
3963 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003964 if (r.info.applicationInfo.uid > 0) {
3965 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3966 r.packageName, resultData, r);
3967 }
3968 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3969 resultData);
3970 r.resultTo = null;
3971 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003972 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003973
3974 // Make sure this HistoryRecord is not holding on to other resources,
3975 // because clients have remote IPC references to this object so we
3976 // can't assume that will go away and want to avoid circular IPC refs.
3977 r.results = null;
3978 r.pendingResults = null;
3979 r.newIntents = null;
3980 r.icicle = null;
3981
3982 if (mPendingThumbnails.size() > 0) {
3983 // There are clients waiting to receive thumbnails so, in case
3984 // this is an activity that someone is waiting for, add it
3985 // to the pending list so we can correctly update the clients.
3986 mCancelledThumbnails.add(r);
3987 }
3988
3989 if (mResumedActivity == r) {
3990 boolean endTask = index <= 0
3991 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3992 if (DEBUG_TRANSITION) Log.v(TAG,
3993 "Prepare close transition: finishing " + r);
3994 mWindowManager.prepareAppTransition(endTask
3995 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3996 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3997
3998 // Tell window manager to prepare for this one to be removed.
3999 mWindowManager.setAppVisibility(r, false);
4000
4001 if (mPausingActivity == null) {
4002 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4003 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4004 startPausingLocked(false, false);
4005 }
4006
4007 } else if (r.state != ActivityState.PAUSING) {
4008 // If the activity is PAUSING, we will complete the finish once
4009 // it is done pausing; else we can just directly finish it here.
4010 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4011 return finishCurrentActivityLocked(r, index,
4012 FINISH_AFTER_PAUSE) == null;
4013 } else {
4014 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4015 }
4016
4017 return false;
4018 }
4019
4020 private static final int FINISH_IMMEDIATELY = 0;
4021 private static final int FINISH_AFTER_PAUSE = 1;
4022 private static final int FINISH_AFTER_VISIBLE = 2;
4023
4024 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4025 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004026 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004027 if (index < 0) {
4028 return null;
4029 }
4030
4031 return finishCurrentActivityLocked(r, index, mode);
4032 }
4033
4034 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4035 int index, int mode) {
4036 // First things first: if this activity is currently visible,
4037 // and the resumed activity is not yet visible, then hold off on
4038 // finishing until the resumed one becomes visible.
4039 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4040 if (!mStoppingActivities.contains(r)) {
4041 mStoppingActivities.add(r);
4042 if (mStoppingActivities.size() > 3) {
4043 // If we already have a few activities waiting to stop,
4044 // then give up on things going idle and start clearing
4045 // them out.
4046 Message msg = Message.obtain();
4047 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4048 mHandler.sendMessage(msg);
4049 }
4050 }
4051 r.state = ActivityState.STOPPING;
4052 updateOomAdjLocked();
4053 return r;
4054 }
4055
4056 // make sure the record is cleaned out of other places.
4057 mStoppingActivities.remove(r);
4058 mWaitingVisibleActivities.remove(r);
4059 if (mResumedActivity == r) {
4060 mResumedActivity = null;
4061 }
4062 final ActivityState prevState = r.state;
4063 r.state = ActivityState.FINISHING;
4064
4065 if (mode == FINISH_IMMEDIATELY
4066 || prevState == ActivityState.STOPPED
4067 || prevState == ActivityState.INITIALIZING) {
4068 // If this activity is already stopped, we can just finish
4069 // it right now.
4070 return destroyActivityLocked(r, true) ? null : r;
4071 } else {
4072 // Need to go through the full pause cycle to get this
4073 // activity into the stopped state and then finish it.
4074 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4075 mFinishingActivities.add(r);
4076 resumeTopActivityLocked(null);
4077 }
4078 return r;
4079 }
4080
4081 /**
4082 * This is the internal entry point for handling Activity.finish().
4083 *
4084 * @param token The Binder token referencing the Activity we want to finish.
4085 * @param resultCode Result code, if any, from this Activity.
4086 * @param resultData Result data (Intent), if any, from this Activity.
4087 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004088 * @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 -08004089 */
4090 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4091 // Refuse possible leaked file descriptors
4092 if (resultData != null && resultData.hasFileDescriptors() == true) {
4093 throw new IllegalArgumentException("File descriptors passed in Intent");
4094 }
4095
4096 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004097 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004098 // Find the first activity that is not finishing.
4099 HistoryRecord next = topRunningActivityLocked(token, 0);
4100 if (next != null) {
4101 // ask watcher if this is allowed
4102 boolean resumeOK = true;
4103 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004104 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004105 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004106 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004107 }
4108
4109 if (!resumeOK) {
4110 return false;
4111 }
4112 }
4113 }
4114 final long origId = Binder.clearCallingIdentity();
4115 boolean res = requestFinishActivityLocked(token, resultCode,
4116 resultData, "app-request");
4117 Binder.restoreCallingIdentity(origId);
4118 return res;
4119 }
4120 }
4121
4122 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4123 String resultWho, int requestCode, int resultCode, Intent data) {
4124
4125 if (callingUid > 0) {
4126 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4127 data, r);
4128 }
4129
The Android Open Source Project10592532009-03-18 17:39:46 -07004130 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4131 + " : who=" + resultWho + " req=" + requestCode
4132 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004133 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4134 try {
4135 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4136 list.add(new ResultInfo(resultWho, requestCode,
4137 resultCode, data));
4138 r.app.thread.scheduleSendResult(r, list);
4139 return;
4140 } catch (Exception e) {
4141 Log.w(TAG, "Exception thrown sending result to " + r, e);
4142 }
4143 }
4144
4145 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4146 }
4147
4148 public final void finishSubActivity(IBinder token, String resultWho,
4149 int requestCode) {
4150 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004151 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004152 if (index < 0) {
4153 return;
4154 }
4155 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4156
4157 final long origId = Binder.clearCallingIdentity();
4158
4159 int i;
4160 for (i=mHistory.size()-1; i>=0; i--) {
4161 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4162 if (r.resultTo == self && r.requestCode == requestCode) {
4163 if ((r.resultWho == null && resultWho == null) ||
4164 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4165 finishActivityLocked(r, i,
4166 Activity.RESULT_CANCELED, null, "request-sub");
4167 }
4168 }
4169 }
4170
4171 Binder.restoreCallingIdentity(origId);
4172 }
4173 }
4174
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004175 public void overridePendingTransition(IBinder token, String packageName,
4176 int enterAnim, int exitAnim) {
4177 synchronized(this) {
4178 int index = indexOfTokenLocked(token);
4179 if (index < 0) {
4180 return;
4181 }
4182 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4183
4184 final long origId = Binder.clearCallingIdentity();
4185
4186 if (self.state == ActivityState.RESUMED
4187 || self.state == ActivityState.PAUSING) {
4188 mWindowManager.overridePendingAppTransition(packageName,
4189 enterAnim, exitAnim);
4190 }
4191
4192 Binder.restoreCallingIdentity(origId);
4193 }
4194 }
4195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004196 /**
4197 * Perform clean-up of service connections in an activity record.
4198 */
4199 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4200 // Throw away any services that have been bound by this activity.
4201 if (r.connections != null) {
4202 Iterator<ConnectionRecord> it = r.connections.iterator();
4203 while (it.hasNext()) {
4204 ConnectionRecord c = it.next();
4205 removeConnectionLocked(c, null, r);
4206 }
4207 r.connections = null;
4208 }
4209 }
4210
4211 /**
4212 * Perform the common clean-up of an activity record. This is called both
4213 * as part of destroyActivityLocked() (when destroying the client-side
4214 * representation) and cleaning things up as a result of its hosting
4215 * processing going away, in which case there is no remaining client-side
4216 * state to destroy so only the cleanup here is needed.
4217 */
4218 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4219 if (mResumedActivity == r) {
4220 mResumedActivity = null;
4221 }
4222 if (mFocusedActivity == r) {
4223 mFocusedActivity = null;
4224 }
4225
4226 r.configDestroy = false;
4227 r.frozenBeforeDestroy = false;
4228
4229 // Make sure this record is no longer in the pending finishes list.
4230 // This could happen, for example, if we are trimming activities
4231 // down to the max limit while they are still waiting to finish.
4232 mFinishingActivities.remove(r);
4233 mWaitingVisibleActivities.remove(r);
4234
4235 // Remove any pending results.
4236 if (r.finishing && r.pendingResults != null) {
4237 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4238 PendingIntentRecord rec = apr.get();
4239 if (rec != null) {
4240 cancelIntentSenderLocked(rec, false);
4241 }
4242 }
4243 r.pendingResults = null;
4244 }
4245
4246 if (cleanServices) {
4247 cleanUpActivityServicesLocked(r);
4248 }
4249
4250 if (mPendingThumbnails.size() > 0) {
4251 // There are clients waiting to receive thumbnails so, in case
4252 // this is an activity that someone is waiting for, add it
4253 // to the pending list so we can correctly update the clients.
4254 mCancelledThumbnails.add(r);
4255 }
4256
4257 // Get rid of any pending idle timeouts.
4258 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4259 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4260 }
4261
4262 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4263 if (r.state != ActivityState.DESTROYED) {
4264 mHistory.remove(r);
4265 r.inHistory = false;
4266 r.state = ActivityState.DESTROYED;
4267 mWindowManager.removeAppToken(r);
4268 if (VALIDATE_TOKENS) {
4269 mWindowManager.validateAppTokens(mHistory);
4270 }
4271 cleanUpActivityServicesLocked(r);
4272 removeActivityUriPermissionsLocked(r);
4273 }
4274 }
4275
4276 /**
4277 * Destroy the current CLIENT SIDE instance of an activity. This may be
4278 * called both when actually finishing an activity, or when performing
4279 * a configuration switch where we destroy the current client-side object
4280 * but then create a new client-side object for this same HistoryRecord.
4281 */
4282 private final boolean destroyActivityLocked(HistoryRecord r,
4283 boolean removeFromApp) {
4284 if (DEBUG_SWITCH) Log.v(
4285 TAG, "Removing activity: token=" + r
4286 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004287 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004288 System.identityHashCode(r),
4289 r.task.taskId, r.shortComponentName);
4290
4291 boolean removedFromHistory = false;
4292
4293 cleanUpActivityLocked(r, false);
4294
Dianne Hackborn03abb812010-01-04 18:43:19 -08004295 final boolean hadApp = r.app != null;
4296
4297 if (hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004298 if (removeFromApp) {
4299 int idx = r.app.activities.indexOf(r);
4300 if (idx >= 0) {
4301 r.app.activities.remove(idx);
4302 }
4303 if (r.persistent) {
4304 decPersistentCountLocked(r.app);
4305 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004306 if (r.app.activities.size() == 0) {
4307 // No longer have activities, so update location in
4308 // LRU list.
4309 updateLruProcessLocked(r.app, true, false);
4310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004311 }
4312
4313 boolean skipDestroy = false;
4314
4315 try {
4316 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4317 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4318 r.configChangeFlags);
4319 } catch (Exception e) {
4320 // We can just ignore exceptions here... if the process
4321 // has crashed, our death notification will clean things
4322 // up.
4323 //Log.w(TAG, "Exception thrown during finish", e);
4324 if (r.finishing) {
4325 removeActivityFromHistoryLocked(r);
4326 removedFromHistory = true;
4327 skipDestroy = true;
4328 }
4329 }
4330
4331 r.app = null;
4332 r.nowVisible = false;
4333
4334 if (r.finishing && !skipDestroy) {
4335 r.state = ActivityState.DESTROYING;
4336 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4337 msg.obj = r;
4338 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4339 } else {
4340 r.state = ActivityState.DESTROYED;
4341 }
4342 } else {
4343 // remove this record from the history.
4344 if (r.finishing) {
4345 removeActivityFromHistoryLocked(r);
4346 removedFromHistory = true;
4347 } else {
4348 r.state = ActivityState.DESTROYED;
4349 }
4350 }
4351
4352 r.configChangeFlags = 0;
4353
Dianne Hackborn03abb812010-01-04 18:43:19 -08004354 if (!mLRUActivities.remove(r) && hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004355 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4356 }
4357
4358 return removedFromHistory;
4359 }
4360
Dianne Hackborn03abb812010-01-04 18:43:19 -08004361 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004362 int i = list.size();
4363 if (localLOGV) Log.v(
4364 TAG, "Removing app " + app + " from list " + list
4365 + " with " + i + " entries");
4366 while (i > 0) {
4367 i--;
4368 HistoryRecord r = (HistoryRecord)list.get(i);
4369 if (localLOGV) Log.v(
4370 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4371 if (r.app == app) {
4372 if (localLOGV) Log.v(TAG, "Removing this entry!");
4373 list.remove(i);
4374 }
4375 }
4376 }
4377
4378 /**
4379 * Main function for removing an existing process from the activity manager
4380 * as a result of that process going away. Clears out all connections
4381 * to the process.
4382 */
4383 private final void handleAppDiedLocked(ProcessRecord app,
4384 boolean restarting) {
4385 cleanUpApplicationRecordLocked(app, restarting, -1);
4386 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004387 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004388 }
4389
4390 // Just in case...
4391 if (mPausingActivity != null && mPausingActivity.app == app) {
4392 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4393 mPausingActivity = null;
4394 }
4395 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4396 mLastPausedActivity = null;
4397 }
4398
4399 // Remove this application's activities from active lists.
4400 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4401 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4402 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4403 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4404
4405 boolean atTop = true;
4406 boolean hasVisibleActivities = false;
4407
4408 // Clean out the history list.
4409 int i = mHistory.size();
4410 if (localLOGV) Log.v(
4411 TAG, "Removing app " + app + " from history with " + i + " entries");
4412 while (i > 0) {
4413 i--;
4414 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4415 if (localLOGV) Log.v(
4416 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4417 if (r.app == app) {
4418 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4419 if (localLOGV) Log.v(
4420 TAG, "Removing this entry! frozen=" + r.haveState
4421 + " finishing=" + r.finishing);
4422 mHistory.remove(i);
4423
4424 r.inHistory = false;
4425 mWindowManager.removeAppToken(r);
4426 if (VALIDATE_TOKENS) {
4427 mWindowManager.validateAppTokens(mHistory);
4428 }
4429 removeActivityUriPermissionsLocked(r);
4430
4431 } else {
4432 // We have the current state for this activity, so
4433 // it can be restarted later when needed.
4434 if (localLOGV) Log.v(
4435 TAG, "Keeping entry, setting app to null");
4436 if (r.visible) {
4437 hasVisibleActivities = true;
4438 }
4439 r.app = null;
4440 r.nowVisible = false;
4441 if (!r.haveState) {
4442 r.icicle = null;
4443 }
4444 }
4445
4446 cleanUpActivityLocked(r, true);
4447 r.state = ActivityState.STOPPED;
4448 }
4449 atTop = false;
4450 }
4451
4452 app.activities.clear();
4453
4454 if (app.instrumentationClass != null) {
4455 Log.w(TAG, "Crash of app " + app.processName
4456 + " running instrumentation " + app.instrumentationClass);
4457 Bundle info = new Bundle();
4458 info.putString("shortMsg", "Process crashed.");
4459 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4460 }
4461
4462 if (!restarting) {
4463 if (!resumeTopActivityLocked(null)) {
4464 // If there was nothing to resume, and we are not already
4465 // restarting this process, but there is a visible activity that
4466 // is hosted by the process... then make sure all visible
4467 // activities are running, taking care of restarting this
4468 // process.
4469 if (hasVisibleActivities) {
4470 ensureActivitiesVisibleLocked(null, 0);
4471 }
4472 }
4473 }
4474 }
4475
4476 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4477 IBinder threadBinder = thread.asBinder();
4478
4479 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004480 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4481 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004482 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4483 return i;
4484 }
4485 }
4486 return -1;
4487 }
4488
4489 private final ProcessRecord getRecordForAppLocked(
4490 IApplicationThread thread) {
4491 if (thread == null) {
4492 return null;
4493 }
4494
4495 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004496 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004497 }
4498
4499 private final void appDiedLocked(ProcessRecord app, int pid,
4500 IApplicationThread thread) {
4501
4502 mProcDeaths[0]++;
4503
4504 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4505 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4506 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004507 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004508 if (localLOGV) Log.v(
4509 TAG, "Dying app: " + app + ", pid: " + pid
4510 + ", thread: " + thread.asBinder());
4511 boolean doLowMem = app.instrumentationClass == null;
4512 handleAppDiedLocked(app, false);
4513
4514 if (doLowMem) {
4515 // If there are no longer any background processes running,
4516 // and the app that died was not running instrumentation,
4517 // then tell everyone we are now low on memory.
4518 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004519 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4520 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004521 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4522 haveBg = true;
4523 break;
4524 }
4525 }
4526
4527 if (!haveBg) {
4528 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004529 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004530 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004531 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4532 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004533 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004534 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4535 // The low memory report is overriding any current
4536 // state for a GC request. Make sure to do
4537 // visible/foreground processes first.
4538 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4539 rec.lastRequestedGc = 0;
4540 } else {
4541 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004542 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004543 rec.reportLowMemory = true;
4544 rec.lastLowMemory = now;
4545 mProcessesToGc.remove(rec);
4546 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004547 }
4548 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004549 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004550 }
4551 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004552 } else if (DEBUG_PROCESSES) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004553 Log.d(TAG, "Received spurious death notification for thread "
4554 + thread.asBinder());
4555 }
4556 }
4557
Dan Egnor42471dd2010-01-07 17:25:22 -08004558 /**
4559 * If a stack trace dump file is configured, dump process stack traces.
4560 * @param pids of dalvik VM processes to dump stack traces for
4561 * @return file containing stack traces, or null if no dump file is configured
4562 */
4563 private static File dumpStackTraces(ArrayList<Integer> pids) {
4564 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4565 if (tracesPath == null || tracesPath.length() == 0) {
4566 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004567 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004568
4569 File tracesFile = new File(tracesPath);
4570 try {
4571 File tracesDir = tracesFile.getParentFile();
4572 if (!tracesDir.exists()) tracesFile.mkdirs();
4573 FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
4574
4575 if (tracesFile.exists()) tracesFile.delete();
4576 tracesFile.createNewFile();
4577 FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
4578 } catch (IOException e) {
4579 Log.w(TAG, "Unable to prepare ANR traces file: " + tracesPath, e);
4580 return null;
4581 }
4582
4583 // Use a FileObserver to detect when traces finish writing.
4584 // The order of traces is considered important to maintain for legibility.
4585 FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
4586 public synchronized void onEvent(int event, String path) { notify(); }
4587 };
4588
4589 try {
4590 observer.startWatching();
4591 int num = pids.size();
4592 for (int i = 0; i < num; i++) {
4593 synchronized (observer) {
4594 Process.sendSignal(pids.get(i), Process.SIGNAL_QUIT);
4595 observer.wait(200); // Wait for write-close, give up after 200msec
4596 }
4597 }
4598 } catch (InterruptedException e) {
4599 Log.wtf(TAG, e);
4600 } finally {
4601 observer.stopWatching();
4602 }
4603
4604 return tracesFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004605 }
4606
Dan Egnor42471dd2010-01-07 17:25:22 -08004607 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4608 HistoryRecord parent, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004609 if (app.notResponding || app.crashing) {
4610 return;
4611 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004613 // Log the ANR to the event log.
Dan Egnor2780e732010-01-22 14:47:35 -08004614 EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
4615 annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004616
Dan Egnor42471dd2010-01-07 17:25:22 -08004617 // Dump thread traces as quickly as we can, starting with "interesting" processes.
4618 ArrayList<Integer> pids = new ArrayList<Integer>(20);
4619 pids.add(app.pid);
4620
4621 int parentPid = app.pid;
4622 if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
4623 if (parentPid != app.pid) pids.add(parentPid);
4624
4625 if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
4626
4627 for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
4628 ProcessRecord r = mLruProcesses.get(i);
4629 if (r != null && r.thread != null) {
4630 int pid = r.pid;
4631 if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004632 }
4633 }
4634
Dan Egnor42471dd2010-01-07 17:25:22 -08004635 File tracesFile = dumpStackTraces(pids);
4636
4637 // Log the ANR to the main log.
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004638 StringBuilder info = mStringBuilder;
4639 info.setLength(0);
Dan Egnor42471dd2010-01-07 17:25:22 -08004640 info.append("ANR in ").append(app.processName);
4641 if (activity != null && activity.shortComponentName != null) {
4642 info.append(" (").append(activity.shortComponentName).append(")");
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004644 if (annotation != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004645 info.append("\nReason: ").append(annotation).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004646 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004647 if (parent != null && parent != activity) {
4648 info.append("\nParent: ").append(parent.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004650
Dan Egnor42471dd2010-01-07 17:25:22 -08004651 String cpuInfo = null;
4652 if (MONITOR_CPU_USAGE) {
4653 updateCpuStatsNow();
4654 synchronized (mProcessStatsThread) { cpuInfo = mProcessStats.printCurrentState(); }
4655 info.append(cpuInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004656 }
4657
Dan Egnor42471dd2010-01-07 17:25:22 -08004658 Log.e(TAG, info.toString());
4659 if (tracesFile == null) {
4660 // There is no trace file, so dump (only) the alleged culprit's threads to the log
4661 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4662 }
4663
4664 addErrorToDropBox("anr", app, activity, parent, annotation, cpuInfo, tracesFile, null);
4665
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004666 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004667 try {
Dan Egnor42471dd2010-01-07 17:25:22 -08004668 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
4669 int res = mController.appNotResponding(app.processName, app.pid, info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004670 if (res != 0) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004671 if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
4672 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004673 }
4674 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004675 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004676 }
4677 }
4678
Dan Egnor42471dd2010-01-07 17:25:22 -08004679 // Unless configured otherwise, swallow ANRs in background processes & kill the process.
4680 boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
4681 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
4682 if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
4683 Process.killProcess(app.pid);
4684 return;
4685 }
4686
4687 // Set the app's notResponding state, and look up the errorReportReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004688 makeAppNotRespondingLocked(app,
4689 activity != null ? activity.shortComponentName : null,
4690 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004691 info.toString());
Dan Egnor42471dd2010-01-07 17:25:22 -08004692
4693 // Bring up the infamous App Not Responding dialog
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004694 Message msg = Message.obtain();
4695 HashMap map = new HashMap();
4696 msg.what = SHOW_NOT_RESPONDING_MSG;
4697 msg.obj = map;
4698 map.put("app", app);
4699 if (activity != null) {
4700 map.put("activity", activity);
4701 }
4702
4703 mHandler.sendMessage(msg);
4704 return;
4705 }
4706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004707 private final void decPersistentCountLocked(ProcessRecord app)
4708 {
4709 app.persistentActivities--;
4710 if (app.persistentActivities > 0) {
4711 // Still more of 'em...
4712 return;
4713 }
4714 if (app.persistent) {
4715 // Ah, but the application itself is persistent. Whatever!
4716 return;
4717 }
4718
4719 // App is no longer persistent... make sure it and the ones
4720 // following it in the LRU list have the correc oom_adj.
4721 updateOomAdjLocked();
4722 }
4723
4724 public void setPersistent(IBinder token, boolean isPersistent) {
4725 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4726 != PackageManager.PERMISSION_GRANTED) {
4727 String msg = "Permission Denial: setPersistent() from pid="
4728 + Binder.getCallingPid()
4729 + ", uid=" + Binder.getCallingUid()
4730 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4731 Log.w(TAG, msg);
4732 throw new SecurityException(msg);
4733 }
4734
4735 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004736 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004737 if (index < 0) {
4738 return;
4739 }
4740 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4741 ProcessRecord app = r.app;
4742
4743 if (localLOGV) Log.v(
4744 TAG, "Setting persistence " + isPersistent + ": " + r);
4745
4746 if (isPersistent) {
4747 if (r.persistent) {
4748 // Okay okay, I heard you already!
4749 if (localLOGV) Log.v(TAG, "Already persistent!");
4750 return;
4751 }
4752 r.persistent = true;
4753 app.persistentActivities++;
4754 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4755 if (app.persistentActivities > 1) {
4756 // We aren't the first...
4757 if (localLOGV) Log.v(TAG, "Not the first!");
4758 return;
4759 }
4760 if (app.persistent) {
4761 // This would be redundant.
4762 if (localLOGV) Log.v(TAG, "App is persistent!");
4763 return;
4764 }
4765
4766 // App is now persistent... make sure it and the ones
4767 // following it now have the correct oom_adj.
4768 final long origId = Binder.clearCallingIdentity();
4769 updateOomAdjLocked();
4770 Binder.restoreCallingIdentity(origId);
4771
4772 } else {
4773 if (!r.persistent) {
4774 // Okay okay, I heard you already!
4775 return;
4776 }
4777 r.persistent = false;
4778 final long origId = Binder.clearCallingIdentity();
4779 decPersistentCountLocked(app);
4780 Binder.restoreCallingIdentity(origId);
4781
4782 }
4783 }
4784 }
4785
4786 public boolean clearApplicationUserData(final String packageName,
4787 final IPackageDataObserver observer) {
4788 int uid = Binder.getCallingUid();
4789 int pid = Binder.getCallingPid();
4790 long callingId = Binder.clearCallingIdentity();
4791 try {
4792 IPackageManager pm = ActivityThread.getPackageManager();
4793 int pkgUid = -1;
4794 synchronized(this) {
4795 try {
4796 pkgUid = pm.getPackageUid(packageName);
4797 } catch (RemoteException e) {
4798 }
4799 if (pkgUid == -1) {
4800 Log.w(TAG, "Invalid packageName:" + packageName);
4801 return false;
4802 }
4803 if (uid == pkgUid || checkComponentPermission(
4804 android.Manifest.permission.CLEAR_APP_USER_DATA,
4805 pid, uid, -1)
4806 == PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08004807 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004808 } else {
4809 throw new SecurityException(pid+" does not have permission:"+
4810 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4811 "for process:"+packageName);
4812 }
4813 }
4814
4815 try {
4816 //clear application user data
4817 pm.clearApplicationUserData(packageName, observer);
4818 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4819 Uri.fromParts("package", packageName, null));
4820 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4821 broadcastIntentLocked(null, null, intent,
4822 null, null, 0, null, null, null,
4823 false, false, MY_PID, Process.SYSTEM_UID);
4824 } catch (RemoteException e) {
4825 }
4826 } finally {
4827 Binder.restoreCallingIdentity(callingId);
4828 }
4829 return true;
4830 }
4831
Dianne Hackborn03abb812010-01-04 18:43:19 -08004832 public void killBackgroundProcesses(final String packageName) {
4833 if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
4834 != PackageManager.PERMISSION_GRANTED &&
4835 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4836 != PackageManager.PERMISSION_GRANTED) {
4837 String msg = "Permission Denial: killBackgroundProcesses() from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004838 + Binder.getCallingPid()
4839 + ", uid=" + Binder.getCallingUid()
Dianne Hackborn03abb812010-01-04 18:43:19 -08004840 + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004841 Log.w(TAG, msg);
4842 throw new SecurityException(msg);
4843 }
4844
4845 long callingId = Binder.clearCallingIdentity();
4846 try {
4847 IPackageManager pm = ActivityThread.getPackageManager();
4848 int pkgUid = -1;
4849 synchronized(this) {
4850 try {
4851 pkgUid = pm.getPackageUid(packageName);
4852 } catch (RemoteException e) {
4853 }
4854 if (pkgUid == -1) {
4855 Log.w(TAG, "Invalid packageName: " + packageName);
4856 return;
4857 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004858 killPackageProcessesLocked(packageName, pkgUid,
4859 SECONDARY_SERVER_ADJ, false);
4860 }
4861 } finally {
4862 Binder.restoreCallingIdentity(callingId);
4863 }
4864 }
4865
4866 public void forceStopPackage(final String packageName) {
4867 if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
4868 != PackageManager.PERMISSION_GRANTED) {
4869 String msg = "Permission Denial: forceStopPackage() from pid="
4870 + Binder.getCallingPid()
4871 + ", uid=" + Binder.getCallingUid()
4872 + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
4873 Log.w(TAG, msg);
4874 throw new SecurityException(msg);
4875 }
4876
4877 long callingId = Binder.clearCallingIdentity();
4878 try {
4879 IPackageManager pm = ActivityThread.getPackageManager();
4880 int pkgUid = -1;
4881 synchronized(this) {
4882 try {
4883 pkgUid = pm.getPackageUid(packageName);
4884 } catch (RemoteException e) {
4885 }
4886 if (pkgUid == -1) {
4887 Log.w(TAG, "Invalid packageName: " + packageName);
4888 return;
4889 }
4890 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004891 }
4892 } finally {
4893 Binder.restoreCallingIdentity(callingId);
4894 }
4895 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004896
4897 /*
4898 * The pkg name and uid have to be specified.
4899 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4900 */
4901 public void killApplicationWithUid(String pkg, int uid) {
4902 if (pkg == null) {
4903 return;
4904 }
4905 // Make sure the uid is valid.
4906 if (uid < 0) {
4907 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4908 return;
4909 }
4910 int callerUid = Binder.getCallingUid();
4911 // Only the system server can kill an application
4912 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004913 // Post an aysnc message to kill the application
4914 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4915 msg.arg1 = uid;
4916 msg.arg2 = 0;
4917 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004918 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004919 } else {
4920 throw new SecurityException(callerUid + " cannot kill pkg: " +
4921 pkg);
4922 }
4923 }
4924
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004925 public void closeSystemDialogs(String reason) {
4926 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4927 if (reason != null) {
4928 intent.putExtra("reason", reason);
4929 }
4930
4931 final int uid = Binder.getCallingUid();
4932 final long origId = Binder.clearCallingIdentity();
4933 synchronized (this) {
4934 int i = mWatchers.beginBroadcast();
4935 while (i > 0) {
4936 i--;
4937 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4938 if (w != null) {
4939 try {
4940 w.closingSystemDialogs(reason);
4941 } catch (RemoteException e) {
4942 }
4943 }
4944 }
4945 mWatchers.finishBroadcast();
4946
Dianne Hackbornffa42482009-09-23 22:20:11 -07004947 mWindowManager.closeSystemDialogs(reason);
4948
4949 for (i=mHistory.size()-1; i>=0; i--) {
4950 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4951 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4952 finishActivityLocked(r, i,
4953 Activity.RESULT_CANCELED, null, "close-sys");
4954 }
4955 }
4956
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004957 broadcastIntentLocked(null, null, intent, null,
4958 null, 0, null, null, null, false, false, -1, uid);
4959 }
4960 Binder.restoreCallingIdentity(origId);
4961 }
4962
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004963 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004964 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004965 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4966 for (int i=pids.length-1; i>=0; i--) {
4967 infos[i] = new Debug.MemoryInfo();
4968 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004969 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004970 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004971 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004972
4973 public void killApplicationProcess(String processName, int uid) {
4974 if (processName == null) {
4975 return;
4976 }
4977
4978 int callerUid = Binder.getCallingUid();
4979 // Only the system server can kill an application
4980 if (callerUid == Process.SYSTEM_UID) {
4981 synchronized (this) {
4982 ProcessRecord app = getProcessRecordLocked(processName, uid);
4983 if (app != null) {
4984 try {
4985 app.thread.scheduleSuicide();
4986 } catch (RemoteException e) {
4987 // If the other end already died, then our work here is done.
4988 }
4989 } else {
4990 Log.w(TAG, "Process/uid not found attempting kill of "
4991 + processName + " / " + uid);
4992 }
4993 }
4994 } else {
4995 throw new SecurityException(callerUid + " cannot kill app process: " +
4996 processName);
4997 }
4998 }
4999
Dianne Hackborn03abb812010-01-04 18:43:19 -08005000 private void forceStopPackageLocked(final String packageName, int uid) {
5001 forceStopPackageLocked(packageName, uid, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005002 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5003 Uri.fromParts("package", packageName, null));
5004 intent.putExtra(Intent.EXTRA_UID, uid);
5005 broadcastIntentLocked(null, null, intent,
5006 null, null, 0, null, null, null,
5007 false, false, MY_PID, Process.SYSTEM_UID);
5008 }
5009
Dianne Hackborn03abb812010-01-04 18:43:19 -08005010 private final void killPackageProcessesLocked(String packageName, int uid,
5011 int minOomAdj, boolean callerWillRestart) {
5012 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005013
Dianne Hackborn03abb812010-01-04 18:43:19 -08005014 // Remove all processes this package may have touched: all with the
5015 // same UID (except for the system or root user), and all whose name
5016 // matches the package name.
5017 final String procNamePrefix = packageName + ":";
5018 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5019 final int NA = apps.size();
5020 for (int ia=0; ia<NA; ia++) {
5021 ProcessRecord app = apps.valueAt(ia);
5022 if (app.removed) {
5023 procs.add(app);
5024 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5025 || app.processName.equals(packageName)
5026 || app.processName.startsWith(procNamePrefix)) {
5027 if (app.setAdj >= minOomAdj) {
5028 app.removed = true;
5029 procs.add(app);
5030 }
5031 }
5032 }
5033 }
5034
5035 int N = procs.size();
5036 for (int i=0; i<N; i++) {
5037 removeProcessLocked(procs.get(i), callerWillRestart);
5038 }
5039 }
5040
5041 private final void forceStopPackageLocked(String name, int uid,
5042 boolean callerWillRestart) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005043 int i, N;
5044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005045 if (uid < 0) {
5046 try {
5047 uid = ActivityThread.getPackageManager().getPackageUid(name);
5048 } catch (RemoteException e) {
5049 }
5050 }
5051
Dianne Hackborn03abb812010-01-04 18:43:19 -08005052 Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
5053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005054 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5055 while (badApps.hasNext()) {
5056 SparseArray<Long> ba = badApps.next();
5057 if (ba.get(uid) != null) {
5058 badApps.remove();
5059 }
5060 }
5061
Dianne Hackborn03abb812010-01-04 18:43:19 -08005062 killPackageProcessesLocked(name, uid, -100, callerWillRestart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005063
5064 for (i=mHistory.size()-1; i>=0; i--) {
5065 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5066 if (r.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005067 Log.i(TAG, " Force finishing activity " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005068 if (r.app != null) {
5069 r.app.removed = true;
5070 }
5071 r.app = null;
5072 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5073 }
5074 }
5075
5076 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5077 for (ServiceRecord service : mServices.values()) {
5078 if (service.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005079 Log.i(TAG, " Force stopping service " + service);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005080 if (service.app != null) {
5081 service.app.removed = true;
5082 }
5083 service.app = null;
5084 services.add(service);
5085 }
5086 }
5087
5088 N = services.size();
5089 for (i=0; i<N; i++) {
5090 bringDownServiceLocked(services.get(i), true);
5091 }
5092
5093 resumeTopActivityLocked(null);
5094 }
5095
5096 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5097 final String name = app.processName;
5098 final int uid = app.info.uid;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005099 if (DEBUG_PROCESSES) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005100 TAG, "Force removing process " + app + " (" + name
5101 + "/" + uid + ")");
5102
5103 mProcessNames.remove(name, uid);
5104 boolean needRestart = false;
5105 if (app.pid > 0 && app.pid != MY_PID) {
5106 int pid = app.pid;
5107 synchronized (mPidsSelfLocked) {
5108 mPidsSelfLocked.remove(pid);
5109 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5110 }
5111 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005112 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005113 Process.killProcess(pid);
5114
5115 if (app.persistent) {
5116 if (!callerWillRestart) {
5117 addAppLocked(app.info);
5118 } else {
5119 needRestart = true;
5120 }
5121 }
5122 } else {
5123 mRemovedProcesses.add(app);
5124 }
5125
5126 return needRestart;
5127 }
5128
5129 private final void processStartTimedOutLocked(ProcessRecord app) {
5130 final int pid = app.pid;
5131 boolean gone = false;
5132 synchronized (mPidsSelfLocked) {
5133 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5134 if (knownApp != null && knownApp.thread == null) {
5135 mPidsSelfLocked.remove(pid);
5136 gone = true;
5137 }
5138 }
5139
5140 if (gone) {
5141 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005142 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005143 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005144 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005145 // Take care of any launching providers waiting for this process.
5146 checkAppInLaunchingProvidersLocked(app, true);
5147 // Take care of any services that are waiting for the process.
5148 for (int i=0; i<mPendingServices.size(); i++) {
5149 ServiceRecord sr = mPendingServices.get(i);
5150 if (app.info.uid == sr.appInfo.uid
5151 && app.processName.equals(sr.processName)) {
5152 Log.w(TAG, "Forcing bringing down service: " + sr);
5153 mPendingServices.remove(i);
5154 i--;
5155 bringDownServiceLocked(sr, true);
5156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005157 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005158 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005159 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5160 Log.w(TAG, "Unattached app died before backup, skipping");
5161 try {
5162 IBackupManager bm = IBackupManager.Stub.asInterface(
5163 ServiceManager.getService(Context.BACKUP_SERVICE));
5164 bm.agentDisconnected(app.info.packageName);
5165 } catch (RemoteException e) {
5166 // Can't happen; the backup manager is local
5167 }
5168 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005169 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5170 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5171 mPendingBroadcast = null;
5172 scheduleBroadcastsLocked();
5173 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005174 } else {
5175 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5176 }
5177 }
5178
5179 private final boolean attachApplicationLocked(IApplicationThread thread,
5180 int pid) {
5181
5182 // Find the application record that is being attached... either via
5183 // the pid if we are running in multiple processes, or just pull the
5184 // next app record if we are emulating process with anonymous threads.
5185 ProcessRecord app;
5186 if (pid != MY_PID && pid >= 0) {
5187 synchronized (mPidsSelfLocked) {
5188 app = mPidsSelfLocked.get(pid);
5189 }
5190 } else if (mStartingProcesses.size() > 0) {
5191 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005192 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005193 } else {
5194 app = null;
5195 }
5196
5197 if (app == null) {
5198 Log.w(TAG, "No pending application record for pid " + pid
5199 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005200 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005201 if (pid > 0 && pid != MY_PID) {
5202 Process.killProcess(pid);
5203 } else {
5204 try {
5205 thread.scheduleExit();
5206 } catch (Exception e) {
5207 // Ignore exceptions.
5208 }
5209 }
5210 return false;
5211 }
5212
5213 // If this application record is still attached to a previous
5214 // process, clean it up now.
5215 if (app.thread != null) {
5216 handleAppDiedLocked(app, true);
5217 }
5218
5219 // Tell the process all about itself.
5220
5221 if (localLOGV) Log.v(
5222 TAG, "Binding process pid " + pid + " to record " + app);
5223
5224 String processName = app.processName;
5225 try {
5226 thread.asBinder().linkToDeath(new AppDeathRecipient(
5227 app, pid, thread), 0);
5228 } catch (RemoteException e) {
5229 app.resetPackageList();
5230 startProcessLocked(app, "link fail", processName);
5231 return false;
5232 }
5233
Doug Zongker2bec3d42009-12-04 12:52:44 -08005234 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005235
5236 app.thread = thread;
5237 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005238 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5239 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005240 app.forcingToForeground = null;
5241 app.foregroundServices = false;
5242 app.debugging = false;
5243
5244 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5245
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005246 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5247 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005248
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005249 if (!normalMode) {
5250 Log.i(TAG, "Launching preboot mode app: " + app);
5251 }
5252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005253 if (localLOGV) Log.v(
5254 TAG, "New app record " + app
5255 + " thread=" + thread.asBinder() + " pid=" + pid);
5256 try {
5257 int testMode = IApplicationThread.DEBUG_OFF;
5258 if (mDebugApp != null && mDebugApp.equals(processName)) {
5259 testMode = mWaitForDebugger
5260 ? IApplicationThread.DEBUG_WAIT
5261 : IApplicationThread.DEBUG_ON;
5262 app.debugging = true;
5263 if (mDebugTransient) {
5264 mDebugApp = mOrigDebugApp;
5265 mWaitForDebugger = mOrigWaitForDebugger;
5266 }
5267 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005268
Christopher Tate181fafa2009-05-14 11:12:14 -07005269 // If the app is being launched for restore or full backup, set it up specially
5270 boolean isRestrictedBackupMode = false;
5271 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5272 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5273 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5274 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005275
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005276 ensurePackageDexOpt(app.instrumentationInfo != null
5277 ? app.instrumentationInfo.packageName
5278 : app.info.packageName);
5279 if (app.instrumentationClass != null) {
5280 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005281 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005282 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5283 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005284 thread.bindApplication(processName, app.instrumentationInfo != null
5285 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005286 app.instrumentationClass, app.instrumentationProfileFile,
5287 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005288 isRestrictedBackupMode || !normalMode,
5289 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005290 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005291 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005292 } catch (Exception e) {
5293 // todo: Yikes! What should we do? For now we will try to
5294 // start another process, but that could easily get us in
5295 // an infinite loop of restarting processes...
5296 Log.w(TAG, "Exception thrown during bind!", e);
5297
5298 app.resetPackageList();
5299 startProcessLocked(app, "bind fail", processName);
5300 return false;
5301 }
5302
5303 // Remove this record from the list of starting applications.
5304 mPersistentStartingProcesses.remove(app);
5305 mProcessesOnHold.remove(app);
5306
5307 boolean badApp = false;
5308 boolean didSomething = false;
5309
5310 // See if the top visible activity is waiting to run in this process...
5311 HistoryRecord hr = topRunningActivityLocked(null);
5312 if (hr != null) {
5313 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5314 && processName.equals(hr.processName)) {
5315 try {
5316 if (realStartActivityLocked(hr, app, true, true)) {
5317 didSomething = true;
5318 }
5319 } catch (Exception e) {
5320 Log.w(TAG, "Exception in new application when starting activity "
5321 + hr.intent.getComponent().flattenToShortString(), e);
5322 badApp = true;
5323 }
5324 } else {
5325 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5326 }
5327 }
5328
5329 // Find any services that should be running in this process...
5330 if (!badApp && mPendingServices.size() > 0) {
5331 ServiceRecord sr = null;
5332 try {
5333 for (int i=0; i<mPendingServices.size(); i++) {
5334 sr = mPendingServices.get(i);
5335 if (app.info.uid != sr.appInfo.uid
5336 || !processName.equals(sr.processName)) {
5337 continue;
5338 }
5339
5340 mPendingServices.remove(i);
5341 i--;
5342 realStartServiceLocked(sr, app);
5343 didSomething = true;
5344 }
5345 } catch (Exception e) {
5346 Log.w(TAG, "Exception in new application when starting service "
5347 + sr.shortName, e);
5348 badApp = true;
5349 }
5350 }
5351
5352 // Check if the next broadcast receiver is in this process...
5353 BroadcastRecord br = mPendingBroadcast;
5354 if (!badApp && br != null && br.curApp == app) {
5355 try {
5356 mPendingBroadcast = null;
5357 processCurBroadcastLocked(br, app);
5358 didSomething = true;
5359 } catch (Exception e) {
5360 Log.w(TAG, "Exception in new application when starting receiver "
5361 + br.curComponent.flattenToShortString(), e);
5362 badApp = true;
5363 logBroadcastReceiverDiscard(br);
5364 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5365 br.resultExtras, br.resultAbort, true);
5366 scheduleBroadcastsLocked();
5367 }
5368 }
5369
Christopher Tate181fafa2009-05-14 11:12:14 -07005370 // Check whether the next backup agent is in this process...
5371 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5372 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005373 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005374 try {
5375 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5376 } catch (Exception e) {
5377 Log.w(TAG, "Exception scheduling backup agent creation: ");
5378 e.printStackTrace();
5379 }
5380 }
5381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005382 if (badApp) {
5383 // todo: Also need to kill application to deal with all
5384 // kinds of exceptions.
5385 handleAppDiedLocked(app, false);
5386 return false;
5387 }
5388
5389 if (!didSomething) {
5390 updateOomAdjLocked();
5391 }
5392
5393 return true;
5394 }
5395
5396 public final void attachApplication(IApplicationThread thread) {
5397 synchronized (this) {
5398 int callingPid = Binder.getCallingPid();
5399 final long origId = Binder.clearCallingIdentity();
5400 attachApplicationLocked(thread, callingPid);
5401 Binder.restoreCallingIdentity(origId);
5402 }
5403 }
5404
Dianne Hackborne88846e2009-09-30 21:34:25 -07005405 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005406 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005407 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005408 Binder.restoreCallingIdentity(origId);
5409 }
5410
5411 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5412 boolean remove) {
5413 int N = mStoppingActivities.size();
5414 if (N <= 0) return null;
5415
5416 ArrayList<HistoryRecord> stops = null;
5417
5418 final boolean nowVisible = mResumedActivity != null
5419 && mResumedActivity.nowVisible
5420 && !mResumedActivity.waitingVisible;
5421 for (int i=0; i<N; i++) {
5422 HistoryRecord s = mStoppingActivities.get(i);
5423 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5424 + nowVisible + " waitingVisible=" + s.waitingVisible
5425 + " finishing=" + s.finishing);
5426 if (s.waitingVisible && nowVisible) {
5427 mWaitingVisibleActivities.remove(s);
5428 s.waitingVisible = false;
5429 if (s.finishing) {
5430 // If this activity is finishing, it is sitting on top of
5431 // everyone else but we now know it is no longer needed...
5432 // so get rid of it. Otherwise, we need to go through the
5433 // normal flow and hide it once we determine that it is
5434 // hidden by the activities in front of it.
5435 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5436 mWindowManager.setAppVisibility(s, false);
5437 }
5438 }
5439 if (!s.waitingVisible && remove) {
5440 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5441 if (stops == null) {
5442 stops = new ArrayList<HistoryRecord>();
5443 }
5444 stops.add(s);
5445 mStoppingActivities.remove(i);
5446 N--;
5447 i--;
5448 }
5449 }
5450
5451 return stops;
5452 }
5453
5454 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005455 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005456 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005457 mWindowManager.enableScreenAfterBoot();
5458 }
5459
Dianne Hackborne88846e2009-09-30 21:34:25 -07005460 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5461 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005462 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5463
5464 ArrayList<HistoryRecord> stops = null;
5465 ArrayList<HistoryRecord> finishes = null;
5466 ArrayList<HistoryRecord> thumbnails = null;
5467 int NS = 0;
5468 int NF = 0;
5469 int NT = 0;
5470 IApplicationThread sendThumbnail = null;
5471 boolean booting = false;
5472 boolean enableScreen = false;
5473
5474 synchronized (this) {
5475 if (token != null) {
5476 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5477 }
5478
5479 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005480 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005481 if (index >= 0) {
5482 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5483
Dianne Hackborne88846e2009-09-30 21:34:25 -07005484 // This is a hack to semi-deal with a race condition
5485 // in the client where it can be constructed with a
5486 // newer configuration from when we asked it to launch.
5487 // We'll update with whatever configuration it now says
5488 // it used to launch.
5489 if (config != null) {
5490 r.configuration = config;
5491 }
5492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005493 // No longer need to keep the device awake.
5494 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5495 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5496 mLaunchingActivity.release();
5497 }
5498
5499 // We are now idle. If someone is waiting for a thumbnail from
5500 // us, we can now deliver.
5501 r.idle = true;
5502 scheduleAppGcsLocked();
5503 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5504 sendThumbnail = r.app.thread;
5505 r.thumbnailNeeded = false;
5506 }
5507
5508 // If this activity is fullscreen, set up to hide those under it.
5509
5510 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5511 ensureActivitiesVisibleLocked(null, 0);
5512
5513 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5514 if (!mBooted && !fromTimeout) {
5515 mBooted = true;
5516 enableScreen = true;
5517 }
5518 }
5519
5520 // Atomically retrieve all of the other things to do.
5521 stops = processStoppingActivitiesLocked(true);
5522 NS = stops != null ? stops.size() : 0;
5523 if ((NF=mFinishingActivities.size()) > 0) {
5524 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5525 mFinishingActivities.clear();
5526 }
5527 if ((NT=mCancelledThumbnails.size()) > 0) {
5528 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5529 mCancelledThumbnails.clear();
5530 }
5531
5532 booting = mBooting;
5533 mBooting = false;
5534 }
5535
5536 int i;
5537
5538 // Send thumbnail if requested.
5539 if (sendThumbnail != null) {
5540 try {
5541 sendThumbnail.requestThumbnail(token);
5542 } catch (Exception e) {
5543 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5544 sendPendingThumbnail(null, token, null, null, true);
5545 }
5546 }
5547
5548 // Stop any activities that are scheduled to do so but have been
5549 // waiting for the next one to start.
5550 for (i=0; i<NS; i++) {
5551 HistoryRecord r = (HistoryRecord)stops.get(i);
5552 synchronized (this) {
5553 if (r.finishing) {
5554 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5555 } else {
5556 stopActivityLocked(r);
5557 }
5558 }
5559 }
5560
5561 // Finish any activities that are scheduled to do so but have been
5562 // waiting for the next one to start.
5563 for (i=0; i<NF; i++) {
5564 HistoryRecord r = (HistoryRecord)finishes.get(i);
5565 synchronized (this) {
5566 destroyActivityLocked(r, true);
5567 }
5568 }
5569
5570 // Report back to any thumbnail receivers.
5571 for (i=0; i<NT; i++) {
5572 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5573 sendPendingThumbnail(r, null, null, null, true);
5574 }
5575
5576 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005577 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005578 }
5579
5580 trimApplications();
5581 //dump();
5582 //mWindowManager.dump();
5583
5584 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005585 enableScreenAfterBoot();
5586 }
5587 }
5588
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005589 final void finishBooting() {
5590 // Ensure that any processes we had put on hold are now started
5591 // up.
5592 final int NP = mProcessesOnHold.size();
5593 if (NP > 0) {
5594 ArrayList<ProcessRecord> procs =
5595 new ArrayList<ProcessRecord>(mProcessesOnHold);
5596 for (int ip=0; ip<NP; ip++) {
5597 this.startProcessLocked(procs.get(ip), "on-hold", null);
5598 }
5599 }
5600 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5601 // Tell anyone interested that we are done booting!
5602 synchronized (this) {
5603 broadcastIntentLocked(null, null,
5604 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5605 null, null, 0, null, null,
5606 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5607 false, false, MY_PID, Process.SYSTEM_UID);
5608 }
5609 }
5610 }
5611
5612 final void ensureBootCompleted() {
5613 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005614 boolean enableScreen;
5615 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005616 booting = mBooting;
5617 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005618 enableScreen = !mBooted;
5619 mBooted = true;
5620 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005621
5622 if (booting) {
5623 finishBooting();
5624 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005625
5626 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005627 enableScreenAfterBoot();
5628 }
5629 }
5630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005631 public final void activityPaused(IBinder token, Bundle icicle) {
5632 // Refuse possible leaked file descriptors
5633 if (icicle != null && icicle.hasFileDescriptors()) {
5634 throw new IllegalArgumentException("File descriptors passed in Bundle");
5635 }
5636
5637 final long origId = Binder.clearCallingIdentity();
5638 activityPaused(token, icicle, false);
5639 Binder.restoreCallingIdentity(origId);
5640 }
5641
5642 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5643 if (DEBUG_PAUSE) Log.v(
5644 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5645 + ", timeout=" + timeout);
5646
5647 HistoryRecord r = null;
5648
5649 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005650 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005651 if (index >= 0) {
5652 r = (HistoryRecord)mHistory.get(index);
5653 if (!timeout) {
5654 r.icicle = icicle;
5655 r.haveState = true;
5656 }
5657 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5658 if (mPausingActivity == r) {
5659 r.state = ActivityState.PAUSED;
5660 completePauseLocked();
5661 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005662 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005663 System.identityHashCode(r), r.shortComponentName,
5664 mPausingActivity != null
5665 ? mPausingActivity.shortComponentName : "(none)");
5666 }
5667 }
5668 }
5669 }
5670
5671 public final void activityStopped(IBinder token, Bitmap thumbnail,
5672 CharSequence description) {
5673 if (localLOGV) Log.v(
5674 TAG, "Activity stopped: token=" + token);
5675
5676 HistoryRecord r = null;
5677
5678 final long origId = Binder.clearCallingIdentity();
5679
5680 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005681 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005682 if (index >= 0) {
5683 r = (HistoryRecord)mHistory.get(index);
5684 r.thumbnail = thumbnail;
5685 r.description = description;
5686 r.stopped = true;
5687 r.state = ActivityState.STOPPED;
5688 if (!r.finishing) {
5689 if (r.configDestroy) {
5690 destroyActivityLocked(r, true);
5691 resumeTopActivityLocked(null);
5692 }
5693 }
5694 }
5695 }
5696
5697 if (r != null) {
5698 sendPendingThumbnail(r, null, null, null, false);
5699 }
5700
5701 trimApplications();
5702
5703 Binder.restoreCallingIdentity(origId);
5704 }
5705
5706 public final void activityDestroyed(IBinder token) {
5707 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5708 synchronized (this) {
5709 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5710
Dianne Hackborn75b03852009-06-12 15:43:26 -07005711 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005712 if (index >= 0) {
5713 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5714 if (r.state == ActivityState.DESTROYING) {
5715 final long origId = Binder.clearCallingIdentity();
5716 removeActivityFromHistoryLocked(r);
5717 Binder.restoreCallingIdentity(origId);
5718 }
5719 }
5720 }
5721 }
5722
5723 public String getCallingPackage(IBinder token) {
5724 synchronized (this) {
5725 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005726 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005727 }
5728 }
5729
5730 public ComponentName getCallingActivity(IBinder token) {
5731 synchronized (this) {
5732 HistoryRecord r = getCallingRecordLocked(token);
5733 return r != null ? r.intent.getComponent() : null;
5734 }
5735 }
5736
5737 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005738 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005739 if (index >= 0) {
5740 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5741 if (r != null) {
5742 return r.resultTo;
5743 }
5744 }
5745 return null;
5746 }
5747
5748 public ComponentName getActivityClassForToken(IBinder token) {
5749 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005750 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005751 if (index >= 0) {
5752 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5753 return r.intent.getComponent();
5754 }
5755 return null;
5756 }
5757 }
5758
5759 public String getPackageForToken(IBinder token) {
5760 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005761 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005762 if (index >= 0) {
5763 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5764 return r.packageName;
5765 }
5766 return null;
5767 }
5768 }
5769
5770 public IIntentSender getIntentSender(int type,
5771 String packageName, IBinder token, String resultWho,
5772 int requestCode, Intent intent, String resolvedType, int flags) {
5773 // Refuse possible leaked file descriptors
5774 if (intent != null && intent.hasFileDescriptors() == true) {
5775 throw new IllegalArgumentException("File descriptors passed in Intent");
5776 }
5777
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005778 if (type == INTENT_SENDER_BROADCAST) {
5779 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5780 throw new IllegalArgumentException(
5781 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5782 }
5783 }
5784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005785 synchronized(this) {
5786 int callingUid = Binder.getCallingUid();
5787 try {
5788 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5789 Process.supportsProcesses()) {
5790 int uid = ActivityThread.getPackageManager()
5791 .getPackageUid(packageName);
5792 if (uid != Binder.getCallingUid()) {
5793 String msg = "Permission Denial: getIntentSender() from pid="
5794 + Binder.getCallingPid()
5795 + ", uid=" + Binder.getCallingUid()
5796 + ", (need uid=" + uid + ")"
5797 + " is not allowed to send as package " + packageName;
5798 Log.w(TAG, msg);
5799 throw new SecurityException(msg);
5800 }
5801 }
5802 } catch (RemoteException e) {
5803 throw new SecurityException(e);
5804 }
5805 HistoryRecord activity = null;
5806 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005807 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005808 if (index < 0) {
5809 return null;
5810 }
5811 activity = (HistoryRecord)mHistory.get(index);
5812 if (activity.finishing) {
5813 return null;
5814 }
5815 }
5816
5817 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5818 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5819 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5820 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5821 |PendingIntent.FLAG_UPDATE_CURRENT);
5822
5823 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5824 type, packageName, activity, resultWho,
5825 requestCode, intent, resolvedType, flags);
5826 WeakReference<PendingIntentRecord> ref;
5827 ref = mIntentSenderRecords.get(key);
5828 PendingIntentRecord rec = ref != null ? ref.get() : null;
5829 if (rec != null) {
5830 if (!cancelCurrent) {
5831 if (updateCurrent) {
5832 rec.key.requestIntent.replaceExtras(intent);
5833 }
5834 return rec;
5835 }
5836 rec.canceled = true;
5837 mIntentSenderRecords.remove(key);
5838 }
5839 if (noCreate) {
5840 return rec;
5841 }
5842 rec = new PendingIntentRecord(this, key, callingUid);
5843 mIntentSenderRecords.put(key, rec.ref);
5844 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5845 if (activity.pendingResults == null) {
5846 activity.pendingResults
5847 = new HashSet<WeakReference<PendingIntentRecord>>();
5848 }
5849 activity.pendingResults.add(rec.ref);
5850 }
5851 return rec;
5852 }
5853 }
5854
5855 public void cancelIntentSender(IIntentSender sender) {
5856 if (!(sender instanceof PendingIntentRecord)) {
5857 return;
5858 }
5859 synchronized(this) {
5860 PendingIntentRecord rec = (PendingIntentRecord)sender;
5861 try {
5862 int uid = ActivityThread.getPackageManager()
5863 .getPackageUid(rec.key.packageName);
5864 if (uid != Binder.getCallingUid()) {
5865 String msg = "Permission Denial: cancelIntentSender() from pid="
5866 + Binder.getCallingPid()
5867 + ", uid=" + Binder.getCallingUid()
5868 + " is not allowed to cancel packges "
5869 + rec.key.packageName;
5870 Log.w(TAG, msg);
5871 throw new SecurityException(msg);
5872 }
5873 } catch (RemoteException e) {
5874 throw new SecurityException(e);
5875 }
5876 cancelIntentSenderLocked(rec, true);
5877 }
5878 }
5879
5880 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5881 rec.canceled = true;
5882 mIntentSenderRecords.remove(rec.key);
5883 if (cleanActivity && rec.key.activity != null) {
5884 rec.key.activity.pendingResults.remove(rec.ref);
5885 }
5886 }
5887
5888 public String getPackageForIntentSender(IIntentSender pendingResult) {
5889 if (!(pendingResult instanceof PendingIntentRecord)) {
5890 return null;
5891 }
5892 synchronized(this) {
5893 try {
5894 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5895 return res.key.packageName;
5896 } catch (ClassCastException e) {
5897 }
5898 }
5899 return null;
5900 }
5901
5902 public void setProcessLimit(int max) {
5903 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5904 "setProcessLimit()");
5905 mProcessLimit = max;
5906 }
5907
5908 public int getProcessLimit() {
5909 return mProcessLimit;
5910 }
5911
5912 void foregroundTokenDied(ForegroundToken token) {
5913 synchronized (ActivityManagerService.this) {
5914 synchronized (mPidsSelfLocked) {
5915 ForegroundToken cur
5916 = mForegroundProcesses.get(token.pid);
5917 if (cur != token) {
5918 return;
5919 }
5920 mForegroundProcesses.remove(token.pid);
5921 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5922 if (pr == null) {
5923 return;
5924 }
5925 pr.forcingToForeground = null;
5926 pr.foregroundServices = false;
5927 }
5928 updateOomAdjLocked();
5929 }
5930 }
5931
5932 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5933 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5934 "setProcessForeground()");
5935 synchronized(this) {
5936 boolean changed = false;
5937
5938 synchronized (mPidsSelfLocked) {
5939 ProcessRecord pr = mPidsSelfLocked.get(pid);
5940 if (pr == null) {
5941 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5942 return;
5943 }
5944 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5945 if (oldToken != null) {
5946 oldToken.token.unlinkToDeath(oldToken, 0);
5947 mForegroundProcesses.remove(pid);
5948 pr.forcingToForeground = null;
5949 changed = true;
5950 }
5951 if (isForeground && token != null) {
5952 ForegroundToken newToken = new ForegroundToken() {
5953 public void binderDied() {
5954 foregroundTokenDied(this);
5955 }
5956 };
5957 newToken.pid = pid;
5958 newToken.token = token;
5959 try {
5960 token.linkToDeath(newToken, 0);
5961 mForegroundProcesses.put(pid, newToken);
5962 pr.forcingToForeground = token;
5963 changed = true;
5964 } catch (RemoteException e) {
5965 // If the process died while doing this, we will later
5966 // do the cleanup with the process death link.
5967 }
5968 }
5969 }
5970
5971 if (changed) {
5972 updateOomAdjLocked();
5973 }
5974 }
5975 }
5976
5977 // =========================================================
5978 // PERMISSIONS
5979 // =========================================================
5980
5981 static class PermissionController extends IPermissionController.Stub {
5982 ActivityManagerService mActivityManagerService;
5983 PermissionController(ActivityManagerService activityManagerService) {
5984 mActivityManagerService = activityManagerService;
5985 }
5986
5987 public boolean checkPermission(String permission, int pid, int uid) {
5988 return mActivityManagerService.checkPermission(permission, pid,
5989 uid) == PackageManager.PERMISSION_GRANTED;
5990 }
5991 }
5992
5993 /**
5994 * This can be called with or without the global lock held.
5995 */
5996 int checkComponentPermission(String permission, int pid, int uid,
5997 int reqUid) {
5998 // We might be performing an operation on behalf of an indirect binder
5999 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6000 // client identity accordingly before proceeding.
6001 Identity tlsIdentity = sCallerIdentity.get();
6002 if (tlsIdentity != null) {
6003 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6004 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6005 uid = tlsIdentity.uid;
6006 pid = tlsIdentity.pid;
6007 }
6008
6009 // Root, system server and our own process get to do everything.
6010 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6011 !Process.supportsProcesses()) {
6012 return PackageManager.PERMISSION_GRANTED;
6013 }
6014 // If the target requires a specific UID, always fail for others.
6015 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006016 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006017 return PackageManager.PERMISSION_DENIED;
6018 }
6019 if (permission == null) {
6020 return PackageManager.PERMISSION_GRANTED;
6021 }
6022 try {
6023 return ActivityThread.getPackageManager()
6024 .checkUidPermission(permission, uid);
6025 } catch (RemoteException e) {
6026 // Should never happen, but if it does... deny!
6027 Log.e(TAG, "PackageManager is dead?!?", e);
6028 }
6029 return PackageManager.PERMISSION_DENIED;
6030 }
6031
6032 /**
6033 * As the only public entry point for permissions checking, this method
6034 * can enforce the semantic that requesting a check on a null global
6035 * permission is automatically denied. (Internally a null permission
6036 * string is used when calling {@link #checkComponentPermission} in cases
6037 * when only uid-based security is needed.)
6038 *
6039 * This can be called with or without the global lock held.
6040 */
6041 public int checkPermission(String permission, int pid, int uid) {
6042 if (permission == null) {
6043 return PackageManager.PERMISSION_DENIED;
6044 }
6045 return checkComponentPermission(permission, pid, uid, -1);
6046 }
6047
6048 /**
6049 * Binder IPC calls go through the public entry point.
6050 * This can be called with or without the global lock held.
6051 */
6052 int checkCallingPermission(String permission) {
6053 return checkPermission(permission,
6054 Binder.getCallingPid(),
6055 Binder.getCallingUid());
6056 }
6057
6058 /**
6059 * This can be called with or without the global lock held.
6060 */
6061 void enforceCallingPermission(String permission, String func) {
6062 if (checkCallingPermission(permission)
6063 == PackageManager.PERMISSION_GRANTED) {
6064 return;
6065 }
6066
6067 String msg = "Permission Denial: " + func + " from pid="
6068 + Binder.getCallingPid()
6069 + ", uid=" + Binder.getCallingUid()
6070 + " requires " + permission;
6071 Log.w(TAG, msg);
6072 throw new SecurityException(msg);
6073 }
6074
6075 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6076 ProviderInfo pi, int uid, int modeFlags) {
6077 try {
6078 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6079 if ((pi.readPermission != null) &&
6080 (pm.checkUidPermission(pi.readPermission, uid)
6081 != PackageManager.PERMISSION_GRANTED)) {
6082 return false;
6083 }
6084 }
6085 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6086 if ((pi.writePermission != null) &&
6087 (pm.checkUidPermission(pi.writePermission, uid)
6088 != PackageManager.PERMISSION_GRANTED)) {
6089 return false;
6090 }
6091 }
6092 return true;
6093 } catch (RemoteException e) {
6094 return false;
6095 }
6096 }
6097
6098 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6099 int modeFlags) {
6100 // Root gets to do everything.
6101 if (uid == 0 || !Process.supportsProcesses()) {
6102 return true;
6103 }
6104 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6105 if (perms == null) return false;
6106 UriPermission perm = perms.get(uri);
6107 if (perm == null) return false;
6108 return (modeFlags&perm.modeFlags) == modeFlags;
6109 }
6110
6111 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6112 // Another redirected-binder-call permissions check as in
6113 // {@link checkComponentPermission}.
6114 Identity tlsIdentity = sCallerIdentity.get();
6115 if (tlsIdentity != null) {
6116 uid = tlsIdentity.uid;
6117 pid = tlsIdentity.pid;
6118 }
6119
6120 // Our own process gets to do everything.
6121 if (pid == MY_PID) {
6122 return PackageManager.PERMISSION_GRANTED;
6123 }
6124 synchronized(this) {
6125 return checkUriPermissionLocked(uri, uid, modeFlags)
6126 ? PackageManager.PERMISSION_GRANTED
6127 : PackageManager.PERMISSION_DENIED;
6128 }
6129 }
6130
6131 private void grantUriPermissionLocked(int callingUid,
6132 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6133 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6134 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6135 if (modeFlags == 0) {
6136 return;
6137 }
6138
6139 final IPackageManager pm = ActivityThread.getPackageManager();
6140
6141 // If this is not a content: uri, we can't do anything with it.
6142 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6143 return;
6144 }
6145
6146 String name = uri.getAuthority();
6147 ProviderInfo pi = null;
6148 ContentProviderRecord cpr
6149 = (ContentProviderRecord)mProvidersByName.get(name);
6150 if (cpr != null) {
6151 pi = cpr.info;
6152 } else {
6153 try {
6154 pi = pm.resolveContentProvider(name,
6155 PackageManager.GET_URI_PERMISSION_PATTERNS);
6156 } catch (RemoteException ex) {
6157 }
6158 }
6159 if (pi == null) {
6160 Log.w(TAG, "No content provider found for: " + name);
6161 return;
6162 }
6163
6164 int targetUid;
6165 try {
6166 targetUid = pm.getPackageUid(targetPkg);
6167 if (targetUid < 0) {
6168 return;
6169 }
6170 } catch (RemoteException ex) {
6171 return;
6172 }
6173
6174 // First... does the target actually need this permission?
6175 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6176 // No need to grant the target this permission.
6177 return;
6178 }
6179
6180 // Second... maybe someone else has already granted the
6181 // permission?
6182 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6183 // No need to grant the target this permission.
6184 return;
6185 }
6186
6187 // Third... is the provider allowing granting of URI permissions?
6188 if (!pi.grantUriPermissions) {
6189 throw new SecurityException("Provider " + pi.packageName
6190 + "/" + pi.name
6191 + " does not allow granting of Uri permissions (uri "
6192 + uri + ")");
6193 }
6194 if (pi.uriPermissionPatterns != null) {
6195 final int N = pi.uriPermissionPatterns.length;
6196 boolean allowed = false;
6197 for (int i=0; i<N; i++) {
6198 if (pi.uriPermissionPatterns[i] != null
6199 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6200 allowed = true;
6201 break;
6202 }
6203 }
6204 if (!allowed) {
6205 throw new SecurityException("Provider " + pi.packageName
6206 + "/" + pi.name
6207 + " does not allow granting of permission to path of Uri "
6208 + uri);
6209 }
6210 }
6211
6212 // Fourth... does the caller itself have permission to access
6213 // this uri?
6214 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6215 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6216 throw new SecurityException("Uid " + callingUid
6217 + " does not have permission to uri " + uri);
6218 }
6219 }
6220
6221 // Okay! So here we are: the caller has the assumed permission
6222 // to the uri, and the target doesn't. Let's now give this to
6223 // the target.
6224
6225 HashMap<Uri, UriPermission> targetUris
6226 = mGrantedUriPermissions.get(targetUid);
6227 if (targetUris == null) {
6228 targetUris = new HashMap<Uri, UriPermission>();
6229 mGrantedUriPermissions.put(targetUid, targetUris);
6230 }
6231
6232 UriPermission perm = targetUris.get(uri);
6233 if (perm == null) {
6234 perm = new UriPermission(targetUid, uri);
6235 targetUris.put(uri, perm);
6236
6237 }
6238 perm.modeFlags |= modeFlags;
6239 if (activity == null) {
6240 perm.globalModeFlags |= modeFlags;
6241 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6242 perm.readActivities.add(activity);
6243 if (activity.readUriPermissions == null) {
6244 activity.readUriPermissions = new HashSet<UriPermission>();
6245 }
6246 activity.readUriPermissions.add(perm);
6247 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6248 perm.writeActivities.add(activity);
6249 if (activity.writeUriPermissions == null) {
6250 activity.writeUriPermissions = new HashSet<UriPermission>();
6251 }
6252 activity.writeUriPermissions.add(perm);
6253 }
6254 }
6255
6256 private void grantUriPermissionFromIntentLocked(int callingUid,
6257 String targetPkg, Intent intent, HistoryRecord activity) {
6258 if (intent == null) {
6259 return;
6260 }
6261 Uri data = intent.getData();
6262 if (data == null) {
6263 return;
6264 }
6265 grantUriPermissionLocked(callingUid, targetPkg, data,
6266 intent.getFlags(), activity);
6267 }
6268
6269 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6270 Uri uri, int modeFlags) {
6271 synchronized(this) {
6272 final ProcessRecord r = getRecordForAppLocked(caller);
6273 if (r == null) {
6274 throw new SecurityException("Unable to find app for caller "
6275 + caller
6276 + " when granting permission to uri " + uri);
6277 }
6278 if (targetPkg == null) {
6279 Log.w(TAG, "grantUriPermission: null target");
6280 return;
6281 }
6282 if (uri == null) {
6283 Log.w(TAG, "grantUriPermission: null uri");
6284 return;
6285 }
6286
6287 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6288 null);
6289 }
6290 }
6291
6292 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6293 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6294 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6295 HashMap<Uri, UriPermission> perms
6296 = mGrantedUriPermissions.get(perm.uid);
6297 if (perms != null) {
6298 perms.remove(perm.uri);
6299 if (perms.size() == 0) {
6300 mGrantedUriPermissions.remove(perm.uid);
6301 }
6302 }
6303 }
6304 }
6305
6306 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6307 if (activity.readUriPermissions != null) {
6308 for (UriPermission perm : activity.readUriPermissions) {
6309 perm.readActivities.remove(activity);
6310 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6311 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6312 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6313 removeUriPermissionIfNeededLocked(perm);
6314 }
6315 }
6316 }
6317 if (activity.writeUriPermissions != null) {
6318 for (UriPermission perm : activity.writeUriPermissions) {
6319 perm.writeActivities.remove(activity);
6320 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6321 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6322 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6323 removeUriPermissionIfNeededLocked(perm);
6324 }
6325 }
6326 }
6327 }
6328
6329 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6330 int modeFlags) {
6331 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6332 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6333 if (modeFlags == 0) {
6334 return;
6335 }
6336
6337 final IPackageManager pm = ActivityThread.getPackageManager();
6338
6339 final String authority = uri.getAuthority();
6340 ProviderInfo pi = null;
6341 ContentProviderRecord cpr
6342 = (ContentProviderRecord)mProvidersByName.get(authority);
6343 if (cpr != null) {
6344 pi = cpr.info;
6345 } else {
6346 try {
6347 pi = pm.resolveContentProvider(authority,
6348 PackageManager.GET_URI_PERMISSION_PATTERNS);
6349 } catch (RemoteException ex) {
6350 }
6351 }
6352 if (pi == null) {
6353 Log.w(TAG, "No content provider found for: " + authority);
6354 return;
6355 }
6356
6357 // Does the caller have this permission on the URI?
6358 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6359 // Right now, if you are not the original owner of the permission,
6360 // you are not allowed to revoke it.
6361 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6362 throw new SecurityException("Uid " + callingUid
6363 + " does not have permission to uri " + uri);
6364 //}
6365 }
6366
6367 // Go through all of the permissions and remove any that match.
6368 final List<String> SEGMENTS = uri.getPathSegments();
6369 if (SEGMENTS != null) {
6370 final int NS = SEGMENTS.size();
6371 int N = mGrantedUriPermissions.size();
6372 for (int i=0; i<N; i++) {
6373 HashMap<Uri, UriPermission> perms
6374 = mGrantedUriPermissions.valueAt(i);
6375 Iterator<UriPermission> it = perms.values().iterator();
6376 toploop:
6377 while (it.hasNext()) {
6378 UriPermission perm = it.next();
6379 Uri targetUri = perm.uri;
6380 if (!authority.equals(targetUri.getAuthority())) {
6381 continue;
6382 }
6383 List<String> targetSegments = targetUri.getPathSegments();
6384 if (targetSegments == null) {
6385 continue;
6386 }
6387 if (targetSegments.size() < NS) {
6388 continue;
6389 }
6390 for (int j=0; j<NS; j++) {
6391 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6392 continue toploop;
6393 }
6394 }
6395 perm.clearModes(modeFlags);
6396 if (perm.modeFlags == 0) {
6397 it.remove();
6398 }
6399 }
6400 if (perms.size() == 0) {
6401 mGrantedUriPermissions.remove(
6402 mGrantedUriPermissions.keyAt(i));
6403 N--;
6404 i--;
6405 }
6406 }
6407 }
6408 }
6409
6410 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6411 int modeFlags) {
6412 synchronized(this) {
6413 final ProcessRecord r = getRecordForAppLocked(caller);
6414 if (r == null) {
6415 throw new SecurityException("Unable to find app for caller "
6416 + caller
6417 + " when revoking permission to uri " + uri);
6418 }
6419 if (uri == null) {
6420 Log.w(TAG, "revokeUriPermission: null uri");
6421 return;
6422 }
6423
6424 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6425 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6426 if (modeFlags == 0) {
6427 return;
6428 }
6429
6430 final IPackageManager pm = ActivityThread.getPackageManager();
6431
6432 final String authority = uri.getAuthority();
6433 ProviderInfo pi = null;
6434 ContentProviderRecord cpr
6435 = (ContentProviderRecord)mProvidersByName.get(authority);
6436 if (cpr != null) {
6437 pi = cpr.info;
6438 } else {
6439 try {
6440 pi = pm.resolveContentProvider(authority,
6441 PackageManager.GET_URI_PERMISSION_PATTERNS);
6442 } catch (RemoteException ex) {
6443 }
6444 }
6445 if (pi == null) {
6446 Log.w(TAG, "No content provider found for: " + authority);
6447 return;
6448 }
6449
6450 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6451 }
6452 }
6453
6454 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6455 synchronized (this) {
6456 ProcessRecord app =
6457 who != null ? getRecordForAppLocked(who) : null;
6458 if (app == null) return;
6459
6460 Message msg = Message.obtain();
6461 msg.what = WAIT_FOR_DEBUGGER_MSG;
6462 msg.obj = app;
6463 msg.arg1 = waiting ? 1 : 0;
6464 mHandler.sendMessage(msg);
6465 }
6466 }
6467
6468 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6469 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006470 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006471 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006472 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006473 }
6474
6475 // =========================================================
6476 // TASK MANAGEMENT
6477 // =========================================================
6478
6479 public List getTasks(int maxNum, int flags,
6480 IThumbnailReceiver receiver) {
6481 ArrayList list = new ArrayList();
6482
6483 PendingThumbnailsRecord pending = null;
6484 IApplicationThread topThumbnail = null;
6485 HistoryRecord topRecord = null;
6486
6487 synchronized(this) {
6488 if (localLOGV) Log.v(
6489 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6490 + ", receiver=" + receiver);
6491
6492 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6493 != PackageManager.PERMISSION_GRANTED) {
6494 if (receiver != null) {
6495 // If the caller wants to wait for pending thumbnails,
6496 // it ain't gonna get them.
6497 try {
6498 receiver.finished();
6499 } catch (RemoteException ex) {
6500 }
6501 }
6502 String msg = "Permission Denial: getTasks() from pid="
6503 + Binder.getCallingPid()
6504 + ", uid=" + Binder.getCallingUid()
6505 + " requires " + android.Manifest.permission.GET_TASKS;
6506 Log.w(TAG, msg);
6507 throw new SecurityException(msg);
6508 }
6509
6510 int pos = mHistory.size()-1;
6511 HistoryRecord next =
6512 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6513 HistoryRecord top = null;
6514 CharSequence topDescription = null;
6515 TaskRecord curTask = null;
6516 int numActivities = 0;
6517 int numRunning = 0;
6518 while (pos >= 0 && maxNum > 0) {
6519 final HistoryRecord r = next;
6520 pos--;
6521 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6522
6523 // Initialize state for next task if needed.
6524 if (top == null ||
6525 (top.state == ActivityState.INITIALIZING
6526 && top.task == r.task)) {
6527 top = r;
6528 topDescription = r.description;
6529 curTask = r.task;
6530 numActivities = numRunning = 0;
6531 }
6532
6533 // Add 'r' into the current task.
6534 numActivities++;
6535 if (r.app != null && r.app.thread != null) {
6536 numRunning++;
6537 }
6538 if (topDescription == null) {
6539 topDescription = r.description;
6540 }
6541
6542 if (localLOGV) Log.v(
6543 TAG, r.intent.getComponent().flattenToShortString()
6544 + ": task=" + r.task);
6545
6546 // If the next one is a different task, generate a new
6547 // TaskInfo entry for what we have.
6548 if (next == null || next.task != curTask) {
6549 ActivityManager.RunningTaskInfo ci
6550 = new ActivityManager.RunningTaskInfo();
6551 ci.id = curTask.taskId;
6552 ci.baseActivity = r.intent.getComponent();
6553 ci.topActivity = top.intent.getComponent();
6554 ci.thumbnail = top.thumbnail;
6555 ci.description = topDescription;
6556 ci.numActivities = numActivities;
6557 ci.numRunning = numRunning;
6558 //System.out.println(
6559 // "#" + maxNum + ": " + " descr=" + ci.description);
6560 if (ci.thumbnail == null && receiver != null) {
6561 if (localLOGV) Log.v(
6562 TAG, "State=" + top.state + "Idle=" + top.idle
6563 + " app=" + top.app
6564 + " thr=" + (top.app != null ? top.app.thread : null));
6565 if (top.state == ActivityState.RESUMED
6566 || top.state == ActivityState.PAUSING) {
6567 if (top.idle && top.app != null
6568 && top.app.thread != null) {
6569 topRecord = top;
6570 topThumbnail = top.app.thread;
6571 } else {
6572 top.thumbnailNeeded = true;
6573 }
6574 }
6575 if (pending == null) {
6576 pending = new PendingThumbnailsRecord(receiver);
6577 }
6578 pending.pendingRecords.add(top);
6579 }
6580 list.add(ci);
6581 maxNum--;
6582 top = null;
6583 }
6584 }
6585
6586 if (pending != null) {
6587 mPendingThumbnails.add(pending);
6588 }
6589 }
6590
6591 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6592
6593 if (topThumbnail != null) {
6594 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6595 try {
6596 topThumbnail.requestThumbnail(topRecord);
6597 } catch (Exception e) {
6598 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6599 sendPendingThumbnail(null, topRecord, null, null, true);
6600 }
6601 }
6602
6603 if (pending == null && receiver != null) {
6604 // In this case all thumbnails were available and the client
6605 // is being asked to be told when the remaining ones come in...
6606 // which is unusually, since the top-most currently running
6607 // activity should never have a canned thumbnail! Oh well.
6608 try {
6609 receiver.finished();
6610 } catch (RemoteException ex) {
6611 }
6612 }
6613
6614 return list;
6615 }
6616
6617 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6618 int flags) {
6619 synchronized (this) {
6620 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6621 "getRecentTasks()");
6622
6623 final int N = mRecentTasks.size();
6624 ArrayList<ActivityManager.RecentTaskInfo> res
6625 = new ArrayList<ActivityManager.RecentTaskInfo>(
6626 maxNum < N ? maxNum : N);
6627 for (int i=0; i<N && maxNum > 0; i++) {
6628 TaskRecord tr = mRecentTasks.get(i);
6629 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6630 || (tr.intent == null)
6631 || ((tr.intent.getFlags()
6632 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6633 ActivityManager.RecentTaskInfo rti
6634 = new ActivityManager.RecentTaskInfo();
6635 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6636 rti.baseIntent = new Intent(
6637 tr.intent != null ? tr.intent : tr.affinityIntent);
6638 rti.origActivity = tr.origActivity;
6639 res.add(rti);
6640 maxNum--;
6641 }
6642 }
6643 return res;
6644 }
6645 }
6646
6647 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6648 int j;
6649 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6650 TaskRecord jt = startTask;
6651
6652 // First look backwards
6653 for (j=startIndex-1; j>=0; j--) {
6654 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6655 if (r.task != jt) {
6656 jt = r.task;
6657 if (affinity.equals(jt.affinity)) {
6658 return j;
6659 }
6660 }
6661 }
6662
6663 // Now look forwards
6664 final int N = mHistory.size();
6665 jt = startTask;
6666 for (j=startIndex+1; j<N; j++) {
6667 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6668 if (r.task != jt) {
6669 if (affinity.equals(jt.affinity)) {
6670 return j;
6671 }
6672 jt = r.task;
6673 }
6674 }
6675
6676 // Might it be at the top?
6677 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6678 return N-1;
6679 }
6680
6681 return -1;
6682 }
6683
6684 /**
6685 * Perform a reset of the given task, if needed as part of launching it.
6686 * Returns the new HistoryRecord at the top of the task.
6687 */
6688 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6689 HistoryRecord newActivity) {
6690 boolean forceReset = (newActivity.info.flags
6691 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6692 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6693 if ((newActivity.info.flags
6694 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6695 forceReset = true;
6696 }
6697 }
6698
6699 final TaskRecord task = taskTop.task;
6700
6701 // We are going to move through the history list so that we can look
6702 // at each activity 'target' with 'below' either the interesting
6703 // activity immediately below it in the stack or null.
6704 HistoryRecord target = null;
6705 int targetI = 0;
6706 int taskTopI = -1;
6707 int replyChainEnd = -1;
6708 int lastReparentPos = -1;
6709 for (int i=mHistory.size()-1; i>=-1; i--) {
6710 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6711
6712 if (below != null && below.finishing) {
6713 continue;
6714 }
6715 if (target == null) {
6716 target = below;
6717 targetI = i;
6718 // If we were in the middle of a reply chain before this
6719 // task, it doesn't appear like the root of the chain wants
6720 // anything interesting, so drop it.
6721 replyChainEnd = -1;
6722 continue;
6723 }
6724
6725 final int flags = target.info.flags;
6726
6727 final boolean finishOnTaskLaunch =
6728 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6729 final boolean allowTaskReparenting =
6730 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6731
6732 if (target.task == task) {
6733 // We are inside of the task being reset... we'll either
6734 // finish this activity, push it out for another task,
6735 // or leave it as-is. We only do this
6736 // for activities that are not the root of the task (since
6737 // if we finish the root, we may no longer have the task!).
6738 if (taskTopI < 0) {
6739 taskTopI = targetI;
6740 }
6741 if (below != null && below.task == task) {
6742 final boolean clearWhenTaskReset =
6743 (target.intent.getFlags()
6744 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006745 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006746 // If this activity is sending a reply to a previous
6747 // activity, we can't do anything with it now until
6748 // we reach the start of the reply chain.
6749 // XXX note that we are assuming the result is always
6750 // to the previous activity, which is almost always
6751 // the case but we really shouldn't count on.
6752 if (replyChainEnd < 0) {
6753 replyChainEnd = targetI;
6754 }
Ed Heyl73798232009-03-24 21:32:21 -07006755 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006756 && target.taskAffinity != null
6757 && !target.taskAffinity.equals(task.affinity)) {
6758 // If this activity has an affinity for another
6759 // task, then we need to move it out of here. We will
6760 // move it as far out of the way as possible, to the
6761 // bottom of the activity stack. This also keeps it
6762 // correctly ordered with any activities we previously
6763 // moved.
6764 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6765 if (target.taskAffinity != null
6766 && target.taskAffinity.equals(p.task.affinity)) {
6767 // If the activity currently at the bottom has the
6768 // same task affinity as the one we are moving,
6769 // then merge it into the same task.
6770 target.task = p.task;
6771 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6772 + " out to bottom task " + p.task);
6773 } else {
6774 mCurTask++;
6775 if (mCurTask <= 0) {
6776 mCurTask = 1;
6777 }
6778 target.task = new TaskRecord(mCurTask, target.info, null,
6779 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6780 target.task.affinityIntent = target.intent;
6781 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6782 + " out to new task " + target.task);
6783 }
6784 mWindowManager.setAppGroupId(target, task.taskId);
6785 if (replyChainEnd < 0) {
6786 replyChainEnd = targetI;
6787 }
6788 int dstPos = 0;
6789 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6790 p = (HistoryRecord)mHistory.get(srcPos);
6791 if (p.finishing) {
6792 continue;
6793 }
6794 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6795 + " out to target's task " + target.task);
6796 task.numActivities--;
6797 p.task = target.task;
6798 target.task.numActivities++;
6799 mHistory.remove(srcPos);
6800 mHistory.add(dstPos, p);
6801 mWindowManager.moveAppToken(dstPos, p);
6802 mWindowManager.setAppGroupId(p, p.task.taskId);
6803 dstPos++;
6804 if (VALIDATE_TOKENS) {
6805 mWindowManager.validateAppTokens(mHistory);
6806 }
6807 i++;
6808 }
6809 if (taskTop == p) {
6810 taskTop = below;
6811 }
6812 if (taskTopI == replyChainEnd) {
6813 taskTopI = -1;
6814 }
6815 replyChainEnd = -1;
6816 addRecentTask(target.task);
6817 } else if (forceReset || finishOnTaskLaunch
6818 || clearWhenTaskReset) {
6819 // If the activity should just be removed -- either
6820 // because it asks for it, or the task should be
6821 // cleared -- then finish it and anything that is
6822 // part of its reply chain.
6823 if (clearWhenTaskReset) {
6824 // In this case, we want to finish this activity
6825 // and everything above it, so be sneaky and pretend
6826 // like these are all in the reply chain.
6827 replyChainEnd = targetI+1;
6828 while (replyChainEnd < mHistory.size() &&
6829 ((HistoryRecord)mHistory.get(
6830 replyChainEnd)).task == task) {
6831 replyChainEnd++;
6832 }
6833 replyChainEnd--;
6834 } else if (replyChainEnd < 0) {
6835 replyChainEnd = targetI;
6836 }
6837 HistoryRecord p = null;
6838 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6839 p = (HistoryRecord)mHistory.get(srcPos);
6840 if (p.finishing) {
6841 continue;
6842 }
6843 if (finishActivityLocked(p, srcPos,
6844 Activity.RESULT_CANCELED, null, "reset")) {
6845 replyChainEnd--;
6846 srcPos--;
6847 }
6848 }
6849 if (taskTop == p) {
6850 taskTop = below;
6851 }
6852 if (taskTopI == replyChainEnd) {
6853 taskTopI = -1;
6854 }
6855 replyChainEnd = -1;
6856 } else {
6857 // If we were in the middle of a chain, well the
6858 // activity that started it all doesn't want anything
6859 // special, so leave it all as-is.
6860 replyChainEnd = -1;
6861 }
6862 } else {
6863 // Reached the bottom of the task -- any reply chain
6864 // should be left as-is.
6865 replyChainEnd = -1;
6866 }
6867
6868 } else if (target.resultTo != null) {
6869 // If this activity is sending a reply to a previous
6870 // activity, we can't do anything with it now until
6871 // we reach the start of the reply chain.
6872 // XXX note that we are assuming the result is always
6873 // to the previous activity, which is almost always
6874 // the case but we really shouldn't count on.
6875 if (replyChainEnd < 0) {
6876 replyChainEnd = targetI;
6877 }
6878
6879 } else if (taskTopI >= 0 && allowTaskReparenting
6880 && task.affinity != null
6881 && task.affinity.equals(target.taskAffinity)) {
6882 // We are inside of another task... if this activity has
6883 // an affinity for our task, then either remove it if we are
6884 // clearing or move it over to our task. Note that
6885 // we currently punt on the case where we are resetting a
6886 // task that is not at the top but who has activities above
6887 // with an affinity to it... this is really not a normal
6888 // case, and we will need to later pull that task to the front
6889 // and usually at that point we will do the reset and pick
6890 // up those remaining activities. (This only happens if
6891 // someone starts an activity in a new task from an activity
6892 // in a task that is not currently on top.)
6893 if (forceReset || finishOnTaskLaunch) {
6894 if (replyChainEnd < 0) {
6895 replyChainEnd = targetI;
6896 }
6897 HistoryRecord p = null;
6898 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6899 p = (HistoryRecord)mHistory.get(srcPos);
6900 if (p.finishing) {
6901 continue;
6902 }
6903 if (finishActivityLocked(p, srcPos,
6904 Activity.RESULT_CANCELED, null, "reset")) {
6905 taskTopI--;
6906 lastReparentPos--;
6907 replyChainEnd--;
6908 srcPos--;
6909 }
6910 }
6911 replyChainEnd = -1;
6912 } else {
6913 if (replyChainEnd < 0) {
6914 replyChainEnd = targetI;
6915 }
6916 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6917 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6918 if (p.finishing) {
6919 continue;
6920 }
6921 if (lastReparentPos < 0) {
6922 lastReparentPos = taskTopI;
6923 taskTop = p;
6924 } else {
6925 lastReparentPos--;
6926 }
6927 mHistory.remove(srcPos);
6928 p.task.numActivities--;
6929 p.task = task;
6930 mHistory.add(lastReparentPos, p);
6931 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6932 + " in to resetting task " + task);
6933 task.numActivities++;
6934 mWindowManager.moveAppToken(lastReparentPos, p);
6935 mWindowManager.setAppGroupId(p, p.task.taskId);
6936 if (VALIDATE_TOKENS) {
6937 mWindowManager.validateAppTokens(mHistory);
6938 }
6939 }
6940 replyChainEnd = -1;
6941
6942 // Now we've moved it in to place... but what if this is
6943 // a singleTop activity and we have put it on top of another
6944 // instance of the same activity? Then we drop the instance
6945 // below so it remains singleTop.
6946 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6947 for (int j=lastReparentPos-1; j>=0; j--) {
6948 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6949 if (p.finishing) {
6950 continue;
6951 }
6952 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6953 if (finishActivityLocked(p, j,
6954 Activity.RESULT_CANCELED, null, "replace")) {
6955 taskTopI--;
6956 lastReparentPos--;
6957 }
6958 }
6959 }
6960 }
6961 }
6962 }
6963
6964 target = below;
6965 targetI = i;
6966 }
6967
6968 return taskTop;
6969 }
6970
6971 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006972 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006973 */
6974 public void moveTaskToFront(int task) {
6975 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6976 "moveTaskToFront()");
6977
6978 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006979 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6980 Binder.getCallingUid(), "Task to front")) {
6981 return;
6982 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006983 final long origId = Binder.clearCallingIdentity();
6984 try {
6985 int N = mRecentTasks.size();
6986 for (int i=0; i<N; i++) {
6987 TaskRecord tr = mRecentTasks.get(i);
6988 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006989 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006990 return;
6991 }
6992 }
6993 for (int i=mHistory.size()-1; i>=0; i--) {
6994 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6995 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006996 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006997 return;
6998 }
6999 }
7000 } finally {
7001 Binder.restoreCallingIdentity(origId);
7002 }
7003 }
7004 }
7005
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007006 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007007 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7008
7009 final int task = tr.taskId;
7010 int top = mHistory.size()-1;
7011
7012 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7013 // nothing to do!
7014 return;
7015 }
7016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007017 ArrayList moved = new ArrayList();
7018
7019 // Applying the affinities may have removed entries from the history,
7020 // so get the size again.
7021 top = mHistory.size()-1;
7022 int pos = top;
7023
7024 // Shift all activities with this task up to the top
7025 // of the stack, keeping them in the same internal order.
7026 while (pos >= 0) {
7027 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7028 if (localLOGV) Log.v(
7029 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7030 boolean first = true;
7031 if (r.task.taskId == task) {
7032 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7033 mHistory.remove(pos);
7034 mHistory.add(top, r);
7035 moved.add(0, r);
7036 top--;
7037 if (first) {
7038 addRecentTask(r.task);
7039 first = false;
7040 }
7041 }
7042 pos--;
7043 }
7044
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007045 if (DEBUG_TRANSITION) Log.v(TAG,
7046 "Prepare to front transition: task=" + tr);
7047 if (reason != null &&
7048 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7049 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7050 HistoryRecord r = topRunningActivityLocked(null);
7051 if (r != null) {
7052 mNoAnimActivities.add(r);
7053 }
7054 } else {
7055 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7056 }
7057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007058 mWindowManager.moveAppTokensToTop(moved);
7059 if (VALIDATE_TOKENS) {
7060 mWindowManager.validateAppTokens(mHistory);
7061 }
7062
7063 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007064 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007065 }
7066
7067 private final void finishTaskMove(int task) {
7068 resumeTopActivityLocked(null);
7069 }
7070
7071 public void moveTaskToBack(int task) {
7072 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7073 "moveTaskToBack()");
7074
7075 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007076 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7077 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7078 Binder.getCallingUid(), "Task to back")) {
7079 return;
7080 }
7081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007082 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007083 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007084 Binder.restoreCallingIdentity(origId);
7085 }
7086 }
7087
7088 /**
7089 * Moves an activity, and all of the other activities within the same task, to the bottom
7090 * of the history stack. The activity's order within the task is unchanged.
7091 *
7092 * @param token A reference to the activity we wish to move
7093 * @param nonRoot If false then this only works if the activity is the root
7094 * of a task; if true it will work for any activity in a task.
7095 * @return Returns true if the move completed, false if not.
7096 */
7097 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7098 synchronized(this) {
7099 final long origId = Binder.clearCallingIdentity();
7100 int taskId = getTaskForActivityLocked(token, !nonRoot);
7101 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007102 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007103 }
7104 Binder.restoreCallingIdentity(origId);
7105 }
7106 return false;
7107 }
7108
7109 /**
7110 * Worker method for rearranging history stack. Implements the function of moving all
7111 * activities for a specific task (gathering them if disjoint) into a single group at the
7112 * bottom of the stack.
7113 *
7114 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7115 * to premeptively cancel the move.
7116 *
7117 * @param task The taskId to collect and move to the bottom.
7118 * @return Returns true if the move completed, false if not.
7119 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007120 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007121 Log.i(TAG, "moveTaskToBack: " + task);
7122
7123 // If we have a watcher, preflight the move before committing to it. First check
7124 // for *other* available tasks, but if none are available, then try again allowing the
7125 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007126 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007127 HistoryRecord next = topRunningActivityLocked(null, task);
7128 if (next == null) {
7129 next = topRunningActivityLocked(null, 0);
7130 }
7131 if (next != null) {
7132 // ask watcher if this is allowed
7133 boolean moveOK = true;
7134 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007135 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007136 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007137 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007138 }
7139 if (!moveOK) {
7140 return false;
7141 }
7142 }
7143 }
7144
7145 ArrayList moved = new ArrayList();
7146
7147 if (DEBUG_TRANSITION) Log.v(TAG,
7148 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007149
7150 final int N = mHistory.size();
7151 int bottom = 0;
7152 int pos = 0;
7153
7154 // Shift all activities with this task down to the bottom
7155 // of the stack, keeping them in the same internal order.
7156 while (pos < N) {
7157 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7158 if (localLOGV) Log.v(
7159 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7160 if (r.task.taskId == task) {
7161 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7162 mHistory.remove(pos);
7163 mHistory.add(bottom, r);
7164 moved.add(r);
7165 bottom++;
7166 }
7167 pos++;
7168 }
7169
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007170 if (reason != null &&
7171 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7172 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7173 HistoryRecord r = topRunningActivityLocked(null);
7174 if (r != null) {
7175 mNoAnimActivities.add(r);
7176 }
7177 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007178 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007180 mWindowManager.moveAppTokensToBottom(moved);
7181 if (VALIDATE_TOKENS) {
7182 mWindowManager.validateAppTokens(mHistory);
7183 }
7184
7185 finishTaskMove(task);
7186 return true;
7187 }
7188
7189 public void moveTaskBackwards(int task) {
7190 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7191 "moveTaskBackwards()");
7192
7193 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007194 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7195 Binder.getCallingUid(), "Task backwards")) {
7196 return;
7197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007198 final long origId = Binder.clearCallingIdentity();
7199 moveTaskBackwardsLocked(task);
7200 Binder.restoreCallingIdentity(origId);
7201 }
7202 }
7203
7204 private final void moveTaskBackwardsLocked(int task) {
7205 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7206 }
7207
7208 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7209 synchronized(this) {
7210 return getTaskForActivityLocked(token, onlyRoot);
7211 }
7212 }
7213
7214 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7215 final int N = mHistory.size();
7216 TaskRecord lastTask = null;
7217 for (int i=0; i<N; i++) {
7218 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7219 if (r == token) {
7220 if (!onlyRoot || lastTask != r.task) {
7221 return r.task.taskId;
7222 }
7223 return -1;
7224 }
7225 lastTask = r.task;
7226 }
7227
7228 return -1;
7229 }
7230
7231 /**
7232 * Returns the top activity in any existing task matching the given
7233 * Intent. Returns null if no such task is found.
7234 */
7235 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7236 ComponentName cls = intent.getComponent();
7237 if (info.targetActivity != null) {
7238 cls = new ComponentName(info.packageName, info.targetActivity);
7239 }
7240
7241 TaskRecord cp = null;
7242
7243 final int N = mHistory.size();
7244 for (int i=(N-1); i>=0; i--) {
7245 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7246 if (!r.finishing && r.task != cp
7247 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7248 cp = r.task;
7249 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7250 // + "/aff=" + r.task.affinity + " to new cls="
7251 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7252 if (r.task.affinity != null) {
7253 if (r.task.affinity.equals(info.taskAffinity)) {
7254 //Log.i(TAG, "Found matching affinity!");
7255 return r;
7256 }
7257 } else if (r.task.intent != null
7258 && r.task.intent.getComponent().equals(cls)) {
7259 //Log.i(TAG, "Found matching class!");
7260 //dump();
7261 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7262 return r;
7263 } else if (r.task.affinityIntent != null
7264 && r.task.affinityIntent.getComponent().equals(cls)) {
7265 //Log.i(TAG, "Found matching class!");
7266 //dump();
7267 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7268 return r;
7269 }
7270 }
7271 }
7272
7273 return null;
7274 }
7275
7276 /**
7277 * Returns the first activity (starting from the top of the stack) that
7278 * is the same as the given activity. Returns null if no such activity
7279 * is found.
7280 */
7281 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7282 ComponentName cls = intent.getComponent();
7283 if (info.targetActivity != null) {
7284 cls = new ComponentName(info.packageName, info.targetActivity);
7285 }
7286
7287 final int N = mHistory.size();
7288 for (int i=(N-1); i>=0; i--) {
7289 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7290 if (!r.finishing) {
7291 if (r.intent.getComponent().equals(cls)) {
7292 //Log.i(TAG, "Found matching class!");
7293 //dump();
7294 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7295 return r;
7296 }
7297 }
7298 }
7299
7300 return null;
7301 }
7302
7303 public void finishOtherInstances(IBinder token, ComponentName className) {
7304 synchronized(this) {
7305 final long origId = Binder.clearCallingIdentity();
7306
7307 int N = mHistory.size();
7308 TaskRecord lastTask = null;
7309 for (int i=0; i<N; i++) {
7310 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7311 if (r.realActivity.equals(className)
7312 && r != token && lastTask != r.task) {
7313 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7314 null, "others")) {
7315 i--;
7316 N--;
7317 }
7318 }
7319 lastTask = r.task;
7320 }
7321
7322 Binder.restoreCallingIdentity(origId);
7323 }
7324 }
7325
7326 // =========================================================
7327 // THUMBNAILS
7328 // =========================================================
7329
7330 public void reportThumbnail(IBinder token,
7331 Bitmap thumbnail, CharSequence description) {
7332 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7333 final long origId = Binder.clearCallingIdentity();
7334 sendPendingThumbnail(null, token, thumbnail, description, true);
7335 Binder.restoreCallingIdentity(origId);
7336 }
7337
7338 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7339 Bitmap thumbnail, CharSequence description, boolean always) {
7340 TaskRecord task = null;
7341 ArrayList receivers = null;
7342
7343 //System.out.println("Send pending thumbnail: " + r);
7344
7345 synchronized(this) {
7346 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007347 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007348 if (index < 0) {
7349 return;
7350 }
7351 r = (HistoryRecord)mHistory.get(index);
7352 }
7353 if (thumbnail == null) {
7354 thumbnail = r.thumbnail;
7355 description = r.description;
7356 }
7357 if (thumbnail == null && !always) {
7358 // If there is no thumbnail, and this entry is not actually
7359 // going away, then abort for now and pick up the next
7360 // thumbnail we get.
7361 return;
7362 }
7363 task = r.task;
7364
7365 int N = mPendingThumbnails.size();
7366 int i=0;
7367 while (i<N) {
7368 PendingThumbnailsRecord pr =
7369 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7370 //System.out.println("Looking in " + pr.pendingRecords);
7371 if (pr.pendingRecords.remove(r)) {
7372 if (receivers == null) {
7373 receivers = new ArrayList();
7374 }
7375 receivers.add(pr);
7376 if (pr.pendingRecords.size() == 0) {
7377 pr.finished = true;
7378 mPendingThumbnails.remove(i);
7379 N--;
7380 continue;
7381 }
7382 }
7383 i++;
7384 }
7385 }
7386
7387 if (receivers != null) {
7388 final int N = receivers.size();
7389 for (int i=0; i<N; i++) {
7390 try {
7391 PendingThumbnailsRecord pr =
7392 (PendingThumbnailsRecord)receivers.get(i);
7393 pr.receiver.newThumbnail(
7394 task != null ? task.taskId : -1, thumbnail, description);
7395 if (pr.finished) {
7396 pr.receiver.finished();
7397 }
7398 } catch (Exception e) {
7399 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7400 }
7401 }
7402 }
7403 }
7404
7405 // =========================================================
7406 // CONTENT PROVIDERS
7407 // =========================================================
7408
7409 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7410 List providers = null;
7411 try {
7412 providers = ActivityThread.getPackageManager().
7413 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007414 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007415 } catch (RemoteException ex) {
7416 }
7417 if (providers != null) {
7418 final int N = providers.size();
7419 for (int i=0; i<N; i++) {
7420 ProviderInfo cpi =
7421 (ProviderInfo)providers.get(i);
7422 ContentProviderRecord cpr =
7423 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7424 if (cpr == null) {
7425 cpr = new ContentProviderRecord(cpi, app.info);
7426 mProvidersByClass.put(cpi.name, cpr);
7427 }
7428 app.pubProviders.put(cpi.name, cpr);
7429 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007430 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007431 }
7432 }
7433 return providers;
7434 }
7435
7436 private final String checkContentProviderPermissionLocked(
7437 ProviderInfo cpi, ProcessRecord r, int mode) {
7438 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7439 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7440 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7441 cpi.exported ? -1 : cpi.applicationInfo.uid)
7442 == PackageManager.PERMISSION_GRANTED
7443 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7444 return null;
7445 }
7446 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7447 cpi.exported ? -1 : cpi.applicationInfo.uid)
7448 == PackageManager.PERMISSION_GRANTED) {
7449 return null;
7450 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007451
7452 PathPermission[] pps = cpi.pathPermissions;
7453 if (pps != null) {
7454 int i = pps.length;
7455 while (i > 0) {
7456 i--;
7457 PathPermission pp = pps[i];
7458 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7459 cpi.exported ? -1 : cpi.applicationInfo.uid)
7460 == PackageManager.PERMISSION_GRANTED
7461 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7462 return null;
7463 }
7464 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7465 cpi.exported ? -1 : cpi.applicationInfo.uid)
7466 == PackageManager.PERMISSION_GRANTED) {
7467 return null;
7468 }
7469 }
7470 }
7471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007472 String msg = "Permission Denial: opening provider " + cpi.name
7473 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7474 + ", uid=" + callingUid + ") requires "
7475 + cpi.readPermission + " or " + cpi.writePermission;
7476 Log.w(TAG, msg);
7477 return msg;
7478 }
7479
7480 private final ContentProviderHolder getContentProviderImpl(
7481 IApplicationThread caller, String name) {
7482 ContentProviderRecord cpr;
7483 ProviderInfo cpi = null;
7484
7485 synchronized(this) {
7486 ProcessRecord r = null;
7487 if (caller != null) {
7488 r = getRecordForAppLocked(caller);
7489 if (r == null) {
7490 throw new SecurityException(
7491 "Unable to find app for caller " + caller
7492 + " (pid=" + Binder.getCallingPid()
7493 + ") when getting content provider " + name);
7494 }
7495 }
7496
7497 // First check if this content provider has been published...
7498 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7499 if (cpr != null) {
7500 cpi = cpr.info;
7501 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7502 return new ContentProviderHolder(cpi,
7503 cpi.readPermission != null
7504 ? cpi.readPermission : cpi.writePermission);
7505 }
7506
7507 if (r != null && cpr.canRunHere(r)) {
7508 // This provider has been published or is in the process
7509 // of being published... but it is also allowed to run
7510 // in the caller's process, so don't make a connection
7511 // and just let the caller instantiate its own instance.
7512 if (cpr.provider != null) {
7513 // don't give caller the provider object, it needs
7514 // to make its own.
7515 cpr = new ContentProviderRecord(cpr);
7516 }
7517 return cpr;
7518 }
7519
7520 final long origId = Binder.clearCallingIdentity();
7521
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007522 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007523 // return it right away.
7524 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007525 if (DEBUG_PROVIDER) Log.v(TAG,
7526 "Adding provider requested by "
7527 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007528 + cpr.info.processName);
7529 Integer cnt = r.conProviders.get(cpr);
7530 if (cnt == null) {
7531 r.conProviders.put(cpr, new Integer(1));
7532 } else {
7533 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7534 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007535 cpr.clients.add(r);
7536 } else {
7537 cpr.externals++;
7538 }
7539
7540 if (cpr.app != null) {
7541 updateOomAdjLocked(cpr.app);
7542 }
7543
7544 Binder.restoreCallingIdentity(origId);
7545
7546 } else {
7547 try {
7548 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007549 resolveContentProvider(name,
7550 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007551 } catch (RemoteException ex) {
7552 }
7553 if (cpi == null) {
7554 return null;
7555 }
7556
7557 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7558 return new ContentProviderHolder(cpi,
7559 cpi.readPermission != null
7560 ? cpi.readPermission : cpi.writePermission);
7561 }
7562
7563 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7564 final boolean firstClass = cpr == null;
7565 if (firstClass) {
7566 try {
7567 ApplicationInfo ai =
7568 ActivityThread.getPackageManager().
7569 getApplicationInfo(
7570 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007571 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007572 if (ai == null) {
7573 Log.w(TAG, "No package info for content provider "
7574 + cpi.name);
7575 return null;
7576 }
7577 cpr = new ContentProviderRecord(cpi, ai);
7578 } catch (RemoteException ex) {
7579 // pm is in same process, this will never happen.
7580 }
7581 }
7582
7583 if (r != null && cpr.canRunHere(r)) {
7584 // If this is a multiprocess provider, then just return its
7585 // info and allow the caller to instantiate it. Only do
7586 // this if the provider is the same user as the caller's
7587 // process, or can run as root (so can be in any process).
7588 return cpr;
7589 }
7590
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007591 if (DEBUG_PROVIDER) {
7592 RuntimeException e = new RuntimeException("here");
7593 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7594 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007595 }
7596
7597 // This is single process, and our app is now connecting to it.
7598 // See if we are already in the process of launching this
7599 // provider.
7600 final int N = mLaunchingProviders.size();
7601 int i;
7602 for (i=0; i<N; i++) {
7603 if (mLaunchingProviders.get(i) == cpr) {
7604 break;
7605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007606 }
7607
7608 // If the provider is not already being launched, then get it
7609 // started.
7610 if (i >= N) {
7611 final long origId = Binder.clearCallingIdentity();
7612 ProcessRecord proc = startProcessLocked(cpi.processName,
7613 cpr.appInfo, false, 0, "content provider",
7614 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007615 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007616 if (proc == null) {
7617 Log.w(TAG, "Unable to launch app "
7618 + cpi.applicationInfo.packageName + "/"
7619 + cpi.applicationInfo.uid + " for provider "
7620 + name + ": process is bad");
7621 return null;
7622 }
7623 cpr.launchingApp = proc;
7624 mLaunchingProviders.add(cpr);
7625 Binder.restoreCallingIdentity(origId);
7626 }
7627
7628 // Make sure the provider is published (the same provider class
7629 // may be published under multiple names).
7630 if (firstClass) {
7631 mProvidersByClass.put(cpi.name, cpr);
7632 }
7633 mProvidersByName.put(name, cpr);
7634
7635 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007636 if (DEBUG_PROVIDER) Log.v(TAG,
7637 "Adding provider requested by "
7638 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007639 + cpr.info.processName);
7640 Integer cnt = r.conProviders.get(cpr);
7641 if (cnt == null) {
7642 r.conProviders.put(cpr, new Integer(1));
7643 } else {
7644 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007646 cpr.clients.add(r);
7647 } else {
7648 cpr.externals++;
7649 }
7650 }
7651 }
7652
7653 // Wait for the provider to be published...
7654 synchronized (cpr) {
7655 while (cpr.provider == null) {
7656 if (cpr.launchingApp == null) {
7657 Log.w(TAG, "Unable to launch app "
7658 + cpi.applicationInfo.packageName + "/"
7659 + cpi.applicationInfo.uid + " for provider "
7660 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007661 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007662 cpi.applicationInfo.packageName,
7663 cpi.applicationInfo.uid, name);
7664 return null;
7665 }
7666 try {
7667 cpr.wait();
7668 } catch (InterruptedException ex) {
7669 }
7670 }
7671 }
7672 return cpr;
7673 }
7674
7675 public final ContentProviderHolder getContentProvider(
7676 IApplicationThread caller, String name) {
7677 if (caller == null) {
7678 String msg = "null IApplicationThread when getting content provider "
7679 + name;
7680 Log.w(TAG, msg);
7681 throw new SecurityException(msg);
7682 }
7683
7684 return getContentProviderImpl(caller, name);
7685 }
7686
7687 private ContentProviderHolder getContentProviderExternal(String name) {
7688 return getContentProviderImpl(null, name);
7689 }
7690
7691 /**
7692 * Drop a content provider from a ProcessRecord's bookkeeping
7693 * @param cpr
7694 */
7695 public void removeContentProvider(IApplicationThread caller, String name) {
7696 synchronized (this) {
7697 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7698 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007699 // remove from mProvidersByClass
7700 if (DEBUG_PROVIDER) Log.v(TAG, name +
7701 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007702 return;
7703 }
7704 final ProcessRecord r = getRecordForAppLocked(caller);
7705 if (r == null) {
7706 throw new SecurityException(
7707 "Unable to find app for caller " + caller +
7708 " when removing content provider " + name);
7709 }
7710 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007711 ContentProviderRecord localCpr = (ContentProviderRecord)
7712 mProvidersByClass.get(cpr.info.name);
7713 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7714 + r.info.processName + " from process "
7715 + localCpr.appInfo.processName);
7716 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007717 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007718 Log.w(TAG, "removeContentProvider called on local provider: "
7719 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007720 return;
7721 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007722 Integer cnt = r.conProviders.get(localCpr);
7723 if (cnt == null || cnt.intValue() <= 1) {
7724 localCpr.clients.remove(r);
7725 r.conProviders.remove(localCpr);
7726 } else {
7727 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7728 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007729 }
7730 updateOomAdjLocked();
7731 }
7732 }
7733
7734 private void removeContentProviderExternal(String name) {
7735 synchronized (this) {
7736 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7737 if(cpr == null) {
7738 //remove from mProvidersByClass
7739 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7740 return;
7741 }
7742
7743 //update content provider record entry info
7744 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7745 localCpr.externals--;
7746 if (localCpr.externals < 0) {
7747 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7748 }
7749 updateOomAdjLocked();
7750 }
7751 }
7752
7753 public final void publishContentProviders(IApplicationThread caller,
7754 List<ContentProviderHolder> providers) {
7755 if (providers == null) {
7756 return;
7757 }
7758
7759 synchronized(this) {
7760 final ProcessRecord r = getRecordForAppLocked(caller);
7761 if (r == null) {
7762 throw new SecurityException(
7763 "Unable to find app for caller " + caller
7764 + " (pid=" + Binder.getCallingPid()
7765 + ") when publishing content providers");
7766 }
7767
7768 final long origId = Binder.clearCallingIdentity();
7769
7770 final int N = providers.size();
7771 for (int i=0; i<N; i++) {
7772 ContentProviderHolder src = providers.get(i);
7773 if (src == null || src.info == null || src.provider == null) {
7774 continue;
7775 }
7776 ContentProviderRecord dst =
7777 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7778 if (dst != null) {
7779 mProvidersByClass.put(dst.info.name, dst);
7780 String names[] = dst.info.authority.split(";");
7781 for (int j = 0; j < names.length; j++) {
7782 mProvidersByName.put(names[j], dst);
7783 }
7784
7785 int NL = mLaunchingProviders.size();
7786 int j;
7787 for (j=0; j<NL; j++) {
7788 if (mLaunchingProviders.get(j) == dst) {
7789 mLaunchingProviders.remove(j);
7790 j--;
7791 NL--;
7792 }
7793 }
7794 synchronized (dst) {
7795 dst.provider = src.provider;
7796 dst.app = r;
7797 dst.notifyAll();
7798 }
7799 updateOomAdjLocked(r);
7800 }
7801 }
7802
7803 Binder.restoreCallingIdentity(origId);
7804 }
7805 }
7806
7807 public static final void installSystemProviders() {
7808 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7809 List providers = mSelf.generateApplicationProvidersLocked(app);
7810 mSystemThread.installSystemProviders(providers);
7811 }
7812
7813 // =========================================================
7814 // GLOBAL MANAGEMENT
7815 // =========================================================
7816
7817 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7818 ApplicationInfo info, String customProcess) {
7819 String proc = customProcess != null ? customProcess : info.processName;
7820 BatteryStatsImpl.Uid.Proc ps = null;
7821 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7822 synchronized (stats) {
7823 ps = stats.getProcessStatsLocked(info.uid, proc);
7824 }
7825 return new ProcessRecord(ps, thread, info, proc);
7826 }
7827
7828 final ProcessRecord addAppLocked(ApplicationInfo info) {
7829 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7830
7831 if (app == null) {
7832 app = newProcessRecordLocked(null, info, null);
7833 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007834 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007835 }
7836
7837 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7838 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7839 app.persistent = true;
7840 app.maxAdj = CORE_SERVER_ADJ;
7841 }
7842 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7843 mPersistentStartingProcesses.add(app);
7844 startProcessLocked(app, "added application", app.processName);
7845 }
7846
7847 return app;
7848 }
7849
7850 public void unhandledBack() {
7851 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7852 "unhandledBack()");
7853
7854 synchronized(this) {
7855 int count = mHistory.size();
Dianne Hackborn03abb812010-01-04 18:43:19 -08007856 if (DEBUG_SWITCH) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007857 TAG, "Performing unhandledBack(): stack size = " + count);
7858 if (count > 1) {
7859 final long origId = Binder.clearCallingIdentity();
7860 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7861 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7862 Binder.restoreCallingIdentity(origId);
7863 }
7864 }
7865 }
7866
7867 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7868 String name = uri.getAuthority();
7869 ContentProviderHolder cph = getContentProviderExternal(name);
7870 ParcelFileDescriptor pfd = null;
7871 if (cph != null) {
7872 // We record the binder invoker's uid in thread-local storage before
7873 // going to the content provider to open the file. Later, in the code
7874 // that handles all permissions checks, we look for this uid and use
7875 // that rather than the Activity Manager's own uid. The effect is that
7876 // we do the check against the caller's permissions even though it looks
7877 // to the content provider like the Activity Manager itself is making
7878 // the request.
7879 sCallerIdentity.set(new Identity(
7880 Binder.getCallingPid(), Binder.getCallingUid()));
7881 try {
7882 pfd = cph.provider.openFile(uri, "r");
7883 } catch (FileNotFoundException e) {
7884 // do nothing; pfd will be returned null
7885 } finally {
7886 // Ensure that whatever happens, we clean up the identity state
7887 sCallerIdentity.remove();
7888 }
7889
7890 // We've got the fd now, so we're done with the provider.
7891 removeContentProviderExternal(name);
7892 } else {
7893 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7894 }
7895 return pfd;
7896 }
7897
7898 public void goingToSleep() {
7899 synchronized(this) {
7900 mSleeping = true;
7901 mWindowManager.setEventDispatching(false);
7902
7903 if (mResumedActivity != null) {
7904 pauseIfSleepingLocked();
7905 } else {
7906 Log.w(TAG, "goingToSleep with no resumed activity!");
7907 }
7908 }
7909 }
7910
Dianne Hackborn55280a92009-05-07 15:53:46 -07007911 public boolean shutdown(int timeout) {
7912 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7913 != PackageManager.PERMISSION_GRANTED) {
7914 throw new SecurityException("Requires permission "
7915 + android.Manifest.permission.SHUTDOWN);
7916 }
7917
7918 boolean timedout = false;
7919
7920 synchronized(this) {
7921 mShuttingDown = true;
7922 mWindowManager.setEventDispatching(false);
7923
7924 if (mResumedActivity != null) {
7925 pauseIfSleepingLocked();
7926 final long endTime = System.currentTimeMillis() + timeout;
7927 while (mResumedActivity != null || mPausingActivity != null) {
7928 long delay = endTime - System.currentTimeMillis();
7929 if (delay <= 0) {
7930 Log.w(TAG, "Activity manager shutdown timed out");
7931 timedout = true;
7932 break;
7933 }
7934 try {
7935 this.wait();
7936 } catch (InterruptedException e) {
7937 }
7938 }
7939 }
7940 }
7941
7942 mUsageStatsService.shutdown();
7943 mBatteryStatsService.shutdown();
7944
7945 return timedout;
7946 }
7947
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007948 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007949 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007950 if (!mGoingToSleep.isHeld()) {
7951 mGoingToSleep.acquire();
7952 if (mLaunchingActivity.isHeld()) {
7953 mLaunchingActivity.release();
7954 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7955 }
7956 }
7957
7958 // If we are not currently pausing an activity, get the current
7959 // one to pause. If we are pausing one, we will just let that stuff
7960 // run and release the wake lock when all done.
7961 if (mPausingActivity == null) {
7962 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7963 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7964 startPausingLocked(false, true);
7965 }
7966 }
7967 }
7968
7969 public void wakingUp() {
7970 synchronized(this) {
7971 if (mGoingToSleep.isHeld()) {
7972 mGoingToSleep.release();
7973 }
7974 mWindowManager.setEventDispatching(true);
7975 mSleeping = false;
7976 resumeTopActivityLocked(null);
7977 }
7978 }
7979
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007980 public void stopAppSwitches() {
7981 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7982 != PackageManager.PERMISSION_GRANTED) {
7983 throw new SecurityException("Requires permission "
7984 + android.Manifest.permission.STOP_APP_SWITCHES);
7985 }
7986
7987 synchronized(this) {
7988 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7989 + APP_SWITCH_DELAY_TIME;
7990 mDidAppSwitch = false;
7991 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7992 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7993 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7994 }
7995 }
7996
7997 public void resumeAppSwitches() {
7998 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7999 != PackageManager.PERMISSION_GRANTED) {
8000 throw new SecurityException("Requires permission "
8001 + android.Manifest.permission.STOP_APP_SWITCHES);
8002 }
8003
8004 synchronized(this) {
8005 // Note that we don't execute any pending app switches... we will
8006 // let those wait until either the timeout, or the next start
8007 // activity request.
8008 mAppSwitchesAllowedTime = 0;
8009 }
8010 }
8011
8012 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8013 String name) {
8014 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8015 return true;
8016 }
8017
8018 final int perm = checkComponentPermission(
8019 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8020 callingUid, -1);
8021 if (perm == PackageManager.PERMISSION_GRANTED) {
8022 return true;
8023 }
8024
8025 Log.w(TAG, name + " request from " + callingUid + " stopped");
8026 return false;
8027 }
8028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008029 public void setDebugApp(String packageName, boolean waitForDebugger,
8030 boolean persistent) {
8031 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8032 "setDebugApp()");
8033
8034 // Note that this is not really thread safe if there are multiple
8035 // callers into it at the same time, but that's not a situation we
8036 // care about.
8037 if (persistent) {
8038 final ContentResolver resolver = mContext.getContentResolver();
8039 Settings.System.putString(
8040 resolver, Settings.System.DEBUG_APP,
8041 packageName);
8042 Settings.System.putInt(
8043 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8044 waitForDebugger ? 1 : 0);
8045 }
8046
8047 synchronized (this) {
8048 if (!persistent) {
8049 mOrigDebugApp = mDebugApp;
8050 mOrigWaitForDebugger = mWaitForDebugger;
8051 }
8052 mDebugApp = packageName;
8053 mWaitForDebugger = waitForDebugger;
8054 mDebugTransient = !persistent;
8055 if (packageName != null) {
8056 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn03abb812010-01-04 18:43:19 -08008057 forceStopPackageLocked(packageName, -1, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008058 Binder.restoreCallingIdentity(origId);
8059 }
8060 }
8061 }
8062
8063 public void setAlwaysFinish(boolean enabled) {
8064 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8065 "setAlwaysFinish()");
8066
8067 Settings.System.putInt(
8068 mContext.getContentResolver(),
8069 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8070
8071 synchronized (this) {
8072 mAlwaysFinishActivities = enabled;
8073 }
8074 }
8075
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008076 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008077 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008078 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008079 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008080 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008081 }
8082 }
8083
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008084 public void registerActivityWatcher(IActivityWatcher watcher) {
8085 mWatchers.register(watcher);
8086 }
8087
8088 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8089 mWatchers.unregister(watcher);
8090 }
8091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008092 public final void enterSafeMode() {
8093 synchronized(this) {
8094 // It only makes sense to do this before the system is ready
8095 // and started launching other packages.
8096 if (!mSystemReady) {
8097 try {
8098 ActivityThread.getPackageManager().enterSafeMode();
8099 } catch (RemoteException e) {
8100 }
8101
8102 View v = LayoutInflater.from(mContext).inflate(
8103 com.android.internal.R.layout.safe_mode, null);
8104 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8105 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8106 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8107 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8108 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8109 lp.format = v.getBackground().getOpacity();
8110 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8111 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8112 ((WindowManager)mContext.getSystemService(
8113 Context.WINDOW_SERVICE)).addView(v, lp);
8114 }
8115 }
8116 }
8117
8118 public void noteWakeupAlarm(IIntentSender sender) {
8119 if (!(sender instanceof PendingIntentRecord)) {
8120 return;
8121 }
8122 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8123 synchronized (stats) {
8124 if (mBatteryStatsService.isOnBattery()) {
8125 mBatteryStatsService.enforceCallingPermission();
8126 PendingIntentRecord rec = (PendingIntentRecord)sender;
8127 int MY_UID = Binder.getCallingUid();
8128 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8129 BatteryStatsImpl.Uid.Pkg pkg =
8130 stats.getPackageStatsLocked(uid, rec.key.packageName);
8131 pkg.incWakeupsLocked();
8132 }
8133 }
8134 }
8135
8136 public boolean killPidsForMemory(int[] pids) {
8137 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8138 throw new SecurityException("killPidsForMemory only available to the system");
8139 }
8140
8141 // XXX Note: don't acquire main activity lock here, because the window
8142 // manager calls in with its locks held.
8143
8144 boolean killed = false;
8145 synchronized (mPidsSelfLocked) {
8146 int[] types = new int[pids.length];
8147 int worstType = 0;
8148 for (int i=0; i<pids.length; i++) {
8149 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8150 if (proc != null) {
8151 int type = proc.setAdj;
8152 types[i] = type;
8153 if (type > worstType) {
8154 worstType = type;
8155 }
8156 }
8157 }
8158
8159 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8160 // then constrain it so we will kill all hidden procs.
8161 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8162 worstType = HIDDEN_APP_MIN_ADJ;
8163 }
8164 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8165 for (int i=0; i<pids.length; i++) {
8166 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8167 if (proc == null) {
8168 continue;
8169 }
8170 int adj = proc.setAdj;
8171 if (adj >= worstType) {
8172 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8173 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008174 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008175 proc.processName, adj);
8176 killed = true;
8177 Process.killProcess(pids[i]);
8178 }
8179 }
8180 }
8181 return killed;
8182 }
8183
8184 public void reportPss(IApplicationThread caller, int pss) {
8185 Watchdog.PssRequestor req;
8186 String name;
8187 ProcessRecord callerApp;
8188 synchronized (this) {
8189 if (caller == null) {
8190 return;
8191 }
8192 callerApp = getRecordForAppLocked(caller);
8193 if (callerApp == null) {
8194 return;
8195 }
8196 callerApp.lastPss = pss;
8197 req = callerApp;
8198 name = callerApp.processName;
8199 }
8200 Watchdog.getInstance().reportPss(req, name, pss);
8201 if (!callerApp.persistent) {
8202 removeRequestedPss(callerApp);
8203 }
8204 }
8205
8206 public void requestPss(Runnable completeCallback) {
8207 ArrayList<ProcessRecord> procs;
8208 synchronized (this) {
8209 mRequestPssCallback = completeCallback;
8210 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008211 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8212 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008213 if (!proc.persistent) {
8214 mRequestPssList.add(proc);
8215 }
8216 }
8217 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8218 }
8219
8220 int oldPri = Process.getThreadPriority(Process.myTid());
8221 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8222 for (int i=procs.size()-1; i>=0; i--) {
8223 ProcessRecord proc = procs.get(i);
8224 proc.lastPss = 0;
8225 proc.requestPss();
8226 }
8227 Process.setThreadPriority(oldPri);
8228 }
8229
8230 void removeRequestedPss(ProcessRecord proc) {
8231 Runnable callback = null;
8232 synchronized (this) {
8233 if (mRequestPssList.remove(proc)) {
8234 if (mRequestPssList.size() == 0) {
8235 callback = mRequestPssCallback;
8236 mRequestPssCallback = null;
8237 }
8238 }
8239 }
8240
8241 if (callback != null) {
8242 callback.run();
8243 }
8244 }
8245
8246 public void collectPss(Watchdog.PssStats stats) {
8247 stats.mEmptyPss = 0;
8248 stats.mEmptyCount = 0;
8249 stats.mBackgroundPss = 0;
8250 stats.mBackgroundCount = 0;
8251 stats.mServicePss = 0;
8252 stats.mServiceCount = 0;
8253 stats.mVisiblePss = 0;
8254 stats.mVisibleCount = 0;
8255 stats.mForegroundPss = 0;
8256 stats.mForegroundCount = 0;
8257 stats.mNoPssCount = 0;
8258 synchronized (this) {
8259 int i;
8260 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8261 ? mProcDeaths.length : stats.mProcDeaths.length;
8262 int aggr = 0;
8263 for (i=0; i<NPD; i++) {
8264 aggr += mProcDeaths[i];
8265 stats.mProcDeaths[i] = aggr;
8266 }
8267 while (i<stats.mProcDeaths.length) {
8268 stats.mProcDeaths[i] = 0;
8269 i++;
8270 }
8271
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008272 for (i=mLruProcesses.size()-1; i>=0; i--) {
8273 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008274 if (proc.persistent) {
8275 continue;
8276 }
8277 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8278 if (proc.lastPss == 0) {
8279 stats.mNoPssCount++;
8280 continue;
8281 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008282 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8283 if (proc.empty) {
8284 stats.mEmptyPss += proc.lastPss;
8285 stats.mEmptyCount++;
8286 } else {
8287 stats.mBackgroundPss += proc.lastPss;
8288 stats.mBackgroundCount++;
8289 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008290 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8291 stats.mVisiblePss += proc.lastPss;
8292 stats.mVisibleCount++;
8293 } else {
8294 stats.mForegroundPss += proc.lastPss;
8295 stats.mForegroundCount++;
8296 }
8297 }
8298 }
8299 }
8300
8301 public final void startRunning(String pkg, String cls, String action,
8302 String data) {
8303 synchronized(this) {
8304 if (mStartRunning) {
8305 return;
8306 }
8307 mStartRunning = true;
8308 mTopComponent = pkg != null && cls != null
8309 ? new ComponentName(pkg, cls) : null;
8310 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8311 mTopData = data;
8312 if (!mSystemReady) {
8313 return;
8314 }
8315 }
8316
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008317 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008318 }
8319
8320 private void retrieveSettings() {
8321 final ContentResolver resolver = mContext.getContentResolver();
8322 String debugApp = Settings.System.getString(
8323 resolver, Settings.System.DEBUG_APP);
8324 boolean waitForDebugger = Settings.System.getInt(
8325 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8326 boolean alwaysFinishActivities = Settings.System.getInt(
8327 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8328
8329 Configuration configuration = new Configuration();
8330 Settings.System.getConfiguration(resolver, configuration);
8331
8332 synchronized (this) {
8333 mDebugApp = mOrigDebugApp = debugApp;
8334 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8335 mAlwaysFinishActivities = alwaysFinishActivities;
8336 // This happens before any activities are started, so we can
8337 // change mConfiguration in-place.
8338 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008339 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008340 }
8341 }
8342
8343 public boolean testIsSystemReady() {
8344 // no need to synchronize(this) just to read & return the value
8345 return mSystemReady;
8346 }
8347
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008348 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008349 // In the simulator, startRunning will never have been called, which
8350 // normally sets a few crucial variables. Do it here instead.
8351 if (!Process.supportsProcesses()) {
8352 mStartRunning = true;
8353 mTopAction = Intent.ACTION_MAIN;
8354 }
8355
8356 synchronized(this) {
8357 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008358 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008359 return;
8360 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008361
8362 // Check to see if there are any update receivers to run.
8363 if (!mDidUpdate) {
8364 if (mWaitingUpdate) {
8365 return;
8366 }
8367 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8368 List<ResolveInfo> ris = null;
8369 try {
8370 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8371 intent, null, 0);
8372 } catch (RemoteException e) {
8373 }
8374 if (ris != null) {
8375 for (int i=ris.size()-1; i>=0; i--) {
8376 if ((ris.get(i).activityInfo.applicationInfo.flags
8377 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8378 ris.remove(i);
8379 }
8380 }
8381 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8382 for (int i=0; i<ris.size(); i++) {
8383 ActivityInfo ai = ris.get(i).activityInfo;
8384 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8385 IIntentReceiver finisher = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -08008386 if (i == ris.size()-1) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008387 finisher = new IIntentReceiver.Stub() {
8388 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008389 String data, Bundle extras, boolean ordered,
8390 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008391 throws RemoteException {
8392 synchronized (ActivityManagerService.this) {
8393 mDidUpdate = true;
8394 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008395 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008396 }
8397 };
8398 }
8399 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8400 broadcastIntentLocked(null, null, intent, null, finisher,
8401 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornd6847842010-01-12 18:14:19 -08008402 if (finisher != null) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008403 mWaitingUpdate = true;
8404 }
8405 }
8406 }
8407 if (mWaitingUpdate) {
8408 return;
8409 }
8410 mDidUpdate = true;
8411 }
8412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008413 mSystemReady = true;
8414 if (!mStartRunning) {
8415 return;
8416 }
8417 }
8418
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008419 ArrayList<ProcessRecord> procsToKill = null;
8420 synchronized(mPidsSelfLocked) {
8421 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8422 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8423 if (!isAllowedWhileBooting(proc.info)){
8424 if (procsToKill == null) {
8425 procsToKill = new ArrayList<ProcessRecord>();
8426 }
8427 procsToKill.add(proc);
8428 }
8429 }
8430 }
8431
8432 if (procsToKill != null) {
8433 synchronized(this) {
8434 for (int i=procsToKill.size()-1; i>=0; i--) {
8435 ProcessRecord proc = procsToKill.get(i);
8436 Log.i(TAG, "Removing system update proc: " + proc);
8437 removeProcessLocked(proc, true);
8438 }
8439 }
8440 }
8441
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008442 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008443 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008444 SystemClock.uptimeMillis());
8445
8446 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008447 // Make sure we have no pre-ready processes sitting around.
8448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008449 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8450 ResolveInfo ri = mContext.getPackageManager()
8451 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008452 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008453 CharSequence errorMsg = null;
8454 if (ri != null) {
8455 ActivityInfo ai = ri.activityInfo;
8456 ApplicationInfo app = ai.applicationInfo;
8457 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8458 mTopAction = Intent.ACTION_FACTORY_TEST;
8459 mTopData = null;
8460 mTopComponent = new ComponentName(app.packageName,
8461 ai.name);
8462 } else {
8463 errorMsg = mContext.getResources().getText(
8464 com.android.internal.R.string.factorytest_not_system);
8465 }
8466 } else {
8467 errorMsg = mContext.getResources().getText(
8468 com.android.internal.R.string.factorytest_no_action);
8469 }
8470 if (errorMsg != null) {
8471 mTopAction = null;
8472 mTopData = null;
8473 mTopComponent = null;
8474 Message msg = Message.obtain();
8475 msg.what = SHOW_FACTORY_ERROR_MSG;
8476 msg.getData().putCharSequence("msg", errorMsg);
8477 mHandler.sendMessage(msg);
8478 }
8479 }
8480 }
8481
8482 retrieveSettings();
8483
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008484 if (goingCallback != null) goingCallback.run();
8485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008486 synchronized (this) {
8487 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8488 try {
8489 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008490 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008491 if (apps != null) {
8492 int N = apps.size();
8493 int i;
8494 for (i=0; i<N; i++) {
8495 ApplicationInfo info
8496 = (ApplicationInfo)apps.get(i);
8497 if (info != null &&
8498 !info.packageName.equals("android")) {
8499 addAppLocked(info);
8500 }
8501 }
8502 }
8503 } catch (RemoteException ex) {
8504 // pm is in same process, this will never happen.
8505 }
8506 }
8507
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008508 // Start up initial activity.
8509 mBooting = true;
8510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008511 try {
8512 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8513 Message msg = Message.obtain();
8514 msg.what = SHOW_UID_ERROR_MSG;
8515 mHandler.sendMessage(msg);
8516 }
8517 } catch (RemoteException e) {
8518 }
8519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008520 resumeTopActivityLocked(null);
8521 }
8522 }
8523
Dan Egnorb7f03672009-12-09 16:22:32 -08008524 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008525 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008526 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008527 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008528 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008529 startAppProblemLocked(app);
8530 app.stopFreezingAllLocked();
8531 return handleAppCrashLocked(app);
8532 }
8533
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008534 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Doug Zongker43866e02010-01-07 12:09:54 -08008535 // check if error reporting is enabled in secure settings
8536 int enabled = Settings.Secure.getInt(mContext.getContentResolver(),
8537 Settings.Secure.SEND_ACTION_APP_ERROR, 0);
Jacek Surazskia2339432009-09-18 15:01:26 +02008538 if (enabled == 0) {
8539 return null;
8540 }
8541
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008542 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008543
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008544 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008545 // look for receiver in the installer package
8546 String candidate = pm.getInstallerPackageName(app.info.packageName);
8547 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8548 if (result != null) {
8549 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008550 }
8551
Jacek Surazski82a73df2009-06-17 14:33:18 +02008552 // if the error app is on the system image, look for system apps
8553 // error receiver
8554 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8555 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8556 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8557 if (result != null) {
8558 return result;
8559 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008560 }
8561
Jacek Surazski82a73df2009-06-17 14:33:18 +02008562 // if there is a default receiver, try that
8563 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8564 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008565 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008566 // should not happen
8567 Log.e(TAG, "error talking to PackageManager", e);
8568 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008569 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008570 }
8571
8572 /**
8573 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8574 *
8575 * @param pm PackageManager isntance
8576 * @param errorPackage package which caused the error
8577 * @param receiverPackage candidate package to receive the error
8578 * @return activity component within receiverPackage which handles
8579 * ACTION_APP_ERROR, or null if not found
8580 */
8581 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8582 String receiverPackage) throws RemoteException {
8583 if (receiverPackage == null || receiverPackage.length() == 0) {
8584 return null;
8585 }
8586
8587 // break the loop if it's the error report receiver package that crashed
8588 if (receiverPackage.equals(errorPackage)) {
8589 return null;
8590 }
8591
8592 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8593 intent.setPackage(receiverPackage);
8594 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8595 if (info == null || info.activityInfo == null) {
8596 return null;
8597 }
8598 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008599 }
8600
Dan Egnorb7f03672009-12-09 16:22:32 -08008601 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008602 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008603 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008604 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008605 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8606 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008607 startAppProblemLocked(app);
8608 app.stopFreezingAllLocked();
8609 }
8610
8611 /**
8612 * Generate a process error record, suitable for attachment to a ProcessRecord.
8613 *
8614 * @param app The ProcessRecord in which the error occurred.
8615 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8616 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008617 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008618 * @param shortMsg Short message describing the crash.
8619 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008620 * @param stackTrace Full crash stack trace, may be null.
8621 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008622 * @return Returns a fully-formed AppErrorStateInfo record.
8623 */
8624 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008625 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008626 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008628 report.condition = condition;
8629 report.processName = app.processName;
8630 report.pid = app.pid;
8631 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008632 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008633 report.shortMsg = shortMsg;
8634 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008635 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008636
8637 return report;
8638 }
8639
Dan Egnor42471dd2010-01-07 17:25:22 -08008640 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008641 synchronized (this) {
8642 app.crashing = false;
8643 app.crashingReport = null;
8644 app.notResponding = false;
8645 app.notRespondingReport = null;
8646 if (app.anrDialog == fromDialog) {
8647 app.anrDialog = null;
8648 }
8649 if (app.waitDialog == fromDialog) {
8650 app.waitDialog = null;
8651 }
8652 if (app.pid > 0 && app.pid != MY_PID) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008653 handleAppCrashLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008654 Log.i(ActivityManagerService.TAG, "Killing process "
8655 + app.processName
8656 + " (pid=" + app.pid + ") at user's request");
8657 Process.killProcess(app.pid);
8658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008659 }
8660 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008661
Dan Egnorb7f03672009-12-09 16:22:32 -08008662 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008663 long now = SystemClock.uptimeMillis();
8664
8665 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8666 app.info.uid);
8667 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8668 // This process loses!
8669 Log.w(TAG, "Process " + app.info.processName
8670 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008671 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008672 app.info.processName, app.info.uid);
8673 killServicesLocked(app, false);
8674 for (int i=mHistory.size()-1; i>=0; i--) {
8675 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8676 if (r.app == app) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08008677 Log.w(TAG, " Force finishing activity "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008678 + r.intent.getComponent().flattenToShortString());
8679 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8680 }
8681 }
8682 if (!app.persistent) {
8683 // We don't want to start this process again until the user
8684 // explicitly does so... but for persistent process, we really
8685 // need to keep it running. If a persistent process is actually
8686 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008687 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008688 app.info.processName);
8689 mBadProcesses.put(app.info.processName, app.info.uid, now);
8690 app.bad = true;
8691 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8692 app.removed = true;
8693 removeProcessLocked(app, false);
8694 return false;
8695 }
8696 }
8697
8698 // Bump up the crash count of any services currently running in the proc.
8699 if (app.services.size() != 0) {
8700 // Any services running in the application need to be placed
8701 // back in the pending list.
8702 Iterator it = app.services.iterator();
8703 while (it.hasNext()) {
8704 ServiceRecord sr = (ServiceRecord)it.next();
8705 sr.crashCount++;
8706 }
8707 }
8708
8709 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8710 return true;
8711 }
8712
8713 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008714 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008715 skipCurrentReceiverLocked(app);
8716 }
8717
8718 void skipCurrentReceiverLocked(ProcessRecord app) {
8719 boolean reschedule = false;
8720 BroadcastRecord r = app.curReceiver;
8721 if (r != null) {
8722 // The current broadcast is waiting for this app's receiver
8723 // to be finished. Looks like that's not going to happen, so
8724 // let the broadcast continue.
8725 logBroadcastReceiverDiscard(r);
8726 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8727 r.resultExtras, r.resultAbort, true);
8728 reschedule = true;
8729 }
8730 r = mPendingBroadcast;
8731 if (r != null && r.curApp == app) {
8732 if (DEBUG_BROADCAST) Log.v(TAG,
8733 "skip & discard pending app " + r);
8734 logBroadcastReceiverDiscard(r);
8735 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8736 r.resultExtras, r.resultAbort, true);
8737 reschedule = true;
8738 }
8739 if (reschedule) {
8740 scheduleBroadcastsLocked();
8741 }
8742 }
8743
Dan Egnor60d87622009-12-16 16:32:58 -08008744 /**
8745 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8746 * The application process will exit immediately after this call returns.
8747 * @param app object of the crashing app, null for the system server
8748 * @param crashInfo describing the exception
8749 */
8750 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8751 ProcessRecord r = findAppProcess(app);
8752
8753 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8754 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008755 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008756 crashInfo.exceptionClassName,
8757 crashInfo.exceptionMessage,
8758 crashInfo.throwFileName,
8759 crashInfo.throwLineNumber);
8760
Dan Egnor42471dd2010-01-07 17:25:22 -08008761 addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008762
8763 crashApplication(r, crashInfo);
8764 }
8765
8766 /**
8767 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8768 * @param app object of the crashing app, null for the system server
8769 * @param tag reported by the caller
8770 * @param crashInfo describing the context of the error
8771 * @return true if the process should exit immediately (WTF is fatal)
8772 */
8773 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008774 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008775 ProcessRecord r = findAppProcess(app);
8776
8777 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8778 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008779 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008780 tag, crashInfo.exceptionMessage);
8781
Dan Egnor42471dd2010-01-07 17:25:22 -08008782 addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008783
Doug Zongker43866e02010-01-07 12:09:54 -08008784 if (Settings.Secure.getInt(mContext.getContentResolver(),
8785 Settings.Secure.WTF_IS_FATAL, 0) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008786 crashApplication(r, crashInfo);
8787 return true;
8788 } else {
8789 return false;
8790 }
8791 }
8792
8793 /**
8794 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8795 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8796 */
8797 private ProcessRecord findAppProcess(IBinder app) {
8798 if (app == null) {
8799 return null;
8800 }
8801
8802 synchronized (this) {
8803 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8804 final int NA = apps.size();
8805 for (int ia=0; ia<NA; ia++) {
8806 ProcessRecord p = apps.valueAt(ia);
8807 if (p.thread != null && p.thread.asBinder() == app) {
8808 return p;
8809 }
8810 }
8811 }
8812
8813 Log.w(TAG, "Can't find mystery application: " + app);
8814 return null;
8815 }
8816 }
8817
8818 /**
Dan Egnor42471dd2010-01-07 17:25:22 -08008819 * Write a description of an error (crash, WTF, ANR) to the drop box.
Dan Egnor60d87622009-12-16 16:32:58 -08008820 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
Dan Egnor42471dd2010-01-07 17:25:22 -08008821 * @param process which caused the error, null means the system server
8822 * @param activity which triggered the error, null if unknown
8823 * @param parent activity related to the error, null if unknown
8824 * @param subject line related to the error, null if absent
8825 * @param report in long form describing the error, null if absent
8826 * @param logFile to include in the report, null if none
8827 * @param crashInfo giving an application stack trace, null if absent
Dan Egnor60d87622009-12-16 16:32:58 -08008828 */
Dan Egnor42471dd2010-01-07 17:25:22 -08008829 private void addErrorToDropBox(String eventType,
8830 ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
8831 String subject, String report, File logFile,
Dan Egnor60d87622009-12-16 16:32:58 -08008832 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008833 String dropboxTag;
8834 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008835 dropboxTag = "system_server_" + eventType;
Dan Egnor42471dd2010-01-07 17:25:22 -08008836 } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008837 dropboxTag = "system_app_" + eventType;
8838 } else {
8839 dropboxTag = "data_app_" + eventType;
8840 }
8841
8842 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8843 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8844 StringBuilder sb = new StringBuilder(1024);
Dan Egnor42471dd2010-01-07 17:25:22 -08008845 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008846 sb.append("Process: system_server\n");
8847 } else {
Dan Egnor42471dd2010-01-07 17:25:22 -08008848 sb.append("Process: ").append(process.processName).append("\n");
Dan Egnor66c40e72010-01-26 16:23:11 -08008849 }
8850 if (process != null) {
8851 int flags = process.info.flags;
8852 IPackageManager pm = ActivityThread.getPackageManager();
8853 sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
8854 for (String pkg : process.pkgList) {
8855 sb.append("Package: ").append(pkg);
8856 try {
8857 PackageInfo pi = pm.getPackageInfo(pkg, 0);
8858 if (pi != null) {
8859 sb.append(" v").append(pi.versionCode);
8860 if (pi.versionName != null) {
8861 sb.append(" (").append(pi.versionName).append(")");
8862 }
8863 }
8864 } catch (RemoteException e) {
8865 Log.e(TAG, "Error getting package info: " + pkg, e);
8866 }
8867 sb.append("\n");
8868 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008869 }
8870 if (activity != null) {
8871 sb.append("Activity: ").append(activity.shortComponentName).append("\n");
8872 }
8873 if (parent != null && parent.app != null && parent.app.pid != process.pid) {
8874 sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
8875 }
8876 if (parent != null && parent != activity) {
8877 sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
8878 }
8879 if (subject != null) {
8880 sb.append("Subject: ").append(subject).append("\n");
8881 }
8882 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8883 sb.append("\n");
8884 if (report != null) {
8885 sb.append(report);
8886 }
8887 if (logFile != null) {
8888 try {
8889 sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
8890 } catch (IOException e) {
8891 Log.e(TAG, "Error reading " + logFile, e);
Dan Egnor60d87622009-12-16 16:32:58 -08008892 }
8893 }
Dan Egnor60d87622009-12-16 16:32:58 -08008894 if (crashInfo != null && crashInfo.stackTrace != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008895 sb.append(crashInfo.stackTrace);
Dan Egnor60d87622009-12-16 16:32:58 -08008896 }
8897 dbox.addText(dropboxTag, sb.toString());
8898 }
8899 }
8900
8901 /**
8902 * Bring up the "unexpected error" dialog box for a crashing app.
8903 * Deal with edge cases (intercepts from instrumented applications,
8904 * ActivityController, error intent receivers, that sort of thing).
8905 * @param r the application crashing
8906 * @param crashInfo describing the failure
8907 */
8908 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008909 long timeMillis = System.currentTimeMillis();
8910 String shortMsg = crashInfo.exceptionClassName;
8911 String longMsg = crashInfo.exceptionMessage;
8912 String stackTrace = crashInfo.stackTrace;
8913 if (shortMsg != null && longMsg != null) {
8914 longMsg = shortMsg + ": " + longMsg;
8915 } else if (shortMsg != null) {
8916 longMsg = shortMsg;
8917 }
8918
Dan Egnor60d87622009-12-16 16:32:58 -08008919 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008920 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008921 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008922 try {
8923 String name = r != null ? r.processName : null;
8924 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008925 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008926 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008927 Log.w(TAG, "Force-killing crashed app " + name
8928 + " at watcher's request");
8929 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008930 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008931 }
8932 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008933 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008934 }
8935 }
8936
8937 final long origId = Binder.clearCallingIdentity();
8938
8939 // If this process is running instrumentation, finish it.
8940 if (r != null && r.instrumentationClass != null) {
8941 Log.w(TAG, "Error in app " + r.processName
8942 + " running instrumentation " + r.instrumentationClass + ":");
8943 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8944 if (longMsg != null) Log.w(TAG, " " + longMsg);
8945 Bundle info = new Bundle();
8946 info.putString("shortMsg", shortMsg);
8947 info.putString("longMsg", longMsg);
8948 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8949 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008950 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008951 }
8952
Dan Egnor60d87622009-12-16 16:32:58 -08008953 // If we can't identify the process or it's already exceeded its crash quota,
8954 // quit right away without showing a crash dialog.
8955 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008956 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008957 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008958 }
8959
8960 Message msg = Message.obtain();
8961 msg.what = SHOW_ERROR_MSG;
8962 HashMap data = new HashMap();
8963 data.put("result", result);
8964 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008965 msg.obj = data;
8966 mHandler.sendMessage(msg);
8967
8968 Binder.restoreCallingIdentity(origId);
8969 }
8970
8971 int res = result.get();
8972
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008973 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008974 synchronized (this) {
8975 if (r != null) {
8976 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8977 SystemClock.uptimeMillis());
8978 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008979 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008980 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008981 }
8982 }
8983
8984 if (appErrorIntent != null) {
8985 try {
8986 mContext.startActivity(appErrorIntent);
8987 } catch (ActivityNotFoundException e) {
8988 Log.w(TAG, "bug report receiver dissappeared", e);
8989 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008990 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008991 }
Dan Egnorb7f03672009-12-09 16:22:32 -08008992
8993 Intent createAppErrorIntentLocked(ProcessRecord r,
8994 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
8995 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008996 if (report == null) {
8997 return null;
8998 }
8999 Intent result = new Intent(Intent.ACTION_APP_ERROR);
9000 result.setComponent(r.errorReportReceiver);
9001 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
9002 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
9003 return result;
9004 }
9005
Dan Egnorb7f03672009-12-09 16:22:32 -08009006 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
9007 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009008 if (r.errorReportReceiver == null) {
9009 return null;
9010 }
9011
9012 if (!r.crashing && !r.notResponding) {
9013 return null;
9014 }
9015
Dan Egnorb7f03672009-12-09 16:22:32 -08009016 ApplicationErrorReport report = new ApplicationErrorReport();
9017 report.packageName = r.info.packageName;
9018 report.installerPackageName = r.errorReportReceiver.getPackageName();
9019 report.processName = r.processName;
9020 report.time = timeMillis;
Jacek Surazskie0ee6ef2010-01-07 16:23:03 +01009021 report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009022
Dan Egnorb7f03672009-12-09 16:22:32 -08009023 if (r.crashing) {
9024 report.type = ApplicationErrorReport.TYPE_CRASH;
9025 report.crashInfo = crashInfo;
9026 } else if (r.notResponding) {
9027 report.type = ApplicationErrorReport.TYPE_ANR;
9028 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009029
Dan Egnorb7f03672009-12-09 16:22:32 -08009030 report.anrInfo.activity = r.notRespondingReport.tag;
9031 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9032 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009033 }
9034
Dan Egnorb7f03672009-12-09 16:22:32 -08009035 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009036 }
9037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009038 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9039 // assume our apps are happy - lazy create the list
9040 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9041
9042 synchronized (this) {
9043
9044 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009045 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9046 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009047 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9048 // This one's in trouble, so we'll generate a report for it
9049 // crashes are higher priority (in case there's a crash *and* an anr)
9050 ActivityManager.ProcessErrorStateInfo report = null;
9051 if (app.crashing) {
9052 report = app.crashingReport;
9053 } else if (app.notResponding) {
9054 report = app.notRespondingReport;
9055 }
9056
9057 if (report != null) {
9058 if (errList == null) {
9059 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9060 }
9061 errList.add(report);
9062 } else {
9063 Log.w(TAG, "Missing app error report, app = " + app.processName +
9064 " crashing = " + app.crashing +
9065 " notResponding = " + app.notResponding);
9066 }
9067 }
9068 }
9069 }
9070
9071 return errList;
9072 }
9073
9074 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9075 // Lazy instantiation of list
9076 List<ActivityManager.RunningAppProcessInfo> runList = null;
9077 synchronized (this) {
9078 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009079 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9080 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009081 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9082 // Generate process state info for running application
9083 ActivityManager.RunningAppProcessInfo currApp =
9084 new ActivityManager.RunningAppProcessInfo(app.processName,
9085 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009086 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009087 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009088 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009089 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9090 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9091 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009092 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9093 } else if (adj >= HOME_APP_ADJ) {
9094 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9095 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009096 } else if (adj >= SECONDARY_SERVER_ADJ) {
9097 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9098 } else if (adj >= VISIBLE_APP_ADJ) {
9099 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9100 } else {
9101 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9102 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009103 currApp.importanceReasonCode = app.adjTypeCode;
9104 if (app.adjSource instanceof ProcessRecord) {
9105 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9106 } else if (app.adjSource instanceof HistoryRecord) {
9107 HistoryRecord r = (HistoryRecord)app.adjSource;
9108 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9109 }
9110 if (app.adjTarget instanceof ComponentName) {
9111 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9112 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009113 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9114 // + " lru=" + currApp.lru);
9115 if (runList == null) {
9116 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9117 }
9118 runList.add(currApp);
9119 }
9120 }
9121 }
9122 return runList;
9123 }
9124
9125 @Override
9126 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009127 if (checkCallingPermission(android.Manifest.permission.DUMP)
9128 != PackageManager.PERMISSION_GRANTED) {
9129 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9130 + Binder.getCallingPid()
9131 + ", uid=" + Binder.getCallingUid()
9132 + " without permission "
9133 + android.Manifest.permission.DUMP);
9134 return;
9135 }
9136
9137 boolean dumpAll = false;
9138
9139 int opti = 0;
9140 while (opti < args.length) {
9141 String opt = args[opti];
9142 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9143 break;
9144 }
9145 opti++;
9146 if ("-a".equals(opt)) {
9147 dumpAll = true;
9148 } else if ("-h".equals(opt)) {
9149 pw.println("Activity manager dump options:");
9150 pw.println(" [-a] [h- [cmd] ...");
9151 pw.println(" cmd may be one of:");
9152 pw.println(" activities: activity stack state");
9153 pw.println(" broadcasts: broadcast state");
9154 pw.println(" intents: pending intent state");
9155 pw.println(" processes: process state");
9156 pw.println(" providers: content provider state");
9157 pw.println(" services: service state");
9158 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009159 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009160 } else {
9161 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009162 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009163 }
9164
9165 // Is the caller requesting to dump a particular piece of data?
9166 if (opti < args.length) {
9167 String cmd = args[opti];
9168 opti++;
9169 if ("activities".equals(cmd) || "a".equals(cmd)) {
9170 synchronized (this) {
9171 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009172 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009173 return;
9174 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9175 synchronized (this) {
9176 dumpBroadcastsLocked(fd, pw, args, opti, true);
9177 }
9178 return;
9179 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9180 synchronized (this) {
9181 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9182 }
9183 return;
9184 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9185 synchronized (this) {
9186 dumpProcessesLocked(fd, pw, args, opti, true);
9187 }
9188 return;
9189 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9190 synchronized (this) {
9191 dumpProvidersLocked(fd, pw, args, opti, true);
9192 }
9193 return;
9194 } else if ("service".equals(cmd)) {
9195 dumpService(fd, pw, args, opti, true);
9196 return;
9197 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9198 synchronized (this) {
9199 dumpServicesLocked(fd, pw, args, opti, true);
9200 }
9201 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009202 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009203 }
9204
9205 // No piece of data specified, dump everything.
9206 synchronized (this) {
9207 boolean needSep;
9208 if (dumpAll) {
9209 pw.println("Providers in Current Activity Manager State:");
9210 }
9211 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9212 if (needSep) {
9213 pw.println(" ");
9214 }
9215 if (dumpAll) {
9216 pw.println("-------------------------------------------------------------------------------");
9217 pw.println("Broadcasts in Current Activity Manager State:");
9218 }
9219 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9220 if (needSep) {
9221 pw.println(" ");
9222 }
9223 if (dumpAll) {
9224 pw.println("-------------------------------------------------------------------------------");
9225 pw.println("Services in Current Activity Manager State:");
9226 }
9227 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9228 if (needSep) {
9229 pw.println(" ");
9230 }
9231 if (dumpAll) {
9232 pw.println("-------------------------------------------------------------------------------");
9233 pw.println("PendingIntents in Current Activity Manager State:");
9234 }
9235 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9236 if (needSep) {
9237 pw.println(" ");
9238 }
9239 if (dumpAll) {
9240 pw.println("-------------------------------------------------------------------------------");
9241 pw.println("Activities in Current Activity Manager State:");
9242 }
9243 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9244 if (needSep) {
9245 pw.println(" ");
9246 }
9247 if (dumpAll) {
9248 pw.println("-------------------------------------------------------------------------------");
9249 pw.println("Processes in Current Activity Manager State:");
9250 }
9251 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9252 }
9253 }
9254
9255 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9256 int opti, boolean dumpAll, boolean needHeader) {
9257 if (needHeader) {
9258 pw.println(" Activity stack:");
9259 }
9260 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9261 pw.println(" ");
9262 pw.println(" Running activities (most recent first):");
9263 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9264 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009265 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009266 pw.println(" Activities waiting for another to become visible:");
9267 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9268 }
9269 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009270 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009271 pw.println(" Activities waiting to stop:");
9272 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9273 }
9274 if (mFinishingActivities.size() > 0) {
9275 pw.println(" ");
9276 pw.println(" Activities waiting to finish:");
9277 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9278 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009279
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009280 pw.println(" ");
9281 pw.println(" mPausingActivity: " + mPausingActivity);
9282 pw.println(" mResumedActivity: " + mResumedActivity);
9283 pw.println(" mFocusedActivity: " + mFocusedActivity);
9284 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009285
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009286 if (dumpAll && mRecentTasks.size() > 0) {
9287 pw.println(" ");
9288 pw.println("Recent tasks in Current Activity Manager State:");
9289
9290 final int N = mRecentTasks.size();
9291 for (int i=0; i<N; i++) {
9292 TaskRecord tr = mRecentTasks.get(i);
9293 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9294 pw.println(tr);
9295 mRecentTasks.get(i).dump(pw, " ");
9296 }
9297 }
9298
9299 pw.println(" ");
9300 pw.println(" mCurTask: " + mCurTask);
9301
9302 return true;
9303 }
9304
9305 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9306 int opti, boolean dumpAll) {
9307 boolean needSep = false;
9308 int numPers = 0;
9309
9310 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009311 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9312 final int NA = procs.size();
9313 for (int ia=0; ia<NA; ia++) {
9314 if (!needSep) {
9315 pw.println(" All known processes:");
9316 needSep = true;
9317 }
9318 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009319 pw.print(r.persistent ? " *PERS*" : " *APP*");
9320 pw.print(" UID "); pw.print(procs.keyAt(ia));
9321 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009322 r.dump(pw, " ");
9323 if (r.persistent) {
9324 numPers++;
9325 }
9326 }
9327 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009328 }
9329
9330 if (mLruProcesses.size() > 0) {
9331 if (needSep) pw.println(" ");
9332 needSep = true;
9333 pw.println(" Running processes (most recent first):");
9334 dumpProcessList(pw, this, mLruProcesses, " ",
9335 "App ", "PERS", true);
9336 needSep = true;
9337 }
9338
9339 synchronized (mPidsSelfLocked) {
9340 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009341 if (needSep) pw.println(" ");
9342 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009343 pw.println(" PID mappings:");
9344 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9345 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9346 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009347 }
9348 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009349 }
9350
9351 if (mForegroundProcesses.size() > 0) {
9352 if (needSep) pw.println(" ");
9353 needSep = true;
9354 pw.println(" Foreground Processes:");
9355 for (int i=0; i<mForegroundProcesses.size(); i++) {
9356 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9357 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009358 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009359 }
9360
9361 if (mPersistentStartingProcesses.size() > 0) {
9362 if (needSep) pw.println(" ");
9363 needSep = true;
9364 pw.println(" Persisent processes that are starting:");
9365 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9366 "Starting Norm", "Restarting PERS", false);
9367 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009368
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009369 if (mStartingProcesses.size() > 0) {
9370 if (needSep) pw.println(" ");
9371 needSep = true;
9372 pw.println(" Processes that are starting:");
9373 dumpProcessList(pw, this, mStartingProcesses, " ",
9374 "Starting Norm", "Starting PERS", false);
9375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009376
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009377 if (mRemovedProcesses.size() > 0) {
9378 if (needSep) pw.println(" ");
9379 needSep = true;
9380 pw.println(" Processes that are being removed:");
9381 dumpProcessList(pw, this, mRemovedProcesses, " ",
9382 "Removed Norm", "Removed PERS", false);
9383 }
9384
9385 if (mProcessesOnHold.size() > 0) {
9386 if (needSep) pw.println(" ");
9387 needSep = true;
9388 pw.println(" Processes that are on old until the system is ready:");
9389 dumpProcessList(pw, this, mProcessesOnHold, " ",
9390 "OnHold Norm", "OnHold PERS", false);
9391 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009392
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009393 if (mProcessesToGc.size() > 0) {
9394 if (needSep) pw.println(" ");
9395 needSep = true;
9396 pw.println(" Processes that are waiting to GC:");
9397 long now = SystemClock.uptimeMillis();
9398 for (int i=0; i<mProcessesToGc.size(); i++) {
9399 ProcessRecord proc = mProcessesToGc.get(i);
9400 pw.print(" Process "); pw.println(proc);
9401 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9402 pw.print(", last gced=");
9403 pw.print(now-proc.lastRequestedGc);
9404 pw.print(" ms ago, last lowMem=");
9405 pw.print(now-proc.lastLowMemory);
9406 pw.println(" ms ago");
9407
9408 }
9409 }
9410
9411 if (mProcessCrashTimes.getMap().size() > 0) {
9412 if (needSep) pw.println(" ");
9413 needSep = true;
9414 pw.println(" Time since processes crashed:");
9415 long now = SystemClock.uptimeMillis();
9416 for (Map.Entry<String, SparseArray<Long>> procs
9417 : mProcessCrashTimes.getMap().entrySet()) {
9418 SparseArray<Long> uids = procs.getValue();
9419 final int N = uids.size();
9420 for (int i=0; i<N; i++) {
9421 pw.print(" Process "); pw.print(procs.getKey());
9422 pw.print(" uid "); pw.print(uids.keyAt(i));
9423 pw.print(": last crashed ");
9424 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009425 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009426 }
9427 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009429
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009430 if (mBadProcesses.getMap().size() > 0) {
9431 if (needSep) pw.println(" ");
9432 needSep = true;
9433 pw.println(" Bad processes:");
9434 for (Map.Entry<String, SparseArray<Long>> procs
9435 : mBadProcesses.getMap().entrySet()) {
9436 SparseArray<Long> uids = procs.getValue();
9437 final int N = uids.size();
9438 for (int i=0; i<N; i++) {
9439 pw.print(" Bad process "); pw.print(procs.getKey());
9440 pw.print(" uid "); pw.print(uids.keyAt(i));
9441 pw.print(": crashed at time ");
9442 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009443 }
9444 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009445 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009446
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009447 pw.println(" ");
9448 pw.println(" mHomeProcess: " + mHomeProcess);
9449 pw.println(" mConfiguration: " + mConfiguration);
9450 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9451 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9452 || mOrigWaitForDebugger) {
9453 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9454 + " mDebugTransient=" + mDebugTransient
9455 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9456 }
9457 if (mAlwaysFinishActivities || mController != null) {
9458 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9459 + " mController=" + mController);
9460 }
9461 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009462 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009463 pw.println(" mStartRunning=" + mStartRunning
9464 + " mSystemReady=" + mSystemReady
9465 + " mBooting=" + mBooting
9466 + " mBooted=" + mBooted
9467 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009468 pw.println(" mGoingToSleep=" + mGoingToSleep);
9469 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009470 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009471
9472 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009473 }
9474
9475 /**
9476 * There are three ways to call this:
9477 * - no service specified: dump all the services
9478 * - a flattened component name that matched an existing service was specified as the
9479 * first arg: dump that one service
9480 * - the first arg isn't the flattened component name of an existing service:
9481 * dump all services whose component contains the first arg as a substring
9482 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009483 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9484 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009485 String[] newArgs;
9486 String componentNameString;
9487 ServiceRecord r;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009488 if (opti <= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009489 componentNameString = null;
9490 newArgs = EMPTY_STRING_ARRAY;
9491 r = null;
9492 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009493 componentNameString = args[opti];
9494 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009495 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9496 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009497 newArgs = new String[args.length - opti];
9498 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009499 }
9500
9501 if (r != null) {
9502 dumpService(fd, pw, r, newArgs);
9503 } else {
9504 for (ServiceRecord r1 : mServices.values()) {
9505 if (componentNameString == null
9506 || r1.name.flattenToString().contains(componentNameString)) {
9507 dumpService(fd, pw, r1, newArgs);
9508 }
9509 }
9510 }
9511 }
9512
9513 /**
9514 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9515 * there is a thread associated with the service.
9516 */
9517 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9518 pw.println(" Service " + r.name.flattenToString());
9519 if (r.app != null && r.app.thread != null) {
9520 try {
9521 // flush anything that is already in the PrintWriter since the thread is going
9522 // to write to the file descriptor directly
9523 pw.flush();
9524 r.app.thread.dumpService(fd, r, args);
9525 pw.print("\n");
9526 } catch (RemoteException e) {
9527 pw.println("got a RemoteException while dumping the service");
9528 }
9529 }
9530 }
9531
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009532 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9533 int opti, boolean dumpAll) {
9534 boolean needSep = false;
9535
9536 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009537 if (mRegisteredReceivers.size() > 0) {
9538 pw.println(" ");
9539 pw.println(" Registered Receivers:");
9540 Iterator it = mRegisteredReceivers.values().iterator();
9541 while (it.hasNext()) {
9542 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009543 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009544 r.dump(pw, " ");
9545 }
9546 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009548 pw.println(" ");
9549 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009550 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009551 needSep = true;
9552 }
9553
9554 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9555 || mPendingBroadcast != null) {
9556 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009557 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009558 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009559 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009560 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9561 pw.println(" Broadcast #" + i + ":");
9562 mParallelBroadcasts.get(i).dump(pw, " ");
9563 }
9564 if (mOrderedBroadcasts.size() > 0) {
9565 pw.println(" ");
9566 pw.println(" Active serialized broadcasts:");
9567 }
9568 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9569 pw.println(" Serialized Broadcast #" + i + ":");
9570 mOrderedBroadcasts.get(i).dump(pw, " ");
9571 }
9572 pw.println(" ");
9573 pw.println(" Pending broadcast:");
9574 if (mPendingBroadcast != null) {
9575 mPendingBroadcast.dump(pw, " ");
9576 } else {
9577 pw.println(" (null)");
9578 }
9579 needSep = true;
9580 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009581
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009582 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009583 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009584 pw.println(" Historical broadcasts:");
9585 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9586 BroadcastRecord r = mBroadcastHistory[i];
9587 if (r == null) {
9588 break;
9589 }
9590 pw.println(" Historical Broadcast #" + i + ":");
9591 r.dump(pw, " ");
9592 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009593 needSep = true;
9594 }
9595
9596 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009597 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009598 pw.println(" Sticky broadcasts:");
9599 StringBuilder sb = new StringBuilder(128);
9600 for (Map.Entry<String, ArrayList<Intent>> ent
9601 : mStickyBroadcasts.entrySet()) {
9602 pw.print(" * Sticky action "); pw.print(ent.getKey());
9603 pw.println(":");
9604 ArrayList<Intent> intents = ent.getValue();
9605 final int N = intents.size();
9606 for (int i=0; i<N; i++) {
9607 sb.setLength(0);
9608 sb.append(" Intent: ");
9609 intents.get(i).toShortString(sb, true, false);
9610 pw.println(sb.toString());
9611 Bundle bundle = intents.get(i).getExtras();
9612 if (bundle != null) {
9613 pw.print(" ");
9614 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009615 }
9616 }
9617 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009618 needSep = true;
9619 }
9620
9621 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009622 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009623 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009624 pw.println(" mHandler:");
9625 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009626 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009627 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009628
9629 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009630 }
9631
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009632 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9633 int opti, boolean dumpAll) {
9634 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009635
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009636 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009637 if (mServices.size() > 0) {
9638 pw.println(" Active services:");
9639 Iterator<ServiceRecord> it = mServices.values().iterator();
9640 while (it.hasNext()) {
9641 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009642 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009643 r.dump(pw, " ");
9644 }
9645 needSep = true;
9646 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009648
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009649 if (mPendingServices.size() > 0) {
9650 if (needSep) pw.println(" ");
9651 pw.println(" Pending services:");
9652 for (int i=0; i<mPendingServices.size(); i++) {
9653 ServiceRecord r = mPendingServices.get(i);
9654 pw.print(" * Pending "); pw.println(r);
9655 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009656 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009657 needSep = true;
9658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009659
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009660 if (mRestartingServices.size() > 0) {
9661 if (needSep) pw.println(" ");
9662 pw.println(" Restarting services:");
9663 for (int i=0; i<mRestartingServices.size(); i++) {
9664 ServiceRecord r = mRestartingServices.get(i);
9665 pw.print(" * Restarting "); pw.println(r);
9666 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009667 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009668 needSep = true;
9669 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009670
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009671 if (mStoppingServices.size() > 0) {
9672 if (needSep) pw.println(" ");
9673 pw.println(" Stopping services:");
9674 for (int i=0; i<mStoppingServices.size(); i++) {
9675 ServiceRecord r = mStoppingServices.get(i);
9676 pw.print(" * Stopping "); pw.println(r);
9677 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009678 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009679 needSep = true;
9680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009681
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009682 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009683 if (mServiceConnections.size() > 0) {
9684 if (needSep) pw.println(" ");
9685 pw.println(" Connection bindings to services:");
9686 Iterator<ConnectionRecord> it
9687 = mServiceConnections.values().iterator();
9688 while (it.hasNext()) {
9689 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009690 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009691 r.dump(pw, " ");
9692 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009693 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009694 }
9695 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009696
9697 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009698 }
9699
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009700 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9701 int opti, boolean dumpAll) {
9702 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009703
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009704 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009705 if (mProvidersByClass.size() > 0) {
9706 if (needSep) pw.println(" ");
9707 pw.println(" Published content providers (by class):");
9708 Iterator it = mProvidersByClass.entrySet().iterator();
9709 while (it.hasNext()) {
9710 Map.Entry e = (Map.Entry)it.next();
9711 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009712 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009713 r.dump(pw, " ");
9714 }
9715 needSep = true;
9716 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009717
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009718 if (mProvidersByName.size() > 0) {
9719 pw.println(" ");
9720 pw.println(" Authority to provider mappings:");
9721 Iterator it = mProvidersByName.entrySet().iterator();
9722 while (it.hasNext()) {
9723 Map.Entry e = (Map.Entry)it.next();
9724 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9725 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9726 pw.println(r);
9727 }
9728 needSep = true;
9729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009730 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009731
9732 if (mLaunchingProviders.size() > 0) {
9733 if (needSep) pw.println(" ");
9734 pw.println(" Launching content providers:");
9735 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9736 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9737 pw.println(mLaunchingProviders.get(i));
9738 }
9739 needSep = true;
9740 }
9741
9742 if (mGrantedUriPermissions.size() > 0) {
9743 pw.println();
9744 pw.println("Granted Uri Permissions:");
9745 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9746 int uid = mGrantedUriPermissions.keyAt(i);
9747 HashMap<Uri, UriPermission> perms
9748 = mGrantedUriPermissions.valueAt(i);
9749 pw.print(" * UID "); pw.print(uid);
9750 pw.println(" holds:");
9751 for (UriPermission perm : perms.values()) {
9752 pw.print(" "); pw.println(perm);
9753 perm.dump(pw, " ");
9754 }
9755 }
9756 needSep = true;
9757 }
9758
9759 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009760 }
9761
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009762 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9763 int opti, boolean dumpAll) {
9764 boolean needSep = false;
9765
9766 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009767 if (this.mIntentSenderRecords.size() > 0) {
9768 Iterator<WeakReference<PendingIntentRecord>> it
9769 = mIntentSenderRecords.values().iterator();
9770 while (it.hasNext()) {
9771 WeakReference<PendingIntentRecord> ref = it.next();
9772 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009773 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009774 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009775 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009776 rec.dump(pw, " ");
9777 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009778 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009779 }
9780 }
9781 }
9782 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009783
9784 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009785 }
9786
9787 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009788 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009789 TaskRecord lastTask = null;
9790 for (int i=list.size()-1; i>=0; i--) {
9791 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009792 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009793 if (lastTask != r.task) {
9794 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009795 pw.print(prefix);
9796 pw.print(full ? "* " : " ");
9797 pw.println(lastTask);
9798 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009799 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009800 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009801 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009802 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9803 pw.print(" #"); pw.print(i); pw.print(": ");
9804 pw.println(r);
9805 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009806 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009808 }
9809 }
9810
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009811 private static String buildOomTag(String prefix, String space, int val, int base) {
9812 if (val == base) {
9813 if (space == null) return prefix;
9814 return prefix + " ";
9815 }
9816 return prefix + "+" + Integer.toString(val-base);
9817 }
9818
9819 private static final int dumpProcessList(PrintWriter pw,
9820 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009821 String prefix, String normalLabel, String persistentLabel,
9822 boolean inclOomAdj) {
9823 int numPers = 0;
9824 for (int i=list.size()-1; i>=0; i--) {
9825 ProcessRecord r = (ProcessRecord)list.get(i);
9826 if (false) {
9827 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9828 + " #" + i + ":");
9829 r.dump(pw, prefix + " ");
9830 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009831 String oomAdj;
9832 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009833 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009834 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009835 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9836 } else if (r.setAdj >= HOME_APP_ADJ) {
9837 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9838 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9839 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9840 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9841 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9842 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9843 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9844 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9845 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009846 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009847 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009848 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009849 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009850 } else {
9851 oomAdj = Integer.toString(r.setAdj);
9852 }
9853 String schedGroup;
9854 switch (r.setSchedGroup) {
9855 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9856 schedGroup = "B";
9857 break;
9858 case Process.THREAD_GROUP_DEFAULT:
9859 schedGroup = "F";
9860 break;
9861 default:
9862 schedGroup = Integer.toString(r.setSchedGroup);
9863 break;
9864 }
9865 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009866 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009867 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009868 if (r.adjSource != null || r.adjTarget != null) {
9869 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009870 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009871 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009872 } else {
9873 pw.println(String.format("%s%s #%2d: %s",
9874 prefix, (r.persistent ? persistentLabel : normalLabel),
9875 i, r.toString()));
9876 }
9877 if (r.persistent) {
9878 numPers++;
9879 }
9880 }
9881 return numPers;
9882 }
9883
9884 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9885 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009886 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009887 long uptime = SystemClock.uptimeMillis();
9888 long realtime = SystemClock.elapsedRealtime();
9889
9890 if (isCheckinRequest) {
9891 // short checkin version
9892 pw.println(uptime + "," + realtime);
9893 pw.flush();
9894 } else {
9895 pw.println("Applications Memory Usage (kB):");
9896 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9897 }
9898 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9899 ProcessRecord r = (ProcessRecord)list.get(i);
9900 if (r.thread != null) {
9901 if (!isCheckinRequest) {
9902 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9903 pw.flush();
9904 }
9905 try {
9906 r.thread.asBinder().dump(fd, args);
9907 } catch (RemoteException e) {
9908 if (!isCheckinRequest) {
9909 pw.println("Got RemoteException!");
9910 pw.flush();
9911 }
9912 }
9913 }
9914 }
9915 }
9916
9917 /**
9918 * Searches array of arguments for the specified string
9919 * @param args array of argument strings
9920 * @param value value to search for
9921 * @return true if the value is contained in the array
9922 */
9923 private static boolean scanArgs(String[] args, String value) {
9924 if (args != null) {
9925 for (String arg : args) {
9926 if (value.equals(arg)) {
9927 return true;
9928 }
9929 }
9930 }
9931 return false;
9932 }
9933
Dianne Hackborn75b03852009-06-12 15:43:26 -07009934 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009935 int count = mHistory.size();
9936
9937 // convert the token to an entry in the history.
9938 HistoryRecord r = null;
9939 int index = -1;
9940 for (int i=count-1; i>=0; i--) {
9941 Object o = mHistory.get(i);
9942 if (o == token) {
9943 r = (HistoryRecord)o;
9944 index = i;
9945 break;
9946 }
9947 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009948
9949 return index;
9950 }
9951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009952 private final void killServicesLocked(ProcessRecord app,
9953 boolean allowRestart) {
9954 // Report disconnected services.
9955 if (false) {
9956 // XXX we are letting the client link to the service for
9957 // death notifications.
9958 if (app.services.size() > 0) {
9959 Iterator it = app.services.iterator();
9960 while (it.hasNext()) {
9961 ServiceRecord r = (ServiceRecord)it.next();
9962 if (r.connections.size() > 0) {
9963 Iterator<ConnectionRecord> jt
9964 = r.connections.values().iterator();
9965 while (jt.hasNext()) {
9966 ConnectionRecord c = jt.next();
9967 if (c.binding.client != app) {
9968 try {
9969 //c.conn.connected(r.className, null);
9970 } catch (Exception e) {
9971 // todo: this should be asynchronous!
9972 Log.w(TAG, "Exception thrown disconnected servce "
9973 + r.shortName
9974 + " from app " + app.processName, e);
9975 }
9976 }
9977 }
9978 }
9979 }
9980 }
9981 }
9982
9983 // Clean up any connections this application has to other services.
9984 if (app.connections.size() > 0) {
9985 Iterator<ConnectionRecord> it = app.connections.iterator();
9986 while (it.hasNext()) {
9987 ConnectionRecord r = it.next();
9988 removeConnectionLocked(r, app, null);
9989 }
9990 }
9991 app.connections.clear();
9992
9993 if (app.services.size() != 0) {
9994 // Any services running in the application need to be placed
9995 // back in the pending list.
9996 Iterator it = app.services.iterator();
9997 while (it.hasNext()) {
9998 ServiceRecord sr = (ServiceRecord)it.next();
9999 synchronized (sr.stats.getBatteryStats()) {
10000 sr.stats.stopLaunchedLocked();
10001 }
10002 sr.app = null;
10003 sr.executeNesting = 0;
10004 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010005
10006 boolean hasClients = sr.bindings.size() > 0;
10007 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010008 Iterator<IntentBindRecord> bindings
10009 = sr.bindings.values().iterator();
10010 while (bindings.hasNext()) {
10011 IntentBindRecord b = bindings.next();
10012 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
10013 + ": shouldUnbind=" + b.hasBound);
10014 b.binder = null;
10015 b.requested = b.received = b.hasBound = false;
10016 }
10017 }
10018
10019 if (sr.crashCount >= 2) {
10020 Log.w(TAG, "Service crashed " + sr.crashCount
10021 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010022 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010023 sr.crashCount, sr.shortName, app.pid);
10024 bringDownServiceLocked(sr, true);
10025 } else if (!allowRestart) {
10026 bringDownServiceLocked(sr, true);
10027 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010028 boolean canceled = scheduleServiceRestartLocked(sr, true);
10029
10030 // Should the service remain running? Note that in the
10031 // extreme case of so many attempts to deliver a command
10032 // that it failed, that we also will stop it here.
10033 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10034 if (sr.pendingStarts.size() == 0) {
10035 sr.startRequested = false;
10036 if (!hasClients) {
10037 // Whoops, no reason to restart!
10038 bringDownServiceLocked(sr, true);
10039 }
10040 }
10041 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010042 }
10043 }
10044
10045 if (!allowRestart) {
10046 app.services.clear();
10047 }
10048 }
10049
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010050 // Make sure we have no more records on the stopping list.
10051 int i = mStoppingServices.size();
10052 while (i > 0) {
10053 i--;
10054 ServiceRecord sr = mStoppingServices.get(i);
10055 if (sr.app == app) {
10056 mStoppingServices.remove(i);
10057 }
10058 }
10059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010060 app.executingServices.clear();
10061 }
10062
10063 private final void removeDyingProviderLocked(ProcessRecord proc,
10064 ContentProviderRecord cpr) {
10065 synchronized (cpr) {
10066 cpr.launchingApp = null;
10067 cpr.notifyAll();
10068 }
10069
10070 mProvidersByClass.remove(cpr.info.name);
10071 String names[] = cpr.info.authority.split(";");
10072 for (int j = 0; j < names.length; j++) {
10073 mProvidersByName.remove(names[j]);
10074 }
10075
10076 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10077 while (cit.hasNext()) {
10078 ProcessRecord capp = cit.next();
10079 if (!capp.persistent && capp.thread != null
10080 && capp.pid != 0
10081 && capp.pid != MY_PID) {
10082 Log.i(TAG, "Killing app " + capp.processName
10083 + " (pid " + capp.pid
10084 + ") because provider " + cpr.info.name
10085 + " is in dying process " + proc.processName);
10086 Process.killProcess(capp.pid);
10087 }
10088 }
10089
10090 mLaunchingProviders.remove(cpr);
10091 }
10092
10093 /**
10094 * Main code for cleaning up a process when it has gone away. This is
10095 * called both as a result of the process dying, or directly when stopping
10096 * a process when running in single process mode.
10097 */
10098 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10099 boolean restarting, int index) {
10100 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010101 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010102 }
10103
Dianne Hackborn36124872009-10-08 16:22:03 -070010104 mProcessesToGc.remove(app);
10105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010106 // Dismiss any open dialogs.
10107 if (app.crashDialog != null) {
10108 app.crashDialog.dismiss();
10109 app.crashDialog = null;
10110 }
10111 if (app.anrDialog != null) {
10112 app.anrDialog.dismiss();
10113 app.anrDialog = null;
10114 }
10115 if (app.waitDialog != null) {
10116 app.waitDialog.dismiss();
10117 app.waitDialog = null;
10118 }
10119
10120 app.crashing = false;
10121 app.notResponding = false;
10122
10123 app.resetPackageList();
10124 app.thread = null;
10125 app.forcingToForeground = null;
10126 app.foregroundServices = false;
10127
10128 killServicesLocked(app, true);
10129
10130 boolean restart = false;
10131
10132 int NL = mLaunchingProviders.size();
10133
10134 // Remove published content providers.
10135 if (!app.pubProviders.isEmpty()) {
10136 Iterator it = app.pubProviders.values().iterator();
10137 while (it.hasNext()) {
10138 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10139 cpr.provider = null;
10140 cpr.app = null;
10141
10142 // See if someone is waiting for this provider... in which
10143 // case we don't remove it, but just let it restart.
10144 int i = 0;
10145 if (!app.bad) {
10146 for (; i<NL; i++) {
10147 if (mLaunchingProviders.get(i) == cpr) {
10148 restart = true;
10149 break;
10150 }
10151 }
10152 } else {
10153 i = NL;
10154 }
10155
10156 if (i >= NL) {
10157 removeDyingProviderLocked(app, cpr);
10158 NL = mLaunchingProviders.size();
10159 }
10160 }
10161 app.pubProviders.clear();
10162 }
10163
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010164 // Take care of any launching providers waiting for this process.
10165 if (checkAppInLaunchingProvidersLocked(app, false)) {
10166 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010167 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010169 // Unregister from connected content providers.
10170 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010171 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010172 while (it.hasNext()) {
10173 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10174 cpr.clients.remove(app);
10175 }
10176 app.conProviders.clear();
10177 }
10178
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010179 // At this point there may be remaining entries in mLaunchingProviders
10180 // where we were the only one waiting, so they are no longer of use.
10181 // Look for these and clean up if found.
10182 // XXX Commented out for now. Trying to figure out a way to reproduce
10183 // the actual situation to identify what is actually going on.
10184 if (false) {
10185 for (int i=0; i<NL; i++) {
10186 ContentProviderRecord cpr = (ContentProviderRecord)
10187 mLaunchingProviders.get(i);
10188 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10189 synchronized (cpr) {
10190 cpr.launchingApp = null;
10191 cpr.notifyAll();
10192 }
10193 }
10194 }
10195 }
10196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010197 skipCurrentReceiverLocked(app);
10198
10199 // Unregister any receivers.
10200 if (app.receivers.size() > 0) {
10201 Iterator<ReceiverList> it = app.receivers.iterator();
10202 while (it.hasNext()) {
10203 removeReceiverLocked(it.next());
10204 }
10205 app.receivers.clear();
10206 }
10207
Christopher Tate181fafa2009-05-14 11:12:14 -070010208 // If the app is undergoing backup, tell the backup manager about it
10209 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10210 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10211 try {
10212 IBackupManager bm = IBackupManager.Stub.asInterface(
10213 ServiceManager.getService(Context.BACKUP_SERVICE));
10214 bm.agentDisconnected(app.info.packageName);
10215 } catch (RemoteException e) {
10216 // can't happen; backup manager is local
10217 }
10218 }
10219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010220 // If the caller is restarting this app, then leave it in its
10221 // current lists and let the caller take care of it.
10222 if (restarting) {
10223 return;
10224 }
10225
10226 if (!app.persistent) {
10227 if (DEBUG_PROCESSES) Log.v(TAG,
10228 "Removing non-persistent process during cleanup: " + app);
10229 mProcessNames.remove(app.processName, app.info.uid);
10230 } else if (!app.removed) {
10231 // This app is persistent, so we need to keep its record around.
10232 // If it is not already on the pending app list, add it there
10233 // and start a new process for it.
10234 app.thread = null;
10235 app.forcingToForeground = null;
10236 app.foregroundServices = false;
10237 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10238 mPersistentStartingProcesses.add(app);
10239 restart = true;
10240 }
10241 }
10242 mProcessesOnHold.remove(app);
10243
The Android Open Source Project4df24232009-03-05 14:34:35 -080010244 if (app == mHomeProcess) {
10245 mHomeProcess = null;
10246 }
10247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010248 if (restart) {
10249 // We have components that still need to be running in the
10250 // process, so re-launch it.
10251 mProcessNames.put(app.processName, app.info.uid, app);
10252 startProcessLocked(app, "restart", app.processName);
10253 } else if (app.pid > 0 && app.pid != MY_PID) {
10254 // Goodbye!
10255 synchronized (mPidsSelfLocked) {
10256 mPidsSelfLocked.remove(app.pid);
10257 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10258 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010259 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010260 }
10261 }
10262
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010263 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10264 // Look through the content providers we are waiting to have launched,
10265 // and if any run in this process then either schedule a restart of
10266 // the process or kill the client waiting for it if this process has
10267 // gone bad.
10268 int NL = mLaunchingProviders.size();
10269 boolean restart = false;
10270 for (int i=0; i<NL; i++) {
10271 ContentProviderRecord cpr = (ContentProviderRecord)
10272 mLaunchingProviders.get(i);
10273 if (cpr.launchingApp == app) {
10274 if (!alwaysBad && !app.bad) {
10275 restart = true;
10276 } else {
10277 removeDyingProviderLocked(app, cpr);
10278 NL = mLaunchingProviders.size();
10279 }
10280 }
10281 }
10282 return restart;
10283 }
10284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010285 // =========================================================
10286 // SERVICES
10287 // =========================================================
10288
10289 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10290 ActivityManager.RunningServiceInfo info =
10291 new ActivityManager.RunningServiceInfo();
10292 info.service = r.name;
10293 if (r.app != null) {
10294 info.pid = r.app.pid;
10295 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010296 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010297 info.process = r.processName;
10298 info.foreground = r.isForeground;
10299 info.activeSince = r.createTime;
10300 info.started = r.startRequested;
10301 info.clientCount = r.connections.size();
10302 info.crashCount = r.crashCount;
10303 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010304 if (r.isForeground) {
10305 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10306 }
10307 if (r.startRequested) {
10308 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10309 }
Dan Egnor42471dd2010-01-07 17:25:22 -080010310 if (r.app != null && r.app.pid == MY_PID) {
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010311 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10312 }
10313 if (r.app != null && r.app.persistent) {
10314 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10315 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010316 for (ConnectionRecord conn : r.connections.values()) {
10317 if (conn.clientLabel != 0) {
10318 info.clientPackage = conn.binding.client.info.packageName;
10319 info.clientLabel = conn.clientLabel;
10320 break;
10321 }
10322 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010323 return info;
10324 }
10325
10326 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10327 int flags) {
10328 synchronized (this) {
10329 ArrayList<ActivityManager.RunningServiceInfo> res
10330 = new ArrayList<ActivityManager.RunningServiceInfo>();
10331
10332 if (mServices.size() > 0) {
10333 Iterator<ServiceRecord> it = mServices.values().iterator();
10334 while (it.hasNext() && res.size() < maxNum) {
10335 res.add(makeRunningServiceInfoLocked(it.next()));
10336 }
10337 }
10338
10339 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10340 ServiceRecord r = mRestartingServices.get(i);
10341 ActivityManager.RunningServiceInfo info =
10342 makeRunningServiceInfoLocked(r);
10343 info.restarting = r.nextRestartTime;
10344 res.add(info);
10345 }
10346
10347 return res;
10348 }
10349 }
10350
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010351 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10352 synchronized (this) {
10353 ServiceRecord r = mServices.get(name);
10354 if (r != null) {
10355 for (ConnectionRecord conn : r.connections.values()) {
10356 if (conn.clientIntent != null) {
10357 return conn.clientIntent;
10358 }
10359 }
10360 }
10361 }
10362 return null;
10363 }
10364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010365 private final ServiceRecord findServiceLocked(ComponentName name,
10366 IBinder token) {
10367 ServiceRecord r = mServices.get(name);
10368 return r == token ? r : null;
10369 }
10370
10371 private final class ServiceLookupResult {
10372 final ServiceRecord record;
10373 final String permission;
10374
10375 ServiceLookupResult(ServiceRecord _record, String _permission) {
10376 record = _record;
10377 permission = _permission;
10378 }
10379 };
10380
10381 private ServiceLookupResult findServiceLocked(Intent service,
10382 String resolvedType) {
10383 ServiceRecord r = null;
10384 if (service.getComponent() != null) {
10385 r = mServices.get(service.getComponent());
10386 }
10387 if (r == null) {
10388 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10389 r = mServicesByIntent.get(filter);
10390 }
10391
10392 if (r == null) {
10393 try {
10394 ResolveInfo rInfo =
10395 ActivityThread.getPackageManager().resolveService(
10396 service, resolvedType, 0);
10397 ServiceInfo sInfo =
10398 rInfo != null ? rInfo.serviceInfo : null;
10399 if (sInfo == null) {
10400 return null;
10401 }
10402
10403 ComponentName name = new ComponentName(
10404 sInfo.applicationInfo.packageName, sInfo.name);
10405 r = mServices.get(name);
10406 } catch (RemoteException ex) {
10407 // pm is in same process, this will never happen.
10408 }
10409 }
10410 if (r != null) {
10411 int callingPid = Binder.getCallingPid();
10412 int callingUid = Binder.getCallingUid();
10413 if (checkComponentPermission(r.permission,
10414 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10415 != PackageManager.PERMISSION_GRANTED) {
10416 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10417 + " from pid=" + callingPid
10418 + ", uid=" + callingUid
10419 + " requires " + r.permission);
10420 return new ServiceLookupResult(null, r.permission);
10421 }
10422 return new ServiceLookupResult(r, null);
10423 }
10424 return null;
10425 }
10426
10427 private class ServiceRestarter implements Runnable {
10428 private ServiceRecord mService;
10429
10430 void setService(ServiceRecord service) {
10431 mService = service;
10432 }
10433
10434 public void run() {
10435 synchronized(ActivityManagerService.this) {
10436 performServiceRestartLocked(mService);
10437 }
10438 }
10439 }
10440
10441 private ServiceLookupResult retrieveServiceLocked(Intent service,
10442 String resolvedType, int callingPid, int callingUid) {
10443 ServiceRecord r = null;
10444 if (service.getComponent() != null) {
10445 r = mServices.get(service.getComponent());
10446 }
10447 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10448 r = mServicesByIntent.get(filter);
10449 if (r == null) {
10450 try {
10451 ResolveInfo rInfo =
10452 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010453 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010454 ServiceInfo sInfo =
10455 rInfo != null ? rInfo.serviceInfo : null;
10456 if (sInfo == null) {
10457 Log.w(TAG, "Unable to start service " + service +
10458 ": not found");
10459 return null;
10460 }
10461
10462 ComponentName name = new ComponentName(
10463 sInfo.applicationInfo.packageName, sInfo.name);
10464 r = mServices.get(name);
10465 if (r == null) {
10466 filter = new Intent.FilterComparison(service.cloneFilter());
10467 ServiceRestarter res = new ServiceRestarter();
10468 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10469 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10470 synchronized (stats) {
10471 ss = stats.getServiceStatsLocked(
10472 sInfo.applicationInfo.uid, sInfo.packageName,
10473 sInfo.name);
10474 }
Dianne Hackbornb1c4a2a2010-01-19 15:36:42 -080010475 r = new ServiceRecord(this, ss, name, filter, sInfo, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010476 res.setService(r);
10477 mServices.put(name, r);
10478 mServicesByIntent.put(filter, r);
10479
10480 // Make sure this component isn't in the pending list.
10481 int N = mPendingServices.size();
10482 for (int i=0; i<N; i++) {
10483 ServiceRecord pr = mPendingServices.get(i);
10484 if (pr.name.equals(name)) {
10485 mPendingServices.remove(i);
10486 i--;
10487 N--;
10488 }
10489 }
10490 }
10491 } catch (RemoteException ex) {
10492 // pm is in same process, this will never happen.
10493 }
10494 }
10495 if (r != null) {
10496 if (checkComponentPermission(r.permission,
10497 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10498 != PackageManager.PERMISSION_GRANTED) {
10499 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10500 + " from pid=" + Binder.getCallingPid()
10501 + ", uid=" + Binder.getCallingUid()
10502 + " requires " + r.permission);
10503 return new ServiceLookupResult(null, r.permission);
10504 }
10505 return new ServiceLookupResult(r, null);
10506 }
10507 return null;
10508 }
10509
10510 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10511 long now = SystemClock.uptimeMillis();
10512 if (r.executeNesting == 0 && r.app != null) {
10513 if (r.app.executingServices.size() == 0) {
10514 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10515 msg.obj = r.app;
10516 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10517 }
10518 r.app.executingServices.add(r);
10519 }
10520 r.executeNesting++;
10521 r.executingStart = now;
10522 }
10523
10524 private final void sendServiceArgsLocked(ServiceRecord r,
10525 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010526 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010527 if (N == 0) {
10528 return;
10529 }
10530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010531 int i = 0;
10532 while (i < N) {
10533 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010534 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010535 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010536 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010537 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010538 // If somehow we got a dummy start at the front, then
10539 // just drop it here.
10540 i++;
10541 continue;
10542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010543 bumpServiceExecutingLocked(r);
10544 if (!oomAdjusted) {
10545 oomAdjusted = true;
10546 updateOomAdjLocked(r.app);
10547 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010548 int flags = 0;
10549 if (si.deliveryCount > 0) {
10550 flags |= Service.START_FLAG_RETRY;
10551 }
10552 if (si.doneExecutingCount > 0) {
10553 flags |= Service.START_FLAG_REDELIVERY;
10554 }
10555 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10556 si.deliveredTime = SystemClock.uptimeMillis();
10557 r.deliveredStarts.add(si);
10558 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010559 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010560 } catch (RemoteException e) {
10561 // Remote process gone... we'll let the normal cleanup take
10562 // care of this.
10563 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010564 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010565 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010566 break;
10567 }
10568 }
10569 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010570 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010571 } else {
10572 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010573 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010574 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010575 }
10576 }
10577 }
10578
10579 private final boolean requestServiceBindingLocked(ServiceRecord r,
10580 IntentBindRecord i, boolean rebind) {
10581 if (r.app == null || r.app.thread == null) {
10582 // If service is not currently running, can't yet bind.
10583 return false;
10584 }
10585 if ((!i.requested || rebind) && i.apps.size() > 0) {
10586 try {
10587 bumpServiceExecutingLocked(r);
10588 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10589 + ": shouldUnbind=" + i.hasBound);
10590 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10591 if (!rebind) {
10592 i.requested = true;
10593 }
10594 i.hasBound = true;
10595 i.doRebind = false;
10596 } catch (RemoteException e) {
10597 return false;
10598 }
10599 }
10600 return true;
10601 }
10602
10603 private final void requestServiceBindingsLocked(ServiceRecord r) {
10604 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10605 while (bindings.hasNext()) {
10606 IntentBindRecord i = bindings.next();
10607 if (!requestServiceBindingLocked(r, i, false)) {
10608 break;
10609 }
10610 }
10611 }
10612
10613 private final void realStartServiceLocked(ServiceRecord r,
10614 ProcessRecord app) throws RemoteException {
10615 if (app.thread == null) {
10616 throw new RemoteException();
10617 }
10618
10619 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010620 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010621
10622 app.services.add(r);
10623 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010624 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010625
10626 boolean created = false;
10627 try {
10628 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10629 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010630 mStringBuilder.setLength(0);
10631 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010632 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010633 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010634 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010635 synchronized (r.stats.getBatteryStats()) {
10636 r.stats.startLaunchedLocked();
10637 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010638 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010639 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010640 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010641 created = true;
10642 } finally {
10643 if (!created) {
10644 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010645 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010646 }
10647 }
10648
10649 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010650
10651 // If the service is in the started state, and there are no
10652 // pending arguments, then fake up one so its onStartCommand() will
10653 // be called.
10654 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10655 r.lastStartId++;
10656 if (r.lastStartId < 1) {
10657 r.lastStartId = 1;
10658 }
10659 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10660 }
10661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010662 sendServiceArgsLocked(r, true);
10663 }
10664
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010665 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10666 boolean allowCancel) {
10667 boolean canceled = false;
10668
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010669 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010670 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010671 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010672
10673 // Any delivered but not yet finished starts should be put back
10674 // on the pending list.
10675 final int N = r.deliveredStarts.size();
10676 if (N > 0) {
10677 for (int i=N-1; i>=0; i--) {
10678 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10679 if (si.intent == null) {
10680 // We'll generate this again if needed.
10681 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10682 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10683 r.pendingStarts.add(0, si);
10684 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10685 dur *= 2;
10686 if (minDuration < dur) minDuration = dur;
10687 if (resetTime < dur) resetTime = dur;
10688 } else {
10689 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10690 + r.name);
10691 canceled = true;
10692 }
10693 }
10694 r.deliveredStarts.clear();
10695 }
10696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010697 r.totalRestartCount++;
10698 if (r.restartDelay == 0) {
10699 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010700 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010701 } else {
10702 // If it has been a "reasonably long time" since the service
10703 // was started, then reset our restart duration back to
10704 // the beginning, so we don't infinitely increase the duration
10705 // on a service that just occasionally gets killed (which is
10706 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010707 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010708 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010709 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010710 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010711 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010712 if (r.restartDelay < minDuration) {
10713 r.restartDelay = minDuration;
10714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010715 }
10716 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010717
10718 r.nextRestartTime = now + r.restartDelay;
10719
10720 // Make sure that we don't end up restarting a bunch of services
10721 // all at the same time.
10722 boolean repeat;
10723 do {
10724 repeat = false;
10725 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10726 ServiceRecord r2 = mRestartingServices.get(i);
10727 if (r2 != r && r.nextRestartTime
10728 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10729 && r.nextRestartTime
10730 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10731 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10732 r.restartDelay = r.nextRestartTime - now;
10733 repeat = true;
10734 break;
10735 }
10736 }
10737 } while (repeat);
10738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010739 if (!mRestartingServices.contains(r)) {
10740 mRestartingServices.add(r);
10741 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010742
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010743 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010745 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010746 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010747 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10748 Log.w(TAG, "Scheduling restart of crashed service "
10749 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010750 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010751 r.shortName, r.restartDelay);
10752
10753 Message msg = Message.obtain();
10754 msg.what = SERVICE_ERROR_MSG;
10755 msg.obj = r;
10756 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010757
10758 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010759 }
10760
10761 final void performServiceRestartLocked(ServiceRecord r) {
10762 if (!mRestartingServices.contains(r)) {
10763 return;
10764 }
10765 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10766 }
10767
10768 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10769 if (r.restartDelay == 0) {
10770 return false;
10771 }
10772 r.resetRestartCounter();
10773 mRestartingServices.remove(r);
10774 mHandler.removeCallbacks(r.restarter);
10775 return true;
10776 }
10777
10778 private final boolean bringUpServiceLocked(ServiceRecord r,
10779 int intentFlags, boolean whileRestarting) {
10780 //Log.i(TAG, "Bring up service:");
10781 //r.dump(" ");
10782
Dianne Hackborn36124872009-10-08 16:22:03 -070010783 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010784 sendServiceArgsLocked(r, false);
10785 return true;
10786 }
10787
10788 if (!whileRestarting && r.restartDelay > 0) {
10789 // If waiting for a restart, then do nothing.
10790 return true;
10791 }
10792
10793 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10794 + " " + r.intent);
10795
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010796 // We are now bringing the service up, so no longer in the
10797 // restarting state.
10798 mRestartingServices.remove(r);
10799
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010800 final String appName = r.processName;
10801 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10802 if (app != null && app.thread != null) {
10803 try {
10804 realStartServiceLocked(r, app);
10805 return true;
10806 } catch (RemoteException e) {
10807 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10808 }
10809
10810 // If a dead object exception was thrown -- fall through to
10811 // restart the application.
10812 }
10813
Dianne Hackborn36124872009-10-08 16:22:03 -070010814 // Not running -- get it started, and enqueue this service record
10815 // to be executed when the app comes up.
10816 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10817 "service", r.name, false) == null) {
10818 Log.w(TAG, "Unable to launch app "
10819 + r.appInfo.packageName + "/"
10820 + r.appInfo.uid + " for service "
10821 + r.intent.getIntent() + ": process is bad");
10822 bringDownServiceLocked(r, true);
10823 return false;
10824 }
10825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010826 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010827 mPendingServices.add(r);
10828 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010830 return true;
10831 }
10832
10833 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10834 //Log.i(TAG, "Bring down service:");
10835 //r.dump(" ");
10836
10837 // Does it still need to run?
10838 if (!force && r.startRequested) {
10839 return;
10840 }
10841 if (r.connections.size() > 0) {
10842 if (!force) {
10843 // XXX should probably keep a count of the number of auto-create
10844 // connections directly in the service.
10845 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10846 while (it.hasNext()) {
10847 ConnectionRecord cr = it.next();
10848 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10849 return;
10850 }
10851 }
10852 }
10853
10854 // Report to all of the connections that the service is no longer
10855 // available.
10856 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10857 while (it.hasNext()) {
10858 ConnectionRecord c = it.next();
10859 try {
10860 // todo: shouldn't be a synchronous call!
10861 c.conn.connected(r.name, null);
10862 } catch (Exception e) {
10863 Log.w(TAG, "Failure disconnecting service " + r.name +
10864 " to connection " + c.conn.asBinder() +
10865 " (in " + c.binding.client.processName + ")", e);
10866 }
10867 }
10868 }
10869
10870 // Tell the service that it has been unbound.
10871 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10872 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10873 while (it.hasNext()) {
10874 IntentBindRecord ibr = it.next();
10875 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10876 + ": hasBound=" + ibr.hasBound);
10877 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10878 try {
10879 bumpServiceExecutingLocked(r);
10880 updateOomAdjLocked(r.app);
10881 ibr.hasBound = false;
10882 r.app.thread.scheduleUnbindService(r,
10883 ibr.intent.getIntent());
10884 } catch (Exception e) {
10885 Log.w(TAG, "Exception when unbinding service "
10886 + r.shortName, e);
10887 serviceDoneExecutingLocked(r, true);
10888 }
10889 }
10890 }
10891 }
10892
10893 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10894 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010895 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010896 System.identityHashCode(r), r.shortName,
10897 (r.app != null) ? r.app.pid : -1);
10898
10899 mServices.remove(r.name);
10900 mServicesByIntent.remove(r.intent);
10901 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10902 r.totalRestartCount = 0;
10903 unscheduleServiceRestartLocked(r);
10904
10905 // Also make sure it is not on the pending list.
10906 int N = mPendingServices.size();
10907 for (int i=0; i<N; i++) {
10908 if (mPendingServices.get(i) == r) {
10909 mPendingServices.remove(i);
10910 if (DEBUG_SERVICE) Log.v(
10911 TAG, "Removed pending service: " + r.shortName);
10912 i--;
10913 N--;
10914 }
10915 }
10916
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010917 r.cancelNotification();
10918 r.isForeground = false;
10919 r.foregroundId = 0;
10920 r.foregroundNoti = null;
10921
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010922 // Clear start entries.
10923 r.deliveredStarts.clear();
10924 r.pendingStarts.clear();
10925
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010926 if (r.app != null) {
10927 synchronized (r.stats.getBatteryStats()) {
10928 r.stats.stopLaunchedLocked();
10929 }
10930 r.app.services.remove(r);
10931 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010932 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010933 if (DEBUG_SERVICE) Log.v(TAG,
10934 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010935 bumpServiceExecutingLocked(r);
10936 mStoppingServices.add(r);
10937 updateOomAdjLocked(r.app);
10938 r.app.thread.scheduleStopService(r);
10939 } catch (Exception e) {
10940 Log.w(TAG, "Exception when stopping service "
10941 + r.shortName, e);
10942 serviceDoneExecutingLocked(r, true);
10943 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010944 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010945 } else {
10946 if (DEBUG_SERVICE) Log.v(
10947 TAG, "Removed service that has no process: " + r.shortName);
10948 }
10949 } else {
10950 if (DEBUG_SERVICE) Log.v(
10951 TAG, "Removed service that is not running: " + r.shortName);
10952 }
10953 }
10954
10955 ComponentName startServiceLocked(IApplicationThread caller,
10956 Intent service, String resolvedType,
10957 int callingPid, int callingUid) {
10958 synchronized(this) {
10959 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10960 + " type=" + resolvedType + " args=" + service.getExtras());
10961
10962 if (caller != null) {
10963 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10964 if (callerApp == null) {
10965 throw new SecurityException(
10966 "Unable to find app for caller " + caller
10967 + " (pid=" + Binder.getCallingPid()
10968 + ") when starting service " + service);
10969 }
10970 }
10971
10972 ServiceLookupResult res =
10973 retrieveServiceLocked(service, resolvedType,
10974 callingPid, callingUid);
10975 if (res == null) {
10976 return null;
10977 }
10978 if (res.record == null) {
10979 return new ComponentName("!", res.permission != null
10980 ? res.permission : "private to package");
10981 }
10982 ServiceRecord r = res.record;
10983 if (unscheduleServiceRestartLocked(r)) {
10984 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10985 + r.shortName);
10986 }
10987 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010988 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010989 r.lastStartId++;
10990 if (r.lastStartId < 1) {
10991 r.lastStartId = 1;
10992 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010993 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010994 r.lastActivity = SystemClock.uptimeMillis();
10995 synchronized (r.stats.getBatteryStats()) {
10996 r.stats.startRunningLocked();
10997 }
10998 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10999 return new ComponentName("!", "Service process is bad");
11000 }
11001 return r.name;
11002 }
11003 }
11004
11005 public ComponentName startService(IApplicationThread caller, Intent service,
11006 String resolvedType) {
11007 // Refuse possible leaked file descriptors
11008 if (service != null && service.hasFileDescriptors() == true) {
11009 throw new IllegalArgumentException("File descriptors passed in Intent");
11010 }
11011
11012 synchronized(this) {
11013 final int callingPid = Binder.getCallingPid();
11014 final int callingUid = Binder.getCallingUid();
11015 final long origId = Binder.clearCallingIdentity();
11016 ComponentName res = startServiceLocked(caller, service,
11017 resolvedType, callingPid, callingUid);
11018 Binder.restoreCallingIdentity(origId);
11019 return res;
11020 }
11021 }
11022
11023 ComponentName startServiceInPackage(int uid,
11024 Intent service, String resolvedType) {
11025 synchronized(this) {
11026 final long origId = Binder.clearCallingIdentity();
11027 ComponentName res = startServiceLocked(null, service,
11028 resolvedType, -1, uid);
11029 Binder.restoreCallingIdentity(origId);
11030 return res;
11031 }
11032 }
11033
11034 public int stopService(IApplicationThread caller, Intent service,
11035 String resolvedType) {
11036 // Refuse possible leaked file descriptors
11037 if (service != null && service.hasFileDescriptors() == true) {
11038 throw new IllegalArgumentException("File descriptors passed in Intent");
11039 }
11040
11041 synchronized(this) {
11042 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11043 + " type=" + resolvedType);
11044
11045 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11046 if (caller != null && callerApp == null) {
11047 throw new SecurityException(
11048 "Unable to find app for caller " + caller
11049 + " (pid=" + Binder.getCallingPid()
11050 + ") when stopping service " + service);
11051 }
11052
11053 // If this service is active, make sure it is stopped.
11054 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11055 if (r != null) {
11056 if (r.record != null) {
11057 synchronized (r.record.stats.getBatteryStats()) {
11058 r.record.stats.stopRunningLocked();
11059 }
11060 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011061 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011062 final long origId = Binder.clearCallingIdentity();
11063 bringDownServiceLocked(r.record, false);
11064 Binder.restoreCallingIdentity(origId);
11065 return 1;
11066 }
11067 return -1;
11068 }
11069 }
11070
11071 return 0;
11072 }
11073
11074 public IBinder peekService(Intent service, String resolvedType) {
11075 // Refuse possible leaked file descriptors
11076 if (service != null && service.hasFileDescriptors() == true) {
11077 throw new IllegalArgumentException("File descriptors passed in Intent");
11078 }
11079
11080 IBinder ret = null;
11081
11082 synchronized(this) {
11083 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11084
11085 if (r != null) {
11086 // r.record is null if findServiceLocked() failed the caller permission check
11087 if (r.record == null) {
11088 throw new SecurityException(
11089 "Permission Denial: Accessing service " + r.record.name
11090 + " from pid=" + Binder.getCallingPid()
11091 + ", uid=" + Binder.getCallingUid()
11092 + " requires " + r.permission);
11093 }
11094 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11095 if (ib != null) {
11096 ret = ib.binder;
11097 }
11098 }
11099 }
11100
11101 return ret;
11102 }
11103
11104 public boolean stopServiceToken(ComponentName className, IBinder token,
11105 int startId) {
11106 synchronized(this) {
11107 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11108 + " " + token + " startId=" + startId);
11109 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011110 if (r != null) {
11111 if (startId >= 0) {
11112 // Asked to only stop if done with all work. Note that
11113 // to avoid leaks, we will take this as dropping all
11114 // start items up to and including this one.
11115 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11116 if (si != null) {
11117 while (r.deliveredStarts.size() > 0) {
11118 if (r.deliveredStarts.remove(0) == si) {
11119 break;
11120 }
11121 }
11122 }
11123
11124 if (r.lastStartId != startId) {
11125 return false;
11126 }
11127
11128 if (r.deliveredStarts.size() > 0) {
11129 Log.w(TAG, "stopServiceToken startId " + startId
11130 + " is last, but have " + r.deliveredStarts.size()
11131 + " remaining args");
11132 }
11133 }
11134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011135 synchronized (r.stats.getBatteryStats()) {
11136 r.stats.stopRunningLocked();
11137 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011138 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011139 }
11140 final long origId = Binder.clearCallingIdentity();
11141 bringDownServiceLocked(r, false);
11142 Binder.restoreCallingIdentity(origId);
11143 return true;
11144 }
11145 }
11146 return false;
11147 }
11148
11149 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011150 int id, Notification notification, boolean removeNotification) {
11151 final long origId = Binder.clearCallingIdentity();
11152 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011153 synchronized(this) {
11154 ServiceRecord r = findServiceLocked(className, token);
11155 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011156 if (id != 0) {
11157 if (notification == null) {
11158 throw new IllegalArgumentException("null notification");
11159 }
11160 if (r.foregroundId != id) {
11161 r.cancelNotification();
11162 r.foregroundId = id;
11163 }
11164 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11165 r.foregroundNoti = notification;
11166 r.isForeground = true;
11167 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011168 if (r.app != null) {
11169 updateServiceForegroundLocked(r.app, true);
11170 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011171 } else {
11172 if (r.isForeground) {
11173 r.isForeground = false;
11174 if (r.app != null) {
11175 updateServiceForegroundLocked(r.app, true);
11176 }
11177 }
11178 if (removeNotification) {
11179 r.cancelNotification();
11180 r.foregroundId = 0;
11181 r.foregroundNoti = null;
11182 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011183 }
11184 }
11185 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011186 } finally {
11187 Binder.restoreCallingIdentity(origId);
11188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011189 }
11190
11191 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11192 boolean anyForeground = false;
11193 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11194 if (sr.isForeground) {
11195 anyForeground = true;
11196 break;
11197 }
11198 }
11199 if (anyForeground != proc.foregroundServices) {
11200 proc.foregroundServices = anyForeground;
11201 if (oomAdj) {
11202 updateOomAdjLocked();
11203 }
11204 }
11205 }
11206
11207 public int bindService(IApplicationThread caller, IBinder token,
11208 Intent service, String resolvedType,
11209 IServiceConnection connection, int flags) {
11210 // Refuse possible leaked file descriptors
11211 if (service != null && service.hasFileDescriptors() == true) {
11212 throw new IllegalArgumentException("File descriptors passed in Intent");
11213 }
11214
11215 synchronized(this) {
11216 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11217 + " type=" + resolvedType + " conn=" + connection.asBinder()
11218 + " flags=0x" + Integer.toHexString(flags));
11219 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11220 if (callerApp == null) {
11221 throw new SecurityException(
11222 "Unable to find app for caller " + caller
11223 + " (pid=" + Binder.getCallingPid()
11224 + ") when binding service " + service);
11225 }
11226
11227 HistoryRecord activity = null;
11228 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011229 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011230 if (aindex < 0) {
11231 Log.w(TAG, "Binding with unknown activity: " + token);
11232 return 0;
11233 }
11234 activity = (HistoryRecord)mHistory.get(aindex);
11235 }
11236
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011237 int clientLabel = 0;
11238 PendingIntent clientIntent = null;
11239
11240 if (callerApp.info.uid == Process.SYSTEM_UID) {
11241 // Hacky kind of thing -- allow system stuff to tell us
11242 // what they are, so we can report this elsewhere for
11243 // others to know why certain services are running.
11244 try {
11245 clientIntent = (PendingIntent)service.getParcelableExtra(
11246 Intent.EXTRA_CLIENT_INTENT);
11247 } catch (RuntimeException e) {
11248 }
11249 if (clientIntent != null) {
11250 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11251 if (clientLabel != 0) {
11252 // There are no useful extras in the intent, trash them.
11253 // System code calling with this stuff just needs to know
11254 // this will happen.
11255 service = service.cloneFilter();
11256 }
11257 }
11258 }
11259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011260 ServiceLookupResult res =
11261 retrieveServiceLocked(service, resolvedType,
11262 Binder.getCallingPid(), Binder.getCallingUid());
11263 if (res == null) {
11264 return 0;
11265 }
11266 if (res.record == null) {
11267 return -1;
11268 }
11269 ServiceRecord s = res.record;
11270
11271 final long origId = Binder.clearCallingIdentity();
11272
11273 if (unscheduleServiceRestartLocked(s)) {
11274 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11275 + s.shortName);
11276 }
11277
11278 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11279 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011280 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011281
11282 IBinder binder = connection.asBinder();
11283 s.connections.put(binder, c);
11284 b.connections.add(c);
11285 if (activity != null) {
11286 if (activity.connections == null) {
11287 activity.connections = new HashSet<ConnectionRecord>();
11288 }
11289 activity.connections.add(c);
11290 }
11291 b.client.connections.add(c);
11292 mServiceConnections.put(binder, c);
11293
11294 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11295 s.lastActivity = SystemClock.uptimeMillis();
11296 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11297 return 0;
11298 }
11299 }
11300
11301 if (s.app != null) {
11302 // This could have made the service more important.
11303 updateOomAdjLocked(s.app);
11304 }
11305
11306 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11307 + ": received=" + b.intent.received
11308 + " apps=" + b.intent.apps.size()
11309 + " doRebind=" + b.intent.doRebind);
11310
11311 if (s.app != null && b.intent.received) {
11312 // Service is already running, so we can immediately
11313 // publish the connection.
11314 try {
11315 c.conn.connected(s.name, b.intent.binder);
11316 } catch (Exception e) {
11317 Log.w(TAG, "Failure sending service " + s.shortName
11318 + " to connection " + c.conn.asBinder()
11319 + " (in " + c.binding.client.processName + ")", e);
11320 }
11321
11322 // If this is the first app connected back to this binding,
11323 // and the service had previously asked to be told when
11324 // rebound, then do so.
11325 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11326 requestServiceBindingLocked(s, b.intent, true);
11327 }
11328 } else if (!b.intent.requested) {
11329 requestServiceBindingLocked(s, b.intent, false);
11330 }
11331
11332 Binder.restoreCallingIdentity(origId);
11333 }
11334
11335 return 1;
11336 }
11337
11338 private void removeConnectionLocked(
11339 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11340 IBinder binder = c.conn.asBinder();
11341 AppBindRecord b = c.binding;
11342 ServiceRecord s = b.service;
11343 s.connections.remove(binder);
11344 b.connections.remove(c);
11345 if (c.activity != null && c.activity != skipAct) {
11346 if (c.activity.connections != null) {
11347 c.activity.connections.remove(c);
11348 }
11349 }
11350 if (b.client != skipApp) {
11351 b.client.connections.remove(c);
11352 }
11353 mServiceConnections.remove(binder);
11354
11355 if (b.connections.size() == 0) {
11356 b.intent.apps.remove(b.client);
11357 }
11358
11359 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11360 + ": shouldUnbind=" + b.intent.hasBound);
11361 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11362 && b.intent.hasBound) {
11363 try {
11364 bumpServiceExecutingLocked(s);
11365 updateOomAdjLocked(s.app);
11366 b.intent.hasBound = false;
11367 // Assume the client doesn't want to know about a rebind;
11368 // we will deal with that later if it asks for one.
11369 b.intent.doRebind = false;
11370 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11371 } catch (Exception e) {
11372 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11373 serviceDoneExecutingLocked(s, true);
11374 }
11375 }
11376
11377 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11378 bringDownServiceLocked(s, false);
11379 }
11380 }
11381
11382 public boolean unbindService(IServiceConnection connection) {
11383 synchronized (this) {
11384 IBinder binder = connection.asBinder();
11385 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11386 ConnectionRecord r = mServiceConnections.get(binder);
11387 if (r == null) {
11388 Log.w(TAG, "Unbind failed: could not find connection for "
11389 + connection.asBinder());
11390 return false;
11391 }
11392
11393 final long origId = Binder.clearCallingIdentity();
11394
11395 removeConnectionLocked(r, null, null);
11396
11397 if (r.binding.service.app != null) {
11398 // This could have made the service less important.
11399 updateOomAdjLocked(r.binding.service.app);
11400 }
11401
11402 Binder.restoreCallingIdentity(origId);
11403 }
11404
11405 return true;
11406 }
11407
11408 public void publishService(IBinder token, Intent intent, IBinder service) {
11409 // Refuse possible leaked file descriptors
11410 if (intent != null && intent.hasFileDescriptors() == true) {
11411 throw new IllegalArgumentException("File descriptors passed in Intent");
11412 }
11413
11414 synchronized(this) {
11415 if (!(token instanceof ServiceRecord)) {
11416 throw new IllegalArgumentException("Invalid service token");
11417 }
11418 ServiceRecord r = (ServiceRecord)token;
11419
11420 final long origId = Binder.clearCallingIdentity();
11421
11422 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11423 + " " + intent + ": " + service);
11424 if (r != null) {
11425 Intent.FilterComparison filter
11426 = new Intent.FilterComparison(intent);
11427 IntentBindRecord b = r.bindings.get(filter);
11428 if (b != null && !b.received) {
11429 b.binder = service;
11430 b.requested = true;
11431 b.received = true;
11432 if (r.connections.size() > 0) {
11433 Iterator<ConnectionRecord> it
11434 = r.connections.values().iterator();
11435 while (it.hasNext()) {
11436 ConnectionRecord c = it.next();
11437 if (!filter.equals(c.binding.intent.intent)) {
11438 if (DEBUG_SERVICE) Log.v(
11439 TAG, "Not publishing to: " + c);
11440 if (DEBUG_SERVICE) Log.v(
11441 TAG, "Bound intent: " + c.binding.intent.intent);
11442 if (DEBUG_SERVICE) Log.v(
11443 TAG, "Published intent: " + intent);
11444 continue;
11445 }
11446 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11447 try {
11448 c.conn.connected(r.name, service);
11449 } catch (Exception e) {
11450 Log.w(TAG, "Failure sending service " + r.name +
11451 " to connection " + c.conn.asBinder() +
11452 " (in " + c.binding.client.processName + ")", e);
11453 }
11454 }
11455 }
11456 }
11457
11458 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11459
11460 Binder.restoreCallingIdentity(origId);
11461 }
11462 }
11463 }
11464
11465 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11466 // Refuse possible leaked file descriptors
11467 if (intent != null && intent.hasFileDescriptors() == true) {
11468 throw new IllegalArgumentException("File descriptors passed in Intent");
11469 }
11470
11471 synchronized(this) {
11472 if (!(token instanceof ServiceRecord)) {
11473 throw new IllegalArgumentException("Invalid service token");
11474 }
11475 ServiceRecord r = (ServiceRecord)token;
11476
11477 final long origId = Binder.clearCallingIdentity();
11478
11479 if (r != null) {
11480 Intent.FilterComparison filter
11481 = new Intent.FilterComparison(intent);
11482 IntentBindRecord b = r.bindings.get(filter);
11483 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11484 + " at " + b + ": apps="
11485 + (b != null ? b.apps.size() : 0));
11486 if (b != null) {
11487 if (b.apps.size() > 0) {
11488 // Applications have already bound since the last
11489 // unbind, so just rebind right here.
11490 requestServiceBindingLocked(r, b, true);
11491 } else {
11492 // Note to tell the service the next time there is
11493 // a new client.
11494 b.doRebind = true;
11495 }
11496 }
11497
11498 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11499
11500 Binder.restoreCallingIdentity(origId);
11501 }
11502 }
11503 }
11504
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011505 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011506 synchronized(this) {
11507 if (!(token instanceof ServiceRecord)) {
11508 throw new IllegalArgumentException("Invalid service token");
11509 }
11510 ServiceRecord r = (ServiceRecord)token;
11511 boolean inStopping = mStoppingServices.contains(token);
11512 if (r != null) {
11513 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11514 + ": nesting=" + r.executeNesting
11515 + ", inStopping=" + inStopping);
11516 if (r != token) {
11517 Log.w(TAG, "Done executing service " + r.name
11518 + " with incorrect token: given " + token
11519 + ", expected " + r);
11520 return;
11521 }
11522
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011523 if (type == 1) {
11524 // This is a call from a service start... take care of
11525 // book-keeping.
11526 r.callStart = true;
11527 switch (res) {
11528 case Service.START_STICKY_COMPATIBILITY:
11529 case Service.START_STICKY: {
11530 // We are done with the associated start arguments.
11531 r.findDeliveredStart(startId, true);
11532 // Don't stop if killed.
11533 r.stopIfKilled = false;
11534 break;
11535 }
11536 case Service.START_NOT_STICKY: {
11537 // We are done with the associated start arguments.
11538 r.findDeliveredStart(startId, true);
11539 if (r.lastStartId == startId) {
11540 // There is no more work, and this service
11541 // doesn't want to hang around if killed.
11542 r.stopIfKilled = true;
11543 }
11544 break;
11545 }
11546 case Service.START_REDELIVER_INTENT: {
11547 // We'll keep this item until they explicitly
11548 // call stop for it, but keep track of the fact
11549 // that it was delivered.
11550 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11551 if (si != null) {
11552 si.deliveryCount = 0;
11553 si.doneExecutingCount++;
11554 // Don't stop if killed.
11555 r.stopIfKilled = true;
11556 }
11557 break;
11558 }
11559 default:
11560 throw new IllegalArgumentException(
11561 "Unknown service start result: " + res);
11562 }
11563 if (res == Service.START_STICKY_COMPATIBILITY) {
11564 r.callStart = false;
11565 }
11566 }
11567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011568 final long origId = Binder.clearCallingIdentity();
11569 serviceDoneExecutingLocked(r, inStopping);
11570 Binder.restoreCallingIdentity(origId);
11571 } else {
11572 Log.w(TAG, "Done executing unknown service " + r.name
11573 + " with token " + token);
11574 }
11575 }
11576 }
11577
11578 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11579 r.executeNesting--;
11580 if (r.executeNesting <= 0 && r.app != null) {
11581 r.app.executingServices.remove(r);
11582 if (r.app.executingServices.size() == 0) {
11583 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11584 }
11585 if (inStopping) {
11586 mStoppingServices.remove(r);
11587 }
11588 updateOomAdjLocked(r.app);
11589 }
11590 }
11591
11592 void serviceTimeout(ProcessRecord proc) {
11593 synchronized(this) {
11594 if (proc.executingServices.size() == 0 || proc.thread == null) {
11595 return;
11596 }
11597 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11598 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11599 ServiceRecord timeout = null;
11600 long nextTime = 0;
11601 while (it.hasNext()) {
11602 ServiceRecord sr = it.next();
11603 if (sr.executingStart < maxTime) {
11604 timeout = sr;
11605 break;
11606 }
11607 if (sr.executingStart > nextTime) {
11608 nextTime = sr.executingStart;
11609 }
11610 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011611 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011612 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnor42471dd2010-01-07 17:25:22 -080011613 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011614 } else {
11615 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11616 msg.obj = proc;
11617 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11618 }
11619 }
11620 }
11621
11622 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011623 // BACKUP AND RESTORE
11624 // =========================================================
11625
11626 // Cause the target app to be launched if necessary and its backup agent
11627 // instantiated. The backup agent will invoke backupAgentCreated() on the
11628 // activity manager to announce its creation.
11629 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11630 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11631 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11632
11633 synchronized(this) {
11634 // !!! TODO: currently no check here that we're already bound
11635 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11636 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11637 synchronized (stats) {
11638 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11639 }
11640
11641 BackupRecord r = new BackupRecord(ss, app, backupMode);
11642 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11643 // startProcessLocked() returns existing proc's record if it's already running
11644 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011645 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011646 if (proc == null) {
11647 Log.e(TAG, "Unable to start backup agent process " + r);
11648 return false;
11649 }
11650
11651 r.app = proc;
11652 mBackupTarget = r;
11653 mBackupAppName = app.packageName;
11654
Christopher Tate6fa95972009-06-05 18:43:55 -070011655 // Try not to kill the process during backup
11656 updateOomAdjLocked(proc);
11657
Christopher Tate181fafa2009-05-14 11:12:14 -070011658 // If the process is already attached, schedule the creation of the backup agent now.
11659 // If it is not yet live, this will be done when it attaches to the framework.
11660 if (proc.thread != null) {
11661 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11662 try {
11663 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11664 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011665 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011666 }
11667 } else {
11668 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11669 }
11670 // Invariants: at this point, the target app process exists and the application
11671 // is either already running or in the process of coming up. mBackupTarget and
11672 // mBackupAppName describe the app, so that when it binds back to the AM we
11673 // know that it's scheduled for a backup-agent operation.
11674 }
11675
11676 return true;
11677 }
11678
11679 // A backup agent has just come up
11680 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11681 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11682 + " = " + agent);
11683
11684 synchronized(this) {
11685 if (!agentPackageName.equals(mBackupAppName)) {
11686 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11687 return;
11688 }
11689
Christopher Tate043dadc2009-06-02 16:11:00 -070011690 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011691 try {
11692 IBackupManager bm = IBackupManager.Stub.asInterface(
11693 ServiceManager.getService(Context.BACKUP_SERVICE));
11694 bm.agentConnected(agentPackageName, agent);
11695 } catch (RemoteException e) {
11696 // can't happen; the backup manager service is local
11697 } catch (Exception e) {
11698 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11699 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011700 } finally {
11701 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011702 }
11703 }
11704 }
11705
11706 // done with this agent
11707 public void unbindBackupAgent(ApplicationInfo appInfo) {
11708 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011709 if (appInfo == null) {
11710 Log.w(TAG, "unbind backup agent for null app");
11711 return;
11712 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011713
11714 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011715 if (mBackupAppName == null) {
11716 Log.w(TAG, "Unbinding backup agent with no active backup");
11717 return;
11718 }
11719
Christopher Tate181fafa2009-05-14 11:12:14 -070011720 if (!mBackupAppName.equals(appInfo.packageName)) {
11721 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11722 return;
11723 }
11724
Christopher Tate6fa95972009-06-05 18:43:55 -070011725 ProcessRecord proc = mBackupTarget.app;
11726 mBackupTarget = null;
11727 mBackupAppName = null;
11728
11729 // Not backing this app up any more; reset its OOM adjustment
11730 updateOomAdjLocked(proc);
11731
Christopher Tatec7b31e32009-06-10 15:49:30 -070011732 // If the app crashed during backup, 'thread' will be null here
11733 if (proc.thread != null) {
11734 try {
11735 proc.thread.scheduleDestroyBackupAgent(appInfo);
11736 } catch (Exception e) {
11737 Log.e(TAG, "Exception when unbinding backup agent:");
11738 e.printStackTrace();
11739 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011740 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011741 }
11742 }
11743 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011744 // BROADCASTS
11745 // =========================================================
11746
11747 private final List getStickies(String action, IntentFilter filter,
11748 List cur) {
11749 final ContentResolver resolver = mContext.getContentResolver();
11750 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11751 if (list == null) {
11752 return cur;
11753 }
11754 int N = list.size();
11755 for (int i=0; i<N; i++) {
11756 Intent intent = list.get(i);
11757 if (filter.match(resolver, intent, true, TAG) >= 0) {
11758 if (cur == null) {
11759 cur = new ArrayList<Intent>();
11760 }
11761 cur.add(intent);
11762 }
11763 }
11764 return cur;
11765 }
11766
11767 private final void scheduleBroadcastsLocked() {
11768 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11769 + mBroadcastsScheduled);
11770
11771 if (mBroadcastsScheduled) {
11772 return;
11773 }
11774 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11775 mBroadcastsScheduled = true;
11776 }
11777
11778 public Intent registerReceiver(IApplicationThread caller,
11779 IIntentReceiver receiver, IntentFilter filter, String permission) {
11780 synchronized(this) {
11781 ProcessRecord callerApp = null;
11782 if (caller != null) {
11783 callerApp = getRecordForAppLocked(caller);
11784 if (callerApp == null) {
11785 throw new SecurityException(
11786 "Unable to find app for caller " + caller
11787 + " (pid=" + Binder.getCallingPid()
11788 + ") when registering receiver " + receiver);
11789 }
11790 }
11791
11792 List allSticky = null;
11793
11794 // Look for any matching sticky broadcasts...
11795 Iterator actions = filter.actionsIterator();
11796 if (actions != null) {
11797 while (actions.hasNext()) {
11798 String action = (String)actions.next();
11799 allSticky = getStickies(action, filter, allSticky);
11800 }
11801 } else {
11802 allSticky = getStickies(null, filter, allSticky);
11803 }
11804
11805 // The first sticky in the list is returned directly back to
11806 // the client.
11807 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11808
11809 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11810 + ": " + sticky);
11811
11812 if (receiver == null) {
11813 return sticky;
11814 }
11815
11816 ReceiverList rl
11817 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11818 if (rl == null) {
11819 rl = new ReceiverList(this, callerApp,
11820 Binder.getCallingPid(),
11821 Binder.getCallingUid(), receiver);
11822 if (rl.app != null) {
11823 rl.app.receivers.add(rl);
11824 } else {
11825 try {
11826 receiver.asBinder().linkToDeath(rl, 0);
11827 } catch (RemoteException e) {
11828 return sticky;
11829 }
11830 rl.linkedToDeath = true;
11831 }
11832 mRegisteredReceivers.put(receiver.asBinder(), rl);
11833 }
11834 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11835 rl.add(bf);
11836 if (!bf.debugCheck()) {
11837 Log.w(TAG, "==> For Dynamic broadast");
11838 }
11839 mReceiverResolver.addFilter(bf);
11840
11841 // Enqueue broadcasts for all existing stickies that match
11842 // this filter.
11843 if (allSticky != null) {
11844 ArrayList receivers = new ArrayList();
11845 receivers.add(bf);
11846
11847 int N = allSticky.size();
11848 for (int i=0; i<N; i++) {
11849 Intent intent = (Intent)allSticky.get(i);
11850 BroadcastRecord r = new BroadcastRecord(intent, null,
11851 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011852 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011853 if (mParallelBroadcasts.size() == 0) {
11854 scheduleBroadcastsLocked();
11855 }
11856 mParallelBroadcasts.add(r);
11857 }
11858 }
11859
11860 return sticky;
11861 }
11862 }
11863
11864 public void unregisterReceiver(IIntentReceiver receiver) {
11865 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11866
11867 boolean doNext = false;
11868
11869 synchronized(this) {
11870 ReceiverList rl
11871 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11872 if (rl != null) {
11873 if (rl.curBroadcast != null) {
11874 BroadcastRecord r = rl.curBroadcast;
11875 doNext = finishReceiverLocked(
11876 receiver.asBinder(), r.resultCode, r.resultData,
11877 r.resultExtras, r.resultAbort, true);
11878 }
11879
11880 if (rl.app != null) {
11881 rl.app.receivers.remove(rl);
11882 }
11883 removeReceiverLocked(rl);
11884 if (rl.linkedToDeath) {
11885 rl.linkedToDeath = false;
11886 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11887 }
11888 }
11889 }
11890
11891 if (!doNext) {
11892 return;
11893 }
11894
11895 final long origId = Binder.clearCallingIdentity();
11896 processNextBroadcast(false);
11897 trimApplications();
11898 Binder.restoreCallingIdentity(origId);
11899 }
11900
11901 void removeReceiverLocked(ReceiverList rl) {
11902 mRegisteredReceivers.remove(rl.receiver.asBinder());
11903 int N = rl.size();
11904 for (int i=0; i<N; i++) {
11905 mReceiverResolver.removeFilter(rl.get(i));
11906 }
11907 }
11908
11909 private final int broadcastIntentLocked(ProcessRecord callerApp,
11910 String callerPackage, Intent intent, String resolvedType,
11911 IIntentReceiver resultTo, int resultCode, String resultData,
11912 Bundle map, String requiredPermission,
11913 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11914 intent = new Intent(intent);
11915
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011916 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011917 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11918 + " ordered=" + ordered);
11919 if ((resultTo != null) && !ordered) {
11920 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11921 }
11922
11923 // Handle special intents: if this broadcast is from the package
11924 // manager about a package being removed, we need to remove all of
11925 // its activities from the history stack.
11926 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11927 intent.getAction());
11928 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11929 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11930 || uidRemoved) {
11931 if (checkComponentPermission(
11932 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11933 callingPid, callingUid, -1)
11934 == PackageManager.PERMISSION_GRANTED) {
11935 if (uidRemoved) {
11936 final Bundle intentExtras = intent.getExtras();
11937 final int uid = intentExtras != null
11938 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11939 if (uid >= 0) {
11940 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11941 synchronized (bs) {
11942 bs.removeUidStatsLocked(uid);
11943 }
11944 }
11945 } else {
11946 Uri data = intent.getData();
11947 String ssp;
11948 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11949 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -080011950 forceStopPackageLocked(ssp,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011951 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011952 AttributeCache ac = AttributeCache.instance();
11953 if (ac != null) {
11954 ac.removePackage(ssp);
11955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011956 }
11957 }
11958 }
11959 } else {
11960 String msg = "Permission Denial: " + intent.getAction()
11961 + " broadcast from " + callerPackage + " (pid=" + callingPid
11962 + ", uid=" + callingUid + ")"
11963 + " requires "
11964 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11965 Log.w(TAG, msg);
11966 throw new SecurityException(msg);
11967 }
11968 }
11969
11970 /*
11971 * If this is the time zone changed action, queue up a message that will reset the timezone
11972 * of all currently running processes. This message will get queued up before the broadcast
11973 * happens.
11974 */
11975 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11976 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11977 }
11978
Dianne Hackborn854060af2009-07-09 18:14:31 -070011979 /*
11980 * Prevent non-system code (defined here to be non-persistent
11981 * processes) from sending protected broadcasts.
11982 */
11983 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11984 || callingUid == Process.SHELL_UID || callingUid == 0) {
11985 // Always okay.
11986 } else if (callerApp == null || !callerApp.persistent) {
11987 try {
11988 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11989 intent.getAction())) {
11990 String msg = "Permission Denial: not allowed to send broadcast "
11991 + intent.getAction() + " from pid="
11992 + callingPid + ", uid=" + callingUid;
11993 Log.w(TAG, msg);
11994 throw new SecurityException(msg);
11995 }
11996 } catch (RemoteException e) {
11997 Log.w(TAG, "Remote exception", e);
11998 return BROADCAST_SUCCESS;
11999 }
12000 }
12001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012002 // Add to the sticky list if requested.
12003 if (sticky) {
12004 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
12005 callingPid, callingUid)
12006 != PackageManager.PERMISSION_GRANTED) {
12007 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
12008 + callingPid + ", uid=" + callingUid
12009 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12010 Log.w(TAG, msg);
12011 throw new SecurityException(msg);
12012 }
12013 if (requiredPermission != null) {
12014 Log.w(TAG, "Can't broadcast sticky intent " + intent
12015 + " and enforce permission " + requiredPermission);
12016 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
12017 }
12018 if (intent.getComponent() != null) {
12019 throw new SecurityException(
12020 "Sticky broadcasts can't target a specific component");
12021 }
12022 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12023 if (list == null) {
12024 list = new ArrayList<Intent>();
12025 mStickyBroadcasts.put(intent.getAction(), list);
12026 }
12027 int N = list.size();
12028 int i;
12029 for (i=0; i<N; i++) {
12030 if (intent.filterEquals(list.get(i))) {
12031 // This sticky already exists, replace it.
12032 list.set(i, new Intent(intent));
12033 break;
12034 }
12035 }
12036 if (i >= N) {
12037 list.add(new Intent(intent));
12038 }
12039 }
12040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012041 // Figure out who all will receive this broadcast.
12042 List receivers = null;
12043 List<BroadcastFilter> registeredReceivers = null;
12044 try {
12045 if (intent.getComponent() != null) {
12046 // Broadcast is going to one specific receiver class...
12047 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012048 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012049 if (ai != null) {
12050 receivers = new ArrayList();
12051 ResolveInfo ri = new ResolveInfo();
12052 ri.activityInfo = ai;
12053 receivers.add(ri);
12054 }
12055 } else {
12056 // Need to resolve the intent to interested receivers...
12057 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12058 == 0) {
12059 receivers =
12060 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012061 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012062 }
Mihai Preda074edef2009-05-18 17:13:31 +020012063 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012064 }
12065 } catch (RemoteException ex) {
12066 // pm is in same process, this will never happen.
12067 }
12068
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012069 final boolean replacePending =
12070 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12071
12072 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12073 + " replacePending=" + replacePending);
12074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012075 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12076 if (!ordered && NR > 0) {
12077 // If we are not serializing this broadcast, then send the
12078 // registered receivers separately so they don't wait for the
12079 // components to be launched.
12080 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12081 callerPackage, callingPid, callingUid, requiredPermission,
12082 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012083 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012084 if (DEBUG_BROADCAST) Log.v(
12085 TAG, "Enqueueing parallel broadcast " + r
12086 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012087 boolean replaced = false;
12088 if (replacePending) {
12089 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12090 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12091 if (DEBUG_BROADCAST) Log.v(TAG,
12092 "***** DROPPING PARALLEL: " + intent);
12093 mParallelBroadcasts.set(i, r);
12094 replaced = true;
12095 break;
12096 }
12097 }
12098 }
12099 if (!replaced) {
12100 mParallelBroadcasts.add(r);
12101 scheduleBroadcastsLocked();
12102 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012103 registeredReceivers = null;
12104 NR = 0;
12105 }
12106
12107 // Merge into one list.
12108 int ir = 0;
12109 if (receivers != null) {
12110 // A special case for PACKAGE_ADDED: do not allow the package
12111 // being added to see this broadcast. This prevents them from
12112 // using this as a back door to get run as soon as they are
12113 // installed. Maybe in the future we want to have a special install
12114 // broadcast or such for apps, but we'd like to deliberately make
12115 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070012116 boolean skip = false;
12117 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070012118 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070012119 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
12120 skip = true;
12121 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12122 skip = true;
12123 }
12124 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012125 ? intent.getData().getSchemeSpecificPart()
12126 : null;
12127 if (skipPackage != null && receivers != null) {
12128 int NT = receivers.size();
12129 for (int it=0; it<NT; it++) {
12130 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12131 if (curt.activityInfo.packageName.equals(skipPackage)) {
12132 receivers.remove(it);
12133 it--;
12134 NT--;
12135 }
12136 }
12137 }
12138
12139 int NT = receivers != null ? receivers.size() : 0;
12140 int it = 0;
12141 ResolveInfo curt = null;
12142 BroadcastFilter curr = null;
12143 while (it < NT && ir < NR) {
12144 if (curt == null) {
12145 curt = (ResolveInfo)receivers.get(it);
12146 }
12147 if (curr == null) {
12148 curr = registeredReceivers.get(ir);
12149 }
12150 if (curr.getPriority() >= curt.priority) {
12151 // Insert this broadcast record into the final list.
12152 receivers.add(it, curr);
12153 ir++;
12154 curr = null;
12155 it++;
12156 NT++;
12157 } else {
12158 // Skip to the next ResolveInfo in the final list.
12159 it++;
12160 curt = null;
12161 }
12162 }
12163 }
12164 while (ir < NR) {
12165 if (receivers == null) {
12166 receivers = new ArrayList();
12167 }
12168 receivers.add(registeredReceivers.get(ir));
12169 ir++;
12170 }
12171
12172 if ((receivers != null && receivers.size() > 0)
12173 || resultTo != null) {
12174 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12175 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012176 receivers, resultTo, resultCode, resultData, map, ordered,
12177 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012178 if (DEBUG_BROADCAST) Log.v(
12179 TAG, "Enqueueing ordered broadcast " + r
12180 + ": prev had " + mOrderedBroadcasts.size());
12181 if (DEBUG_BROADCAST) {
12182 int seq = r.intent.getIntExtra("seq", -1);
12183 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12184 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012185 boolean replaced = false;
12186 if (replacePending) {
12187 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12188 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12189 if (DEBUG_BROADCAST) Log.v(TAG,
12190 "***** DROPPING ORDERED: " + intent);
12191 mOrderedBroadcasts.set(i, r);
12192 replaced = true;
12193 break;
12194 }
12195 }
12196 }
12197 if (!replaced) {
12198 mOrderedBroadcasts.add(r);
12199 scheduleBroadcastsLocked();
12200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012201 }
12202
12203 return BROADCAST_SUCCESS;
12204 }
12205
12206 public final int broadcastIntent(IApplicationThread caller,
12207 Intent intent, String resolvedType, IIntentReceiver resultTo,
12208 int resultCode, String resultData, Bundle map,
12209 String requiredPermission, boolean serialized, boolean sticky) {
12210 // Refuse possible leaked file descriptors
12211 if (intent != null && intent.hasFileDescriptors() == true) {
12212 throw new IllegalArgumentException("File descriptors passed in Intent");
12213 }
12214
12215 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012216 int flags = intent.getFlags();
12217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012218 if (!mSystemReady) {
12219 // if the caller really truly claims to know what they're doing, go
12220 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012221 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12222 intent = new Intent(intent);
12223 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12224 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12225 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12226 + " before boot completion");
12227 throw new IllegalStateException("Cannot broadcast before boot completed");
12228 }
12229 }
12230
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012231 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12232 throw new IllegalArgumentException(
12233 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12234 }
12235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012236 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12237 final int callingPid = Binder.getCallingPid();
12238 final int callingUid = Binder.getCallingUid();
12239 final long origId = Binder.clearCallingIdentity();
12240 int res = broadcastIntentLocked(callerApp,
12241 callerApp != null ? callerApp.info.packageName : null,
12242 intent, resolvedType, resultTo,
12243 resultCode, resultData, map, requiredPermission, serialized,
12244 sticky, callingPid, callingUid);
12245 Binder.restoreCallingIdentity(origId);
12246 return res;
12247 }
12248 }
12249
12250 int broadcastIntentInPackage(String packageName, int uid,
12251 Intent intent, String resolvedType, IIntentReceiver resultTo,
12252 int resultCode, String resultData, Bundle map,
12253 String requiredPermission, boolean serialized, boolean sticky) {
12254 synchronized(this) {
12255 final long origId = Binder.clearCallingIdentity();
12256 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12257 resultTo, resultCode, resultData, map, requiredPermission,
12258 serialized, sticky, -1, uid);
12259 Binder.restoreCallingIdentity(origId);
12260 return res;
12261 }
12262 }
12263
12264 public final void unbroadcastIntent(IApplicationThread caller,
12265 Intent intent) {
12266 // Refuse possible leaked file descriptors
12267 if (intent != null && intent.hasFileDescriptors() == true) {
12268 throw new IllegalArgumentException("File descriptors passed in Intent");
12269 }
12270
12271 synchronized(this) {
12272 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12273 != PackageManager.PERMISSION_GRANTED) {
12274 String msg = "Permission Denial: unbroadcastIntent() from pid="
12275 + Binder.getCallingPid()
12276 + ", uid=" + Binder.getCallingUid()
12277 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12278 Log.w(TAG, msg);
12279 throw new SecurityException(msg);
12280 }
12281 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12282 if (list != null) {
12283 int N = list.size();
12284 int i;
12285 for (i=0; i<N; i++) {
12286 if (intent.filterEquals(list.get(i))) {
12287 list.remove(i);
12288 break;
12289 }
12290 }
12291 }
12292 }
12293 }
12294
12295 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12296 String resultData, Bundle resultExtras, boolean resultAbort,
12297 boolean explicit) {
12298 if (mOrderedBroadcasts.size() == 0) {
12299 if (explicit) {
12300 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12301 }
12302 return false;
12303 }
12304 BroadcastRecord r = mOrderedBroadcasts.get(0);
12305 if (r.receiver == null) {
12306 if (explicit) {
12307 Log.w(TAG, "finishReceiver called but none active");
12308 }
12309 return false;
12310 }
12311 if (r.receiver != receiver) {
12312 Log.w(TAG, "finishReceiver called but active receiver is different");
12313 return false;
12314 }
12315 int state = r.state;
12316 r.state = r.IDLE;
12317 if (state == r.IDLE) {
12318 if (explicit) {
12319 Log.w(TAG, "finishReceiver called but state is IDLE");
12320 }
12321 }
12322 r.receiver = null;
12323 r.intent.setComponent(null);
12324 if (r.curApp != null) {
12325 r.curApp.curReceiver = null;
12326 }
12327 if (r.curFilter != null) {
12328 r.curFilter.receiverList.curBroadcast = null;
12329 }
12330 r.curFilter = null;
12331 r.curApp = null;
12332 r.curComponent = null;
12333 r.curReceiver = null;
12334 mPendingBroadcast = null;
12335
12336 r.resultCode = resultCode;
12337 r.resultData = resultData;
12338 r.resultExtras = resultExtras;
12339 r.resultAbort = resultAbort;
12340
12341 // We will process the next receiver right now if this is finishing
12342 // an app receiver (which is always asynchronous) or after we have
12343 // come back from calling a receiver.
12344 return state == BroadcastRecord.APP_RECEIVE
12345 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12346 }
12347
12348 public void finishReceiver(IBinder who, int resultCode, String resultData,
12349 Bundle resultExtras, boolean resultAbort) {
12350 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12351
12352 // Refuse possible leaked file descriptors
12353 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12354 throw new IllegalArgumentException("File descriptors passed in Bundle");
12355 }
12356
12357 boolean doNext;
12358
12359 final long origId = Binder.clearCallingIdentity();
12360
12361 synchronized(this) {
12362 doNext = finishReceiverLocked(
12363 who, resultCode, resultData, resultExtras, resultAbort, true);
12364 }
12365
12366 if (doNext) {
12367 processNextBroadcast(false);
12368 }
12369 trimApplications();
12370
12371 Binder.restoreCallingIdentity(origId);
12372 }
12373
12374 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12375 if (r.nextReceiver > 0) {
12376 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12377 if (curReceiver instanceof BroadcastFilter) {
12378 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012379 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012380 System.identityHashCode(r),
12381 r.intent.getAction(),
12382 r.nextReceiver - 1,
12383 System.identityHashCode(bf));
12384 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012385 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012386 System.identityHashCode(r),
12387 r.intent.getAction(),
12388 r.nextReceiver - 1,
12389 ((ResolveInfo)curReceiver).toString());
12390 }
12391 } else {
12392 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12393 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012394 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012395 System.identityHashCode(r),
12396 r.intent.getAction(),
12397 r.nextReceiver,
12398 "NONE");
12399 }
12400 }
12401
12402 private final void broadcastTimeout() {
12403 synchronized (this) {
12404 if (mOrderedBroadcasts.size() == 0) {
12405 return;
12406 }
12407 long now = SystemClock.uptimeMillis();
12408 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012409 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012410 if (DEBUG_BROADCAST) Log.v(TAG,
12411 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012412 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012413 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012414 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012415 return;
12416 }
12417
12418 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012419 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012420 r.anrCount++;
12421
12422 // Current receiver has passed its expiration date.
12423 if (r.nextReceiver <= 0) {
12424 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12425 return;
12426 }
12427
12428 ProcessRecord app = null;
12429
12430 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12431 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12432 logBroadcastReceiverDiscard(r);
12433 if (curReceiver instanceof BroadcastFilter) {
12434 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12435 if (bf.receiverList.pid != 0
12436 && bf.receiverList.pid != MY_PID) {
12437 synchronized (this.mPidsSelfLocked) {
12438 app = this.mPidsSelfLocked.get(
12439 bf.receiverList.pid);
12440 }
12441 }
12442 } else {
12443 app = r.curApp;
12444 }
12445
12446 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012447 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012448 }
12449
12450 if (mPendingBroadcast == r) {
12451 mPendingBroadcast = null;
12452 }
12453
12454 // Move on to the next receiver.
12455 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12456 r.resultExtras, r.resultAbort, true);
12457 scheduleBroadcastsLocked();
12458 }
12459 }
12460
12461 private final void processCurBroadcastLocked(BroadcastRecord r,
12462 ProcessRecord app) throws RemoteException {
12463 if (app.thread == null) {
12464 throw new RemoteException();
12465 }
12466 r.receiver = app.thread.asBinder();
12467 r.curApp = app;
12468 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012469 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012470
12471 // Tell the application to launch this receiver.
12472 r.intent.setComponent(r.curComponent);
12473
12474 boolean started = false;
12475 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012476 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012477 "Delivering to component " + r.curComponent
12478 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012479 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012480 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12481 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12482 started = true;
12483 } finally {
12484 if (!started) {
12485 r.receiver = null;
12486 r.curApp = null;
12487 app.curReceiver = null;
12488 }
12489 }
12490
12491 }
12492
12493 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012494 Intent intent, int resultCode, String data, Bundle extras,
12495 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012496 if (app != null && app.thread != null) {
12497 // If we have an app thread, do the call through that so it is
12498 // correctly ordered with other one-way calls.
12499 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012500 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012501 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012502 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012503 }
12504 }
12505
12506 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12507 BroadcastFilter filter, boolean ordered) {
12508 boolean skip = false;
12509 if (filter.requiredPermission != null) {
12510 int perm = checkComponentPermission(filter.requiredPermission,
12511 r.callingPid, r.callingUid, -1);
12512 if (perm != PackageManager.PERMISSION_GRANTED) {
12513 Log.w(TAG, "Permission Denial: broadcasting "
12514 + r.intent.toString()
12515 + " from " + r.callerPackage + " (pid="
12516 + r.callingPid + ", uid=" + r.callingUid + ")"
12517 + " requires " + filter.requiredPermission
12518 + " due to registered receiver " + filter);
12519 skip = true;
12520 }
12521 }
12522 if (r.requiredPermission != null) {
12523 int perm = checkComponentPermission(r.requiredPermission,
12524 filter.receiverList.pid, filter.receiverList.uid, -1);
12525 if (perm != PackageManager.PERMISSION_GRANTED) {
12526 Log.w(TAG, "Permission Denial: receiving "
12527 + r.intent.toString()
12528 + " to " + filter.receiverList.app
12529 + " (pid=" + filter.receiverList.pid
12530 + ", uid=" + filter.receiverList.uid + ")"
12531 + " requires " + r.requiredPermission
12532 + " due to sender " + r.callerPackage
12533 + " (uid " + r.callingUid + ")");
12534 skip = true;
12535 }
12536 }
12537
12538 if (!skip) {
12539 // If this is not being sent as an ordered broadcast, then we
12540 // don't want to touch the fields that keep track of the current
12541 // state of ordered broadcasts.
12542 if (ordered) {
12543 r.receiver = filter.receiverList.receiver.asBinder();
12544 r.curFilter = filter;
12545 filter.receiverList.curBroadcast = r;
12546 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012547 if (filter.receiverList.app != null) {
12548 // Bump hosting application to no longer be in background
12549 // scheduling class. Note that we can't do that if there
12550 // isn't an app... but we can only be in that case for
12551 // things that directly call the IActivityManager API, which
12552 // are already core system stuff so don't matter for this.
12553 r.curApp = filter.receiverList.app;
12554 filter.receiverList.app.curReceiver = r;
12555 updateOomAdjLocked();
12556 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012557 }
12558 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012559 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012560 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012561 Log.i(TAG, "Delivering to " + filter.receiverList.app
12562 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012563 }
12564 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12565 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012566 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012567 if (ordered) {
12568 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12569 }
12570 } catch (RemoteException e) {
12571 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12572 if (ordered) {
12573 r.receiver = null;
12574 r.curFilter = null;
12575 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012576 if (filter.receiverList.app != null) {
12577 filter.receiverList.app.curReceiver = null;
12578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012579 }
12580 }
12581 }
12582 }
12583
Dianne Hackborn12527f92009-11-11 17:39:50 -080012584 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12585 if (r.callingUid < 0) {
12586 // This was from a registerReceiver() call; ignore it.
12587 return;
12588 }
12589 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12590 MAX_BROADCAST_HISTORY-1);
12591 r.finishTime = SystemClock.uptimeMillis();
12592 mBroadcastHistory[0] = r;
12593 }
12594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012595 private final void processNextBroadcast(boolean fromMsg) {
12596 synchronized(this) {
12597 BroadcastRecord r;
12598
12599 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12600 + mParallelBroadcasts.size() + " broadcasts, "
12601 + mOrderedBroadcasts.size() + " serialized broadcasts");
12602
12603 updateCpuStats();
12604
12605 if (fromMsg) {
12606 mBroadcastsScheduled = false;
12607 }
12608
12609 // First, deliver any non-serialized broadcasts right away.
12610 while (mParallelBroadcasts.size() > 0) {
12611 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012612 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012613 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012614 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12615 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012616 for (int i=0; i<N; i++) {
12617 Object target = r.receivers.get(i);
12618 if (DEBUG_BROADCAST) Log.v(TAG,
12619 "Delivering non-serialized to registered "
12620 + target + ": " + r);
12621 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12622 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012623 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012624 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12625 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012626 }
12627
12628 // Now take care of the next serialized one...
12629
12630 // If we are waiting for a process to come up to handle the next
12631 // broadcast, then do nothing at this point. Just in case, we
12632 // check that the process we're waiting for still exists.
12633 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012634 if (DEBUG_BROADCAST_LIGHT) {
12635 Log.v(TAG, "processNextBroadcast: waiting for "
12636 + mPendingBroadcast.curApp);
12637 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012638
12639 boolean isDead;
12640 synchronized (mPidsSelfLocked) {
12641 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12642 }
12643 if (!isDead) {
12644 // It's still alive, so keep waiting
12645 return;
12646 } else {
12647 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12648 + " died before responding to broadcast");
12649 mPendingBroadcast = null;
12650 }
12651 }
12652
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012653 boolean looped = false;
12654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012655 do {
12656 if (mOrderedBroadcasts.size() == 0) {
12657 // No more broadcasts pending, so all done!
12658 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012659 if (looped) {
12660 // If we had finished the last ordered broadcast, then
12661 // make sure all processes have correct oom and sched
12662 // adjustments.
12663 updateOomAdjLocked();
12664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012665 return;
12666 }
12667 r = mOrderedBroadcasts.get(0);
12668 boolean forceReceive = false;
12669
12670 // Ensure that even if something goes awry with the timeout
12671 // detection, we catch "hung" broadcasts here, discard them,
12672 // and continue to make progress.
12673 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12674 long now = SystemClock.uptimeMillis();
12675 if (r.dispatchTime > 0) {
12676 if ((numReceivers > 0) &&
12677 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12678 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12679 + " now=" + now
12680 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012681 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012682 + " intent=" + r.intent
12683 + " numReceivers=" + numReceivers
12684 + " nextReceiver=" + r.nextReceiver
12685 + " state=" + r.state);
12686 broadcastTimeout(); // forcibly finish this broadcast
12687 forceReceive = true;
12688 r.state = BroadcastRecord.IDLE;
12689 }
12690 }
12691
12692 if (r.state != BroadcastRecord.IDLE) {
12693 if (DEBUG_BROADCAST) Log.d(TAG,
12694 "processNextBroadcast() called when not idle (state="
12695 + r.state + ")");
12696 return;
12697 }
12698
12699 if (r.receivers == null || r.nextReceiver >= numReceivers
12700 || r.resultAbort || forceReceive) {
12701 // No more receivers for this broadcast! Send the final
12702 // result if requested...
12703 if (r.resultTo != null) {
12704 try {
12705 if (DEBUG_BROADCAST) {
12706 int seq = r.intent.getIntExtra("seq", -1);
12707 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12708 + " seq=" + seq + " app=" + r.callerApp);
12709 }
12710 performReceive(r.callerApp, r.resultTo,
12711 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012712 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012713 } catch (RemoteException e) {
12714 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12715 }
12716 }
12717
12718 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12719 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12720
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012721 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12722 + r);
12723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012724 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012725 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012726 mOrderedBroadcasts.remove(0);
12727 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012728 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012729 continue;
12730 }
12731 } while (r == null);
12732
12733 // Get the next receiver...
12734 int recIdx = r.nextReceiver++;
12735
12736 // Keep track of when this receiver started, and make sure there
12737 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012738 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012739 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012740 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012741
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012742 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12743 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012744 if (DEBUG_BROADCAST) Log.v(TAG,
12745 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012746 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012747 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012748 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012749 }
12750
12751 Object nextReceiver = r.receivers.get(recIdx);
12752 if (nextReceiver instanceof BroadcastFilter) {
12753 // Simple case: this is a registered receiver who gets
12754 // a direct call.
12755 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12756 if (DEBUG_BROADCAST) Log.v(TAG,
12757 "Delivering serialized to registered "
12758 + filter + ": " + r);
12759 deliverToRegisteredReceiver(r, filter, r.ordered);
12760 if (r.receiver == null || !r.ordered) {
12761 // The receiver has already finished, so schedule to
12762 // process the next one.
12763 r.state = BroadcastRecord.IDLE;
12764 scheduleBroadcastsLocked();
12765 }
12766 return;
12767 }
12768
12769 // Hard case: need to instantiate the receiver, possibly
12770 // starting its application process to host it.
12771
12772 ResolveInfo info =
12773 (ResolveInfo)nextReceiver;
12774
12775 boolean skip = false;
12776 int perm = checkComponentPermission(info.activityInfo.permission,
12777 r.callingPid, r.callingUid,
12778 info.activityInfo.exported
12779 ? -1 : info.activityInfo.applicationInfo.uid);
12780 if (perm != PackageManager.PERMISSION_GRANTED) {
12781 Log.w(TAG, "Permission Denial: broadcasting "
12782 + r.intent.toString()
12783 + " from " + r.callerPackage + " (pid=" + r.callingPid
12784 + ", uid=" + r.callingUid + ")"
12785 + " requires " + info.activityInfo.permission
12786 + " due to receiver " + info.activityInfo.packageName
12787 + "/" + info.activityInfo.name);
12788 skip = true;
12789 }
12790 if (r.callingUid != Process.SYSTEM_UID &&
12791 r.requiredPermission != null) {
12792 try {
12793 perm = ActivityThread.getPackageManager().
12794 checkPermission(r.requiredPermission,
12795 info.activityInfo.applicationInfo.packageName);
12796 } catch (RemoteException e) {
12797 perm = PackageManager.PERMISSION_DENIED;
12798 }
12799 if (perm != PackageManager.PERMISSION_GRANTED) {
12800 Log.w(TAG, "Permission Denial: receiving "
12801 + r.intent + " to "
12802 + info.activityInfo.applicationInfo.packageName
12803 + " requires " + r.requiredPermission
12804 + " due to sender " + r.callerPackage
12805 + " (uid " + r.callingUid + ")");
12806 skip = true;
12807 }
12808 }
12809 if (r.curApp != null && r.curApp.crashing) {
12810 // If the target process is crashing, just skip it.
12811 skip = true;
12812 }
12813
12814 if (skip) {
12815 r.receiver = null;
12816 r.curFilter = null;
12817 r.state = BroadcastRecord.IDLE;
12818 scheduleBroadcastsLocked();
12819 return;
12820 }
12821
12822 r.state = BroadcastRecord.APP_RECEIVE;
12823 String targetProcess = info.activityInfo.processName;
12824 r.curComponent = new ComponentName(
12825 info.activityInfo.applicationInfo.packageName,
12826 info.activityInfo.name);
12827 r.curReceiver = info.activityInfo;
12828
12829 // Is this receiver's application already running?
12830 ProcessRecord app = getProcessRecordLocked(targetProcess,
12831 info.activityInfo.applicationInfo.uid);
12832 if (app != null && app.thread != null) {
12833 try {
12834 processCurBroadcastLocked(r, app);
12835 return;
12836 } catch (RemoteException e) {
12837 Log.w(TAG, "Exception when sending broadcast to "
12838 + r.curComponent, e);
12839 }
12840
12841 // If a dead object exception was thrown -- fall through to
12842 // restart the application.
12843 }
12844
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012845 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012846 if ((r.curApp=startProcessLocked(targetProcess,
12847 info.activityInfo.applicationInfo, true,
12848 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012849 "broadcast", r.curComponent,
12850 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12851 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012852 // Ah, this recipient is unavailable. Finish it if necessary,
12853 // and mark the broadcast record as ready for the next.
12854 Log.w(TAG, "Unable to launch app "
12855 + info.activityInfo.applicationInfo.packageName + "/"
12856 + info.activityInfo.applicationInfo.uid + " for broadcast "
12857 + r.intent + ": process is bad");
12858 logBroadcastReceiverDiscard(r);
12859 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12860 r.resultExtras, r.resultAbort, true);
12861 scheduleBroadcastsLocked();
12862 r.state = BroadcastRecord.IDLE;
12863 return;
12864 }
12865
12866 mPendingBroadcast = r;
12867 }
12868 }
12869
12870 // =========================================================
12871 // INSTRUMENTATION
12872 // =========================================================
12873
12874 public boolean startInstrumentation(ComponentName className,
12875 String profileFile, int flags, Bundle arguments,
12876 IInstrumentationWatcher watcher) {
12877 // Refuse possible leaked file descriptors
12878 if (arguments != null && arguments.hasFileDescriptors()) {
12879 throw new IllegalArgumentException("File descriptors passed in Bundle");
12880 }
12881
12882 synchronized(this) {
12883 InstrumentationInfo ii = null;
12884 ApplicationInfo ai = null;
12885 try {
12886 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012887 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012888 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012889 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012890 } catch (PackageManager.NameNotFoundException e) {
12891 }
12892 if (ii == null) {
12893 reportStartInstrumentationFailure(watcher, className,
12894 "Unable to find instrumentation info for: " + className);
12895 return false;
12896 }
12897 if (ai == null) {
12898 reportStartInstrumentationFailure(watcher, className,
12899 "Unable to find instrumentation target package: " + ii.targetPackage);
12900 return false;
12901 }
12902
12903 int match = mContext.getPackageManager().checkSignatures(
12904 ii.targetPackage, ii.packageName);
12905 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12906 String msg = "Permission Denial: starting instrumentation "
12907 + className + " from pid="
12908 + Binder.getCallingPid()
12909 + ", uid=" + Binder.getCallingPid()
12910 + " not allowed because package " + ii.packageName
12911 + " does not have a signature matching the target "
12912 + ii.targetPackage;
12913 reportStartInstrumentationFailure(watcher, className, msg);
12914 throw new SecurityException(msg);
12915 }
12916
12917 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn03abb812010-01-04 18:43:19 -080012918 forceStopPackageLocked(ii.targetPackage, -1, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012919 ProcessRecord app = addAppLocked(ai);
12920 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012921 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012922 app.instrumentationProfileFile = profileFile;
12923 app.instrumentationArguments = arguments;
12924 app.instrumentationWatcher = watcher;
12925 app.instrumentationResultClass = className;
12926 Binder.restoreCallingIdentity(origId);
12927 }
12928
12929 return true;
12930 }
12931
12932 /**
12933 * Report errors that occur while attempting to start Instrumentation. Always writes the
12934 * error to the logs, but if somebody is watching, send the report there too. This enables
12935 * the "am" command to report errors with more information.
12936 *
12937 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12938 * @param cn The component name of the instrumentation.
12939 * @param report The error report.
12940 */
12941 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12942 ComponentName cn, String report) {
12943 Log.w(TAG, report);
12944 try {
12945 if (watcher != null) {
12946 Bundle results = new Bundle();
12947 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12948 results.putString("Error", report);
12949 watcher.instrumentationStatus(cn, -1, results);
12950 }
12951 } catch (RemoteException e) {
12952 Log.w(TAG, e);
12953 }
12954 }
12955
12956 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12957 if (app.instrumentationWatcher != null) {
12958 try {
12959 // NOTE: IInstrumentationWatcher *must* be oneway here
12960 app.instrumentationWatcher.instrumentationFinished(
12961 app.instrumentationClass,
12962 resultCode,
12963 results);
12964 } catch (RemoteException e) {
12965 }
12966 }
12967 app.instrumentationWatcher = null;
12968 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012969 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012970 app.instrumentationProfileFile = null;
12971 app.instrumentationArguments = null;
12972
Dianne Hackborn03abb812010-01-04 18:43:19 -080012973 forceStopPackageLocked(app.processName, -1, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012974 }
12975
12976 public void finishInstrumentation(IApplicationThread target,
12977 int resultCode, Bundle results) {
12978 // Refuse possible leaked file descriptors
12979 if (results != null && results.hasFileDescriptors()) {
12980 throw new IllegalArgumentException("File descriptors passed in Intent");
12981 }
12982
12983 synchronized(this) {
12984 ProcessRecord app = getRecordForAppLocked(target);
12985 if (app == null) {
12986 Log.w(TAG, "finishInstrumentation: no app for " + target);
12987 return;
12988 }
12989 final long origId = Binder.clearCallingIdentity();
12990 finishInstrumentationLocked(app, resultCode, results);
12991 Binder.restoreCallingIdentity(origId);
12992 }
12993 }
12994
12995 // =========================================================
12996 // CONFIGURATION
12997 // =========================================================
12998
12999 public ConfigurationInfo getDeviceConfigurationInfo() {
13000 ConfigurationInfo config = new ConfigurationInfo();
13001 synchronized (this) {
13002 config.reqTouchScreen = mConfiguration.touchscreen;
13003 config.reqKeyboardType = mConfiguration.keyboard;
13004 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013005 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
13006 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013007 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
13008 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013009 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
13010 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013011 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
13012 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070013013 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013014 }
13015 return config;
13016 }
13017
13018 public Configuration getConfiguration() {
13019 Configuration ci;
13020 synchronized(this) {
13021 ci = new Configuration(mConfiguration);
13022 }
13023 return ci;
13024 }
13025
13026 public void updateConfiguration(Configuration values) {
13027 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13028 "updateConfiguration()");
13029
13030 synchronized(this) {
13031 if (values == null && mWindowManager != null) {
13032 // sentinel: fetch the current configuration from the window manager
13033 values = mWindowManager.computeNewConfiguration();
13034 }
13035
13036 final long origId = Binder.clearCallingIdentity();
13037 updateConfigurationLocked(values, null);
13038 Binder.restoreCallingIdentity(origId);
13039 }
13040 }
13041
13042 /**
13043 * Do either or both things: (1) change the current configuration, and (2)
13044 * make sure the given activity is running with the (now) current
13045 * configuration. Returns true if the activity has been left running, or
13046 * false if <var>starting</var> is being destroyed to match the new
13047 * configuration.
13048 */
13049 public boolean updateConfigurationLocked(Configuration values,
13050 HistoryRecord starting) {
13051 int changes = 0;
13052
13053 boolean kept = true;
13054
13055 if (values != null) {
13056 Configuration newConfig = new Configuration(mConfiguration);
13057 changes = newConfig.updateFrom(values);
13058 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013059 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013060 Log.i(TAG, "Updating configuration to: " + values);
13061 }
13062
Doug Zongker2bec3d42009-12-04 12:52:44 -080013063 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013064
13065 if (values.locale != null) {
13066 saveLocaleLocked(values.locale,
13067 !values.locale.equals(mConfiguration.locale),
13068 values.userSetLocale);
13069 }
13070
13071 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013072 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013073
13074 AttributeCache ac = AttributeCache.instance();
13075 if (ac != null) {
13076 ac.updateConfiguration(mConfiguration);
13077 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013078
13079 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13080 msg.obj = new Configuration(mConfiguration);
13081 mHandler.sendMessage(msg);
13082
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013083 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13084 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013085 try {
13086 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013087 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13088 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013089 app.thread.scheduleConfigurationChanged(mConfiguration);
13090 }
13091 } catch (Exception e) {
13092 }
13093 }
13094 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013095 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13096 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013097 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13098 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013099 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13100 broadcastIntentLocked(null, null,
13101 new Intent(Intent.ACTION_LOCALE_CHANGED),
13102 null, null, 0, null, null,
13103 null, false, false, MY_PID, Process.SYSTEM_UID);
13104 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013105 }
13106 }
13107
13108 if (changes != 0 && starting == null) {
13109 // If the configuration changed, and the caller is not already
13110 // in the process of starting an activity, then find the top
13111 // activity to check if its configuration needs to change.
13112 starting = topRunningActivityLocked(null);
13113 }
13114
13115 if (starting != null) {
13116 kept = ensureActivityConfigurationLocked(starting, changes);
13117 if (kept) {
13118 // If this didn't result in the starting activity being
13119 // destroyed, then we need to make sure at this point that all
13120 // other activities are made visible.
13121 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13122 + ", ensuring others are correct.");
13123 ensureActivitiesVisibleLocked(starting, changes);
13124 }
13125 }
13126
13127 return kept;
13128 }
13129
13130 private final boolean relaunchActivityLocked(HistoryRecord r,
13131 int changes, boolean andResume) {
13132 List<ResultInfo> results = null;
13133 List<Intent> newIntents = null;
13134 if (andResume) {
13135 results = r.results;
13136 newIntents = r.newIntents;
13137 }
13138 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13139 + " with results=" + results + " newIntents=" + newIntents
13140 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013141 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13142 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013143 r.task.taskId, r.shortComponentName);
13144
13145 r.startFreezingScreenLocked(r.app, 0);
13146
13147 try {
13148 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13149 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013150 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013151 // Note: don't need to call pauseIfSleepingLocked() here, because
13152 // the caller will only pass in 'andResume' if this activity is
13153 // currently resumed, which implies we aren't sleeping.
13154 } catch (RemoteException e) {
13155 return false;
13156 }
13157
13158 if (andResume) {
13159 r.results = null;
13160 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013161 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013162 }
13163
13164 return true;
13165 }
13166
13167 /**
13168 * Make sure the given activity matches the current configuration. Returns
13169 * false if the activity had to be destroyed. Returns true if the
13170 * configuration is the same, or the activity will remain running as-is
13171 * for whatever reason. Ensures the HistoryRecord is updated with the
13172 * correct configuration and all other bookkeeping is handled.
13173 */
13174 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13175 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013176 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13177 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013178
13179 // Short circuit: if the two configurations are the exact same
13180 // object (the common case), then there is nothing to do.
13181 Configuration newConfig = mConfiguration;
13182 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013183 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13184 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013185 return true;
13186 }
13187
13188 // We don't worry about activities that are finishing.
13189 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013190 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013191 "Configuration doesn't matter in finishing " + r);
13192 r.stopFreezingScreenLocked(false);
13193 return true;
13194 }
13195
13196 // Okay we now are going to make this activity have the new config.
13197 // But then we need to figure out how it needs to deal with that.
13198 Configuration oldConfig = r.configuration;
13199 r.configuration = newConfig;
13200
13201 // If the activity isn't currently running, just leave the new
13202 // configuration and it will pick that up next time it starts.
13203 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013204 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013205 "Configuration doesn't matter not running " + r);
13206 r.stopFreezingScreenLocked(false);
13207 return true;
13208 }
13209
13210 // If the activity isn't persistent, there is a chance we will
13211 // need to restart it.
13212 if (!r.persistent) {
13213
13214 // Figure out what has changed between the two configurations.
13215 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013216 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13217 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013218 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013219 + Integer.toHexString(r.info.configChanges)
13220 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013221 }
13222 if ((changes&(~r.info.configChanges)) != 0) {
13223 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13224 r.configChangeFlags |= changes;
13225 r.startFreezingScreenLocked(r.app, globalChanges);
13226 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013227 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13228 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013229 destroyActivityLocked(r, true);
13230 } else if (r.state == ActivityState.PAUSING) {
13231 // A little annoying: we are waiting for this activity to
13232 // finish pausing. Let's not do anything now, but just
13233 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013234 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13235 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013236 r.configDestroy = true;
13237 return true;
13238 } else if (r.state == ActivityState.RESUMED) {
13239 // Try to optimize this case: the configuration is changing
13240 // and we need to restart the top, resumed activity.
13241 // Instead of doing the normal handshaking, just say
13242 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013243 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13244 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013245 relaunchActivityLocked(r, r.configChangeFlags, true);
13246 r.configChangeFlags = 0;
13247 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013248 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13249 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013250 relaunchActivityLocked(r, r.configChangeFlags, false);
13251 r.configChangeFlags = 0;
13252 }
13253
13254 // All done... tell the caller we weren't able to keep this
13255 // activity around.
13256 return false;
13257 }
13258 }
13259
13260 // Default case: the activity can handle this new configuration, so
13261 // hand it over. Note that we don't need to give it the new
13262 // configuration, since we always send configuration changes to all
13263 // process when they happen so it can just use whatever configuration
13264 // it last got.
13265 if (r.app != null && r.app.thread != null) {
13266 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013267 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013268 r.app.thread.scheduleActivityConfigurationChanged(r);
13269 } catch (RemoteException e) {
13270 // If process died, whatever.
13271 }
13272 }
13273 r.stopFreezingScreenLocked(false);
13274
13275 return true;
13276 }
13277
13278 /**
13279 * Save the locale. You must be inside a synchronized (this) block.
13280 */
13281 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13282 if(isDiff) {
13283 SystemProperties.set("user.language", l.getLanguage());
13284 SystemProperties.set("user.region", l.getCountry());
13285 }
13286
13287 if(isPersist) {
13288 SystemProperties.set("persist.sys.language", l.getLanguage());
13289 SystemProperties.set("persist.sys.country", l.getCountry());
13290 SystemProperties.set("persist.sys.localevar", l.getVariant());
13291 }
13292 }
13293
13294 // =========================================================
13295 // LIFETIME MANAGEMENT
13296 // =========================================================
13297
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013298 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13299 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013300 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013301 // This adjustment has already been computed. If we are calling
13302 // from the top, we may have already computed our adjustment with
13303 // an earlier hidden adjustment that isn't really for us... if
13304 // so, use the new hidden adjustment.
13305 if (!recursed && app.hidden) {
13306 app.curAdj = hiddenAdj;
13307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013308 return app.curAdj;
13309 }
13310
13311 if (app.thread == null) {
13312 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013313 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013314 return (app.curAdj=EMPTY_APP_ADJ);
13315 }
13316
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013317 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13318 // The max adjustment doesn't allow this app to be anything
13319 // below foreground, so it is not worth doing work for it.
13320 app.adjType = "fixed";
13321 app.adjSeq = mAdjSeq;
13322 app.curRawAdj = app.maxAdj;
13323 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13324 return (app.curAdj=app.maxAdj);
13325 }
13326
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013327 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013328 app.adjSource = null;
13329 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013330 app.empty = false;
13331 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013332
The Android Open Source Project4df24232009-03-05 14:34:35 -080013333 // Determine the importance of the process, starting with most
13334 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013335 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013336 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013337 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013338 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013339 // The last app on the list is the foreground app.
13340 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013341 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013342 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013343 } else if (app.instrumentationClass != null) {
13344 // Don't want to kill running instrumentation.
13345 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013346 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013347 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013348 } else if (app.persistentActivities > 0) {
13349 // Special persistent activities... shouldn't be used these days.
13350 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013351 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013352 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013353 } else if (app.curReceiver != null ||
13354 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13355 // An app that is currently receiving a broadcast also
13356 // counts as being in the foreground.
13357 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013358 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013359 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013360 } else if (app.executingServices.size() > 0) {
13361 // An app that is currently executing a service callback also
13362 // counts as being in the foreground.
13363 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013364 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013365 app.adjType = "exec-service";
13366 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013367 // The user is aware of this app, so make it visible.
13368 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013369 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013370 app.adjType = "foreground-service";
13371 } else if (app.forcingToForeground != null) {
13372 // The user is aware of this app, so make it visible.
13373 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013374 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013375 app.adjType = "force-foreground";
13376 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013377 } else if (app == mHomeProcess) {
13378 // This process is hosting what we currently consider to be the
13379 // home app, so we don't want to let it go into the background.
13380 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013381 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013382 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013383 } else if ((N=app.activities.size()) != 0) {
13384 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013385 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013386 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013387 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013388 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013389 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013390 for (int j=0; j<N; j++) {
13391 if (((HistoryRecord)app.activities.get(j)).visible) {
13392 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013393 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013394 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013395 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013396 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013397 break;
13398 }
13399 }
13400 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013401 // A very not-needed process. If this is lower in the lru list,
13402 // we will push it in to the empty bucket.
13403 app.hidden = true;
13404 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013405 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013406 adj = hiddenAdj;
13407 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013408 }
13409
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013410 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13411
The Android Open Source Project4df24232009-03-05 14:34:35 -080013412 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013413 // there are applications dependent on our services or providers, but
13414 // this gives us a baseline and makes sure we don't get into an
13415 // infinite recursion.
13416 app.adjSeq = mAdjSeq;
13417 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013418
Christopher Tate6fa95972009-06-05 18:43:55 -070013419 if (mBackupTarget != null && app == mBackupTarget.app) {
13420 // If possible we want to avoid killing apps while they're being backed up
13421 if (adj > BACKUP_APP_ADJ) {
13422 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13423 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013424 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013425 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013426 }
13427 }
13428
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013429 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13430 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013431 final long now = SystemClock.uptimeMillis();
13432 // This process is more important if the top activity is
13433 // bound to the service.
13434 Iterator jt = app.services.iterator();
13435 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13436 ServiceRecord s = (ServiceRecord)jt.next();
13437 if (s.startRequested) {
13438 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13439 // This service has seen some activity within
13440 // recent memory, so we will keep its process ahead
13441 // of the background processes.
13442 if (adj > SECONDARY_SERVER_ADJ) {
13443 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013444 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013445 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013446 }
13447 }
13448 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013449 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13450 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013451 Iterator<ConnectionRecord> kt
13452 = s.connections.values().iterator();
13453 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13454 // XXX should compute this based on the max of
13455 // all connected clients.
13456 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013457 if (cr.binding.client == app) {
13458 // Binding to ourself is not interesting.
13459 continue;
13460 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013461 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13462 ProcessRecord client = cr.binding.client;
13463 int myHiddenAdj = hiddenAdj;
13464 if (myHiddenAdj > client.hiddenAdj) {
13465 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13466 myHiddenAdj = client.hiddenAdj;
13467 } else {
13468 myHiddenAdj = VISIBLE_APP_ADJ;
13469 }
13470 }
13471 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013472 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013473 if (adj > clientAdj) {
13474 adj = clientAdj > VISIBLE_APP_ADJ
13475 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013476 if (!client.hidden) {
13477 app.hidden = false;
13478 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013479 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013480 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13481 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013482 app.adjSource = cr.binding.client;
13483 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013484 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013485 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13486 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13487 schedGroup = Process.THREAD_GROUP_DEFAULT;
13488 }
13489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013490 }
13491 HistoryRecord a = cr.activity;
13492 //if (a != null) {
13493 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13494 //}
13495 if (a != null && adj > FOREGROUND_APP_ADJ &&
13496 (a.state == ActivityState.RESUMED
13497 || a.state == ActivityState.PAUSING)) {
13498 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013499 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013500 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013501 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013502 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13503 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013504 app.adjSource = a;
13505 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013506 }
13507 }
13508 }
13509 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013510
13511 // Finally, f this process has active services running in it, we
13512 // would like to avoid killing it unless it would prevent the current
13513 // application from running. By default we put the process in
13514 // with the rest of the background processes; as we scan through
13515 // its services we may bump it up from there.
13516 if (adj > hiddenAdj) {
13517 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013518 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013519 app.adjType = "bg-services";
13520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013521 }
13522
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013523 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13524 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013525 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013526 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13527 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013528 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13529 if (cpr.clients.size() != 0) {
13530 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13531 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13532 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013533 if (client == app) {
13534 // Being our own client is not interesting.
13535 continue;
13536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013537 int myHiddenAdj = hiddenAdj;
13538 if (myHiddenAdj > client.hiddenAdj) {
13539 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13540 myHiddenAdj = client.hiddenAdj;
13541 } else {
13542 myHiddenAdj = FOREGROUND_APP_ADJ;
13543 }
13544 }
13545 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013546 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013547 if (adj > clientAdj) {
13548 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013549 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013550 if (!client.hidden) {
13551 app.hidden = false;
13552 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013553 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013554 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13555 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013556 app.adjSource = client;
13557 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013558 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013559 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13560 schedGroup = Process.THREAD_GROUP_DEFAULT;
13561 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013562 }
13563 }
13564 // If the provider has external (non-framework) process
13565 // dependencies, ensure that its adjustment is at least
13566 // FOREGROUND_APP_ADJ.
13567 if (cpr.externals != 0) {
13568 if (adj > FOREGROUND_APP_ADJ) {
13569 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013570 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013571 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013572 app.adjType = "provider";
13573 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013574 }
13575 }
13576 }
13577 }
13578
13579 app.curRawAdj = adj;
13580
13581 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13582 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13583 if (adj > app.maxAdj) {
13584 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013585 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13586 schedGroup = Process.THREAD_GROUP_DEFAULT;
13587 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013588 }
13589
13590 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013591 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013593 return adj;
13594 }
13595
13596 /**
13597 * Ask a given process to GC right now.
13598 */
13599 final void performAppGcLocked(ProcessRecord app) {
13600 try {
13601 app.lastRequestedGc = SystemClock.uptimeMillis();
13602 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013603 if (app.reportLowMemory) {
13604 app.reportLowMemory = false;
13605 app.thread.scheduleLowMemory();
13606 } else {
13607 app.thread.processInBackground();
13608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013609 }
13610 } catch (Exception e) {
13611 // whatever.
13612 }
13613 }
13614
13615 /**
13616 * Returns true if things are idle enough to perform GCs.
13617 */
13618 private final boolean canGcNow() {
13619 return mParallelBroadcasts.size() == 0
13620 && mOrderedBroadcasts.size() == 0
13621 && (mSleeping || (mResumedActivity != null &&
13622 mResumedActivity.idle));
13623 }
13624
13625 /**
13626 * Perform GCs on all processes that are waiting for it, but only
13627 * if things are idle.
13628 */
13629 final void performAppGcsLocked() {
13630 final int N = mProcessesToGc.size();
13631 if (N <= 0) {
13632 return;
13633 }
13634 if (canGcNow()) {
13635 while (mProcessesToGc.size() > 0) {
13636 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013637 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13638 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13639 <= SystemClock.uptimeMillis()) {
13640 // To avoid spamming the system, we will GC processes one
13641 // at a time, waiting a few seconds between each.
13642 performAppGcLocked(proc);
13643 scheduleAppGcsLocked();
13644 return;
13645 } else {
13646 // It hasn't been long enough since we last GCed this
13647 // process... put it in the list to wait for its time.
13648 addProcessToGcListLocked(proc);
13649 break;
13650 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013651 }
13652 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013653
13654 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013655 }
13656 }
13657
13658 /**
13659 * If all looks good, perform GCs on all processes waiting for them.
13660 */
13661 final void performAppGcsIfAppropriateLocked() {
13662 if (canGcNow()) {
13663 performAppGcsLocked();
13664 return;
13665 }
13666 // Still not idle, wait some more.
13667 scheduleAppGcsLocked();
13668 }
13669
13670 /**
13671 * Schedule the execution of all pending app GCs.
13672 */
13673 final void scheduleAppGcsLocked() {
13674 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013675
13676 if (mProcessesToGc.size() > 0) {
13677 // Schedule a GC for the time to the next process.
13678 ProcessRecord proc = mProcessesToGc.get(0);
13679 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13680
13681 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13682 long now = SystemClock.uptimeMillis();
13683 if (when < (now+GC_TIMEOUT)) {
13684 when = now + GC_TIMEOUT;
13685 }
13686 mHandler.sendMessageAtTime(msg, when);
13687 }
13688 }
13689
13690 /**
13691 * Add a process to the array of processes waiting to be GCed. Keeps the
13692 * list in sorted order by the last GC time. The process can't already be
13693 * on the list.
13694 */
13695 final void addProcessToGcListLocked(ProcessRecord proc) {
13696 boolean added = false;
13697 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13698 if (mProcessesToGc.get(i).lastRequestedGc <
13699 proc.lastRequestedGc) {
13700 added = true;
13701 mProcessesToGc.add(i+1, proc);
13702 break;
13703 }
13704 }
13705 if (!added) {
13706 mProcessesToGc.add(0, proc);
13707 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013708 }
13709
13710 /**
13711 * Set up to ask a process to GC itself. This will either do it
13712 * immediately, or put it on the list of processes to gc the next
13713 * time things are idle.
13714 */
13715 final void scheduleAppGcLocked(ProcessRecord app) {
13716 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013717 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013718 return;
13719 }
13720 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013721 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013722 scheduleAppGcsLocked();
13723 }
13724 }
13725
13726 private final boolean updateOomAdjLocked(
13727 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13728 app.hiddenAdj = hiddenAdj;
13729
13730 if (app.thread == null) {
13731 return true;
13732 }
13733
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013734 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013735
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013736 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013737 if (app.curRawAdj != app.setRawAdj) {
13738 if (app.curRawAdj > FOREGROUND_APP_ADJ
13739 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13740 // If this app is transitioning from foreground to
13741 // non-foreground, have it do a gc.
13742 scheduleAppGcLocked(app);
13743 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13744 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13745 // Likewise do a gc when an app is moving in to the
13746 // background (such as a service stopping).
13747 scheduleAppGcLocked(app);
13748 }
13749 app.setRawAdj = app.curRawAdj;
13750 }
13751 if (adj != app.setAdj) {
13752 if (Process.setOomAdj(app.pid, adj)) {
13753 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13754 TAG, "Set app " + app.processName +
13755 " oom adj to " + adj);
13756 app.setAdj = adj;
13757 } else {
13758 return false;
13759 }
13760 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013761 if (app.setSchedGroup != app.curSchedGroup) {
13762 app.setSchedGroup = app.curSchedGroup;
13763 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13764 "Setting process group of " + app.processName
13765 + " to " + app.curSchedGroup);
13766 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013767 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013768 try {
13769 Process.setProcessGroup(app.pid, app.curSchedGroup);
13770 } catch (Exception e) {
13771 Log.w(TAG, "Failed setting process group of " + app.pid
13772 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013773 e.printStackTrace();
13774 } finally {
13775 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013776 }
13777 }
13778 if (false) {
13779 if (app.thread != null) {
13780 try {
13781 app.thread.setSchedulingGroup(app.curSchedGroup);
13782 } catch (RemoteException e) {
13783 }
13784 }
13785 }
13786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013787 }
13788
13789 return true;
13790 }
13791
13792 private final HistoryRecord resumedAppLocked() {
13793 HistoryRecord resumedActivity = mResumedActivity;
13794 if (resumedActivity == null || resumedActivity.app == null) {
13795 resumedActivity = mPausingActivity;
13796 if (resumedActivity == null || resumedActivity.app == null) {
13797 resumedActivity = topRunningActivityLocked(null);
13798 }
13799 }
13800 return resumedActivity;
13801 }
13802
13803 private final boolean updateOomAdjLocked(ProcessRecord app) {
13804 final HistoryRecord TOP_ACT = resumedAppLocked();
13805 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13806 int curAdj = app.curAdj;
13807 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13808 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13809
13810 mAdjSeq++;
13811
13812 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13813 if (res) {
13814 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13815 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13816 if (nowHidden != wasHidden) {
13817 // Changed to/from hidden state, so apps after it in the LRU
13818 // list may also be changed.
13819 updateOomAdjLocked();
13820 }
13821 }
13822 return res;
13823 }
13824
13825 private final boolean updateOomAdjLocked() {
13826 boolean didOomAdj = true;
13827 final HistoryRecord TOP_ACT = resumedAppLocked();
13828 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13829
13830 if (false) {
13831 RuntimeException e = new RuntimeException();
13832 e.fillInStackTrace();
13833 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13834 }
13835
13836 mAdjSeq++;
13837
13838 // First try updating the OOM adjustment for each of the
13839 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013840 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013841 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13842 while (i > 0) {
13843 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013844 ProcessRecord app = mLruProcesses.get(i);
13845 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013846 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013847 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013848 && app.curAdj == curHiddenAdj) {
13849 curHiddenAdj++;
13850 }
13851 } else {
13852 didOomAdj = false;
13853 }
13854 }
13855
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013856 // If we return false, we will fall back on killing processes to
13857 // have a fixed limit. Do this if a limit has been requested; else
13858 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013859 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13860 }
13861
13862 private final void trimApplications() {
13863 synchronized (this) {
13864 int i;
13865
13866 // First remove any unused application processes whose package
13867 // has been removed.
13868 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13869 final ProcessRecord app = mRemovedProcesses.get(i);
13870 if (app.activities.size() == 0
13871 && app.curReceiver == null && app.services.size() == 0) {
13872 Log.i(
13873 TAG, "Exiting empty application process "
13874 + app.processName + " ("
13875 + (app.thread != null ? app.thread.asBinder() : null)
13876 + ")\n");
13877 if (app.pid > 0 && app.pid != MY_PID) {
13878 Process.killProcess(app.pid);
13879 } else {
13880 try {
13881 app.thread.scheduleExit();
13882 } catch (Exception e) {
13883 // Ignore exceptions.
13884 }
13885 }
13886 cleanUpApplicationRecordLocked(app, false, -1);
13887 mRemovedProcesses.remove(i);
13888
13889 if (app.persistent) {
13890 if (app.persistent) {
13891 addAppLocked(app.info);
13892 }
13893 }
13894 }
13895 }
13896
13897 // Now try updating the OOM adjustment for each of the
13898 // application processes based on their current state.
13899 // If the setOomAdj() API is not supported, then go with our
13900 // back-up plan...
13901 if (!updateOomAdjLocked()) {
13902
13903 // Count how many processes are running services.
13904 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013905 for (i=mLruProcesses.size()-1; i>=0; i--) {
13906 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013907
13908 if (app.persistent || app.services.size() != 0
13909 || app.curReceiver != null
13910 || app.persistentActivities > 0) {
13911 // Don't count processes holding services against our
13912 // maximum process count.
13913 if (localLOGV) Log.v(
13914 TAG, "Not trimming app " + app + " with services: "
13915 + app.services);
13916 numServiceProcs++;
13917 }
13918 }
13919
13920 int curMaxProcs = mProcessLimit;
13921 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13922 if (mAlwaysFinishActivities) {
13923 curMaxProcs = 1;
13924 }
13925 curMaxProcs += numServiceProcs;
13926
13927 // Quit as many processes as we can to get down to the desired
13928 // process count. First remove any processes that no longer
13929 // have activites running in them.
13930 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013931 i<mLruProcesses.size()
13932 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013933 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013934 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013935 // Quit an application only if it is not currently
13936 // running any activities.
13937 if (!app.persistent && app.activities.size() == 0
13938 && app.curReceiver == null && app.services.size() == 0) {
13939 Log.i(
13940 TAG, "Exiting empty application process "
13941 + app.processName + " ("
13942 + (app.thread != null ? app.thread.asBinder() : null)
13943 + ")\n");
13944 if (app.pid > 0 && app.pid != MY_PID) {
13945 Process.killProcess(app.pid);
13946 } else {
13947 try {
13948 app.thread.scheduleExit();
13949 } catch (Exception e) {
13950 // Ignore exceptions.
13951 }
13952 }
13953 // todo: For now we assume the application is not buggy
13954 // or evil, and will quit as a result of our request.
13955 // Eventually we need to drive this off of the death
13956 // notification, and kill the process if it takes too long.
13957 cleanUpApplicationRecordLocked(app, false, i);
13958 i--;
13959 }
13960 }
13961
13962 // If we still have too many processes, now from the least
13963 // recently used process we start finishing activities.
13964 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013965 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013966 " of " + curMaxProcs + " processes");
13967 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013968 i<mLruProcesses.size()
13969 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013970 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013971 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013972 // Quit the application only if we have a state saved for
13973 // all of its activities.
13974 boolean canQuit = !app.persistent && app.curReceiver == null
13975 && app.services.size() == 0
13976 && app.persistentActivities == 0;
13977 int NUMA = app.activities.size();
13978 int j;
13979 if (Config.LOGV) Log.v(
13980 TAG, "Looking to quit " + app.processName);
13981 for (j=0; j<NUMA && canQuit; j++) {
13982 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13983 if (Config.LOGV) Log.v(
13984 TAG, " " + r.intent.getComponent().flattenToShortString()
13985 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13986 canQuit = (r.haveState || !r.stateNotNeeded)
13987 && !r.visible && r.stopped;
13988 }
13989 if (canQuit) {
13990 // Finish all of the activities, and then the app itself.
13991 for (j=0; j<NUMA; j++) {
13992 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13993 if (!r.finishing) {
13994 destroyActivityLocked(r, false);
13995 }
13996 r.resultTo = null;
13997 }
13998 Log.i(TAG, "Exiting application process "
13999 + app.processName + " ("
14000 + (app.thread != null ? app.thread.asBinder() : null)
14001 + ")\n");
14002 if (app.pid > 0 && app.pid != MY_PID) {
14003 Process.killProcess(app.pid);
14004 } else {
14005 try {
14006 app.thread.scheduleExit();
14007 } catch (Exception e) {
14008 // Ignore exceptions.
14009 }
14010 }
14011 // todo: For now we assume the application is not buggy
14012 // or evil, and will quit as a result of our request.
14013 // Eventually we need to drive this off of the death
14014 // notification, and kill the process if it takes too long.
14015 cleanUpApplicationRecordLocked(app, false, i);
14016 i--;
14017 //dump();
14018 }
14019 }
14020
14021 }
14022
14023 int curMaxActivities = MAX_ACTIVITIES;
14024 if (mAlwaysFinishActivities) {
14025 curMaxActivities = 1;
14026 }
14027
14028 // Finally, if there are too many activities now running, try to
14029 // finish as many as we can to get back down to the limit.
14030 for ( i=0;
14031 i<mLRUActivities.size()
14032 && mLRUActivities.size() > curMaxActivities;
14033 i++) {
14034 final HistoryRecord r
14035 = (HistoryRecord)mLRUActivities.get(i);
14036
14037 // We can finish this one if we have its icicle saved and
14038 // it is not persistent.
14039 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14040 && r.stopped && !r.persistent && !r.finishing) {
14041 final int origSize = mLRUActivities.size();
14042 destroyActivityLocked(r, true);
14043
14044 // This will remove it from the LRU list, so keep
14045 // our index at the same value. Note that this check to
14046 // see if the size changes is just paranoia -- if
14047 // something unexpected happens, we don't want to end up
14048 // in an infinite loop.
14049 if (origSize > mLRUActivities.size()) {
14050 i--;
14051 }
14052 }
14053 }
14054 }
14055 }
14056
14057 /** This method sends the specified signal to each of the persistent apps */
14058 public void signalPersistentProcesses(int sig) throws RemoteException {
14059 if (sig != Process.SIGNAL_USR1) {
14060 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14061 }
14062
14063 synchronized (this) {
14064 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14065 != PackageManager.PERMISSION_GRANTED) {
14066 throw new SecurityException("Requires permission "
14067 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14068 }
14069
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014070 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14071 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014072 if (r.thread != null && r.persistent) {
14073 Process.sendSignal(r.pid, sig);
14074 }
14075 }
14076 }
14077 }
14078
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014079 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014080 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014081
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014082 try {
14083 synchronized (this) {
14084 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14085 // its own permission.
14086 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14087 != PackageManager.PERMISSION_GRANTED) {
14088 throw new SecurityException("Requires permission "
14089 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014090 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014091
14092 if (start && fd == null) {
14093 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014094 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014095
14096 ProcessRecord proc = null;
14097 try {
14098 int pid = Integer.parseInt(process);
14099 synchronized (mPidsSelfLocked) {
14100 proc = mPidsSelfLocked.get(pid);
14101 }
14102 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014103 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014104
14105 if (proc == null) {
14106 HashMap<String, SparseArray<ProcessRecord>> all
14107 = mProcessNames.getMap();
14108 SparseArray<ProcessRecord> procs = all.get(process);
14109 if (procs != null && procs.size() > 0) {
14110 proc = procs.valueAt(0);
14111 }
14112 }
14113
14114 if (proc == null || proc.thread == null) {
14115 throw new IllegalArgumentException("Unknown process: " + process);
14116 }
14117
14118 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14119 if (isSecure) {
14120 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14121 throw new SecurityException("Process not debuggable: " + proc);
14122 }
14123 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014124
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014125 proc.thread.profilerControl(start, path, fd);
14126 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014127 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014128 }
14129 } catch (RemoteException e) {
14130 throw new IllegalStateException("Process disappeared");
14131 } finally {
14132 if (fd != null) {
14133 try {
14134 fd.close();
14135 } catch (IOException e) {
14136 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014137 }
14138 }
14139 }
14140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014141 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14142 public void monitor() {
14143 synchronized (this) { }
14144 }
14145}