blob: 44b662451bc972d7ba32274bffa6e86179eef54d [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;
64import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070065import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.content.pm.ProviderInfo;
67import android.content.pm.ResolveInfo;
68import android.content.pm.ServiceInfo;
69import android.content.res.Configuration;
70import android.graphics.Bitmap;
71import android.net.Uri;
72import android.os.Binder;
Dan Egnor60d87622009-12-16 16:32:58 -080073import android.os.Build;
Dan Egnor42471dd2010-01-07 17:25:22 -080074import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070075import android.os.Debug;
Dan Egnor60d87622009-12-16 16:32:58 -080076import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.os.Environment;
Dan Egnor42471dd2010-01-07 17:25:22 -080078import android.os.FileObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import android.os.FileUtils;
80import android.os.Handler;
81import android.os.IBinder;
82import android.os.IPermissionController;
83import android.os.Looper;
84import android.os.Message;
85import android.os.Parcel;
86import android.os.ParcelFileDescriptor;
87import android.os.PowerManager;
88import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070089import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.os.RemoteException;
91import android.os.ServiceManager;
92import android.os.SystemClock;
93import android.os.SystemProperties;
94import android.provider.Checkin;
95import android.provider.Settings;
96import android.text.TextUtils;
97import android.util.Config;
98import android.util.EventLog;
99import android.util.Log;
100import android.util.PrintWriterPrinter;
101import android.util.SparseArray;
102import android.view.Gravity;
103import android.view.LayoutInflater;
104import android.view.View;
105import android.view.WindowManager;
106import android.view.WindowManagerPolicy;
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.File;
109import java.io.FileDescriptor;
110import java.io.FileInputStream;
111import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200112import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import java.io.PrintWriter;
114import java.lang.IllegalStateException;
115import java.lang.ref.WeakReference;
116import java.util.ArrayList;
117import java.util.HashMap;
118import java.util.HashSet;
119import java.util.Iterator;
120import java.util.List;
121import java.util.Locale;
122import java.util.Map;
123
124public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
125 static final String TAG = "ActivityManager";
126 static final boolean DEBUG = false;
127 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
128 static final boolean DEBUG_SWITCH = localLOGV || false;
129 static final boolean DEBUG_TASKS = localLOGV || false;
130 static final boolean DEBUG_PAUSE = localLOGV || false;
131 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
132 static final boolean DEBUG_TRANSITION = localLOGV || false;
133 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700134 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 static final boolean DEBUG_SERVICE = localLOGV || false;
136 static final boolean DEBUG_VISBILITY = localLOGV || false;
137 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700138 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700140 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700141 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700142 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 static final boolean VALIDATE_TOKENS = false;
144 static final boolean SHOW_ACTIVITY_START_TIME = true;
145
146 // Control over CPU and battery monitoring.
147 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
148 static final boolean MONITOR_CPU_USAGE = true;
149 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
150 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
151 static final boolean MONITOR_THREAD_CPU_USAGE = false;
152
Dianne Hackborn1655be42009-05-08 14:29:01 -0700153 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700154 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 private static final String SYSTEM_SECURE = "ro.secure";
157
158 // This is the maximum number of application processes we would like
159 // to have running. Due to the asynchronous nature of things, we can
160 // temporarily go beyond this limit.
161 static final int MAX_PROCESSES = 2;
162
163 // Set to false to leave processes running indefinitely, relying on
164 // the kernel killing them as resources are required.
165 static final boolean ENFORCE_PROCESS_LIMIT = false;
166
167 // This is the maximum number of activities that we would like to have
168 // running at a given time.
169 static final int MAX_ACTIVITIES = 20;
170
171 // Maximum number of recent tasks that we can remember.
172 static final int MAX_RECENT_TASKS = 20;
173
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700174 // Amount of time after a call to stopAppSwitches() during which we will
175 // prevent further untrusted switches from happening.
176 static final long APP_SWITCH_DELAY_TIME = 5*1000;
177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 // How long until we reset a task when the user returns to it. Currently
179 // 30 minutes.
180 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
181
182 // Set to true to disable the icon that is shown while a new activity
183 // is being started.
184 static final boolean SHOW_APP_STARTING_ICON = true;
185
186 // How long we wait until giving up on the last activity to pause. This
187 // is short because it directly impacts the responsiveness of starting the
188 // next activity.
189 static final int PAUSE_TIMEOUT = 500;
190
191 /**
192 * How long we can hold the launch wake lock before giving up.
193 */
194 static final int LAUNCH_TIMEOUT = 10*1000;
195
196 // How long we wait for a launched process to attach to the activity manager
197 // before we decide it's never going to come up for real.
198 static final int PROC_START_TIMEOUT = 10*1000;
199
200 // How long we wait until giving up on the last activity telling us it
201 // is idle.
202 static final int IDLE_TIMEOUT = 10*1000;
203
204 // How long to wait after going idle before forcing apps to GC.
205 static final int GC_TIMEOUT = 5*1000;
206
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700207 // The minimum amount of time between successive GC requests for a process.
208 static final int GC_MIN_INTERVAL = 60*1000;
209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 // How long we wait until giving up on an activity telling us it has
211 // finished destroying itself.
212 static final int DESTROY_TIMEOUT = 10*1000;
213
214 // How long we allow a receiver to run before giving up on it.
215 static final int BROADCAST_TIMEOUT = 10*1000;
216
217 // How long we wait for a service to finish executing.
218 static final int SERVICE_TIMEOUT = 20*1000;
219
220 // How long a service needs to be running until restarting its process
221 // is no longer considered to be a relaunch of the service.
222 static final int SERVICE_RESTART_DURATION = 5*1000;
223
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700224 // How long a service needs to be running until it will start back at
225 // SERVICE_RESTART_DURATION after being killed.
226 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
227
228 // Multiplying factor to increase restart duration time by, for each time
229 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
230 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
231
232 // The minimum amount of time between restarting services that we allow.
233 // That is, when multiple services are restarting, we won't allow each
234 // to restart less than this amount of time from the last one.
235 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 // Maximum amount of time for there to be no activity on a service before
238 // we consider it non-essential and allow its process to go on the
239 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700240 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
242 // How long we wait until we timeout on key dispatching.
243 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
244
245 // The minimum time we allow between crashes, for us to consider this
246 // application to be bad and stop and its services and reject broadcasts.
247 static final int MIN_CRASH_INTERVAL = 60*1000;
248
249 // How long we wait until we timeout on key dispatching during instrumentation.
250 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
251
252 // OOM adjustments for processes in various states:
253
254 // This is a process without anything currently running in it. Definitely
255 // the first to go! Value set in system/rootdir/init.rc on startup.
256 // This value is initalized in the constructor, careful when refering to
257 // this static variable externally.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800258 static final int EMPTY_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
260 // This is a process only hosting activities that are not visible,
261 // so it can be killed without any disruption. Value set in
262 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800263 static final int HIDDEN_APP_MAX_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 static int HIDDEN_APP_MIN_ADJ;
265
The Android Open Source Project4df24232009-03-05 14:34:35 -0800266 // This is a process holding the home application -- we want to try
267 // avoiding killing it, even if it would normally be in the background,
268 // because the user interacts with it so much.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800269 static final int HOME_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800270
Christopher Tate6fa95972009-06-05 18:43:55 -0700271 // This is a process currently hosting a backup operation. Killing it
272 // is not entirely fatal but is generally a bad idea.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800273 static final int BACKUP_APP_ADJ;
Christopher Tate6fa95972009-06-05 18:43:55 -0700274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 // This is a process holding a secondary server -- killing it will not
276 // have much of an impact as far as the user is concerned. Value set in
277 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800278 static final int SECONDARY_SERVER_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 // This is a process only hosting activities that are visible to the
281 // user, so we'd prefer they don't disappear. Value set in
282 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800283 static final int VISIBLE_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284
285 // This is the process running the current foreground app. We'd really
286 // rather not kill it! Value set in system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800287 static final int FOREGROUND_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288
289 // This is a process running a core server, such as telephony. Definitely
290 // don't want to kill it, but doing so is not completely fatal.
291 static final int CORE_SERVER_ADJ = -12;
292
293 // The system process runs at the default adjustment.
294 static final int SYSTEM_ADJ = -16;
295
296 // Memory pages are 4K.
297 static final int PAGE_SIZE = 4*1024;
298
Jacek Surazski82a73df2009-06-17 14:33:18 +0200299 // System property defining error report receiver for system apps
300 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
301
302 // System property defining default error report receiver
303 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 // Corresponding memory levels for above adjustments.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800306 static final int EMPTY_APP_MEM;
307 static final int HIDDEN_APP_MEM;
308 static final int HOME_APP_MEM;
309 static final int BACKUP_APP_MEM;
310 static final int SECONDARY_SERVER_MEM;
311 static final int VISIBLE_APP_MEM;
312 static final int FOREGROUND_APP_MEM;
313
314 // The minimum number of hidden apps we want to be able to keep around,
315 // without empty apps being able to push them out of memory.
316 static final int MIN_HIDDEN_APPS = 2;
317
318 // We put empty content processes after any hidden processes that have
319 // been idle for less than 30 seconds.
320 static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
321
322 // We put empty content processes after any hidden processes that have
323 // been idle for less than 60 seconds.
324 static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
325
326 static {
327 // These values are set in system/rootdir/init.rc on startup.
328 FOREGROUND_APP_ADJ =
329 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
330 VISIBLE_APP_ADJ =
331 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
332 SECONDARY_SERVER_ADJ =
333 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
334 BACKUP_APP_ADJ =
335 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
336 HOME_APP_ADJ =
337 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
338 HIDDEN_APP_MIN_ADJ =
339 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
340 EMPTY_APP_ADJ =
341 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
342 HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
343 FOREGROUND_APP_MEM =
344 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
345 VISIBLE_APP_MEM =
346 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
347 SECONDARY_SERVER_MEM =
348 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
349 BACKUP_APP_MEM =
350 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
351 HOME_APP_MEM =
352 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
353 HIDDEN_APP_MEM =
354 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
355 EMPTY_APP_MEM =
356 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358
Dan Egnor42471dd2010-01-07 17:25:22 -0800359 static final int MY_PID = Process.myPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360
361 static final String[] EMPTY_STRING_ARRAY = new String[0];
362
363 enum ActivityState {
364 INITIALIZING,
365 RESUMED,
366 PAUSING,
367 PAUSED,
368 STOPPING,
369 STOPPED,
370 FINISHING,
371 DESTROYING,
372 DESTROYED
373 }
374
375 /**
376 * The back history of all previous (and possibly still
377 * running) activities. It contains HistoryRecord objects.
378 */
379 final ArrayList mHistory = new ArrayList();
380
381 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700382 * Description of a request to start a new activity, which has been held
383 * due to app switches being disabled.
384 */
385 class PendingActivityLaunch {
386 HistoryRecord r;
387 HistoryRecord sourceRecord;
388 Uri[] grantedUriPermissions;
389 int grantedMode;
390 boolean onlyIfNeeded;
391 }
392
393 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
394 = new ArrayList<PendingActivityLaunch>();
395
396 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 * List of all active broadcasts that are to be executed immediately
398 * (without waiting for another broadcast to finish). Currently this only
399 * contains broadcasts to registered receivers, to avoid spinning up
400 * a bunch of processes to execute IntentReceiver components.
401 */
402 final ArrayList<BroadcastRecord> mParallelBroadcasts
403 = new ArrayList<BroadcastRecord>();
404
405 /**
406 * List of all active broadcasts that are to be executed one at a time.
407 * The object at the top of the list is the currently activity broadcasts;
408 * those after it are waiting for the top to finish..
409 */
410 final ArrayList<BroadcastRecord> mOrderedBroadcasts
411 = new ArrayList<BroadcastRecord>();
412
413 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800414 * Historical data of past broadcasts, for debugging.
415 */
416 static final int MAX_BROADCAST_HISTORY = 100;
417 final BroadcastRecord[] mBroadcastHistory
418 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
419
420 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 * Set when we current have a BROADCAST_INTENT_MSG in flight.
422 */
423 boolean mBroadcastsScheduled = false;
424
425 /**
426 * Set to indicate whether to issue an onUserLeaving callback when a
427 * newly launched activity is being brought in front of us.
428 */
429 boolean mUserLeaving = false;
430
431 /**
432 * When we are in the process of pausing an activity, before starting the
433 * next one, this variable holds the activity that is currently being paused.
434 */
435 HistoryRecord mPausingActivity = null;
436
437 /**
438 * Current activity that is resumed, or null if there is none.
439 */
440 HistoryRecord mResumedActivity = null;
441
442 /**
443 * Activity we have told the window manager to have key focus.
444 */
445 HistoryRecord mFocusedActivity = null;
446
447 /**
448 * This is the last activity that we put into the paused state. This is
449 * used to determine if we need to do an activity transition while sleeping,
450 * when we normally hold the top activity paused.
451 */
452 HistoryRecord mLastPausedActivity = null;
453
454 /**
455 * List of activities that are waiting for a new activity
456 * to become visible before completing whatever operation they are
457 * supposed to do.
458 */
459 final ArrayList mWaitingVisibleActivities = new ArrayList();
460
461 /**
462 * List of activities that are ready to be stopped, but waiting
463 * for the next activity to settle down before doing so. It contains
464 * HistoryRecord objects.
465 */
466 final ArrayList<HistoryRecord> mStoppingActivities
467 = new ArrayList<HistoryRecord>();
468
469 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700470 * Animations that for the current transition have requested not to
471 * be considered for the transition animation.
472 */
473 final ArrayList<HistoryRecord> mNoAnimActivities
474 = new ArrayList<HistoryRecord>();
475
476 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 * List of intents that were used to start the most recent tasks.
478 */
479 final ArrayList<TaskRecord> mRecentTasks
480 = new ArrayList<TaskRecord>();
481
482 /**
483 * List of activities that are ready to be finished, but waiting
484 * for the previous activity to settle down before doing so. It contains
485 * HistoryRecord objects.
486 */
487 final ArrayList mFinishingActivities = new ArrayList();
488
489 /**
490 * All of the applications we currently have running organized by name.
491 * The keys are strings of the application package name (as
492 * returned by the package manager), and the keys are ApplicationRecord
493 * objects.
494 */
495 final ProcessMap<ProcessRecord> mProcessNames
496 = new ProcessMap<ProcessRecord>();
497
498 /**
499 * The last time that various processes have crashed.
500 */
501 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
502
503 /**
504 * Set of applications that we consider to be bad, and will reject
505 * incoming broadcasts from (which the user has no control over).
506 * Processes are added to this set when they have crashed twice within
507 * a minimum amount of time; they are removed from it when they are
508 * later restarted (hopefully due to some user action). The value is the
509 * time it was added to the list.
510 */
511 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
512
513 /**
514 * All of the processes we currently have running organized by pid.
515 * The keys are the pid running the application.
516 *
517 * <p>NOTE: This object is protected by its own lock, NOT the global
518 * activity manager lock!
519 */
520 final SparseArray<ProcessRecord> mPidsSelfLocked
521 = new SparseArray<ProcessRecord>();
522
523 /**
524 * All of the processes that have been forced to be foreground. The key
525 * is the pid of the caller who requested it (we hold a death
526 * link on it).
527 */
528 abstract class ForegroundToken implements IBinder.DeathRecipient {
529 int pid;
530 IBinder token;
531 }
532 final SparseArray<ForegroundToken> mForegroundProcesses
533 = new SparseArray<ForegroundToken>();
534
535 /**
536 * List of records for processes that someone had tried to start before the
537 * system was ready. We don't start them at that point, but ensure they
538 * are started by the time booting is complete.
539 */
540 final ArrayList<ProcessRecord> mProcessesOnHold
541 = new ArrayList<ProcessRecord>();
542
543 /**
544 * List of records for processes that we have started and are waiting
545 * for them to call back. This is really only needed when running in
546 * single processes mode, in which case we do not have a unique pid for
547 * each process.
548 */
549 final ArrayList<ProcessRecord> mStartingProcesses
550 = new ArrayList<ProcessRecord>();
551
552 /**
553 * List of persistent applications that are in the process
554 * of being started.
555 */
556 final ArrayList<ProcessRecord> mPersistentStartingProcesses
557 = new ArrayList<ProcessRecord>();
558
559 /**
560 * Processes that are being forcibly torn down.
561 */
562 final ArrayList<ProcessRecord> mRemovedProcesses
563 = new ArrayList<ProcessRecord>();
564
565 /**
566 * List of running applications, sorted by recent usage.
567 * The first entry in the list is the least recently used.
568 * It contains ApplicationRecord objects. This list does NOT include
569 * any persistent application records (since we never want to exit them).
570 */
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800571 final ArrayList<ProcessRecord> mLruProcesses
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 = new ArrayList<ProcessRecord>();
573
574 /**
575 * List of processes that should gc as soon as things are idle.
576 */
577 final ArrayList<ProcessRecord> mProcessesToGc
578 = new ArrayList<ProcessRecord>();
579
580 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800581 * This is the process holding what we currently consider to be
582 * the "home" activity.
583 */
584 private ProcessRecord mHomeProcess;
585
586 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 * List of running activities, sorted by recent usage.
588 * The first entry in the list is the least recently used.
589 * It contains HistoryRecord objects.
590 */
591 private final ArrayList mLRUActivities = new ArrayList();
592
593 /**
594 * Set of PendingResultRecord objects that are currently active.
595 */
596 final HashSet mPendingResultRecords = new HashSet();
597
598 /**
599 * Set of IntentSenderRecord objects that are currently active.
600 */
601 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
602 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
603
604 /**
605 * Intent broadcast that we have tried to start, but are
606 * waiting for its application's process to be created. We only
607 * need one (instead of a list) because we always process broadcasts
608 * one at a time, so no others can be started while waiting for this
609 * one.
610 */
611 BroadcastRecord mPendingBroadcast = null;
612
613 /**
614 * Keeps track of all IIntentReceivers that have been registered for
615 * broadcasts. Hash keys are the receiver IBinder, hash value is
616 * a ReceiverList.
617 */
618 final HashMap mRegisteredReceivers = new HashMap();
619
620 /**
621 * Resolver for broadcast intents to registered receivers.
622 * Holds BroadcastFilter (subclass of IntentFilter).
623 */
624 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
625 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
626 @Override
627 protected boolean allowFilterResult(
628 BroadcastFilter filter, List<BroadcastFilter> dest) {
629 IBinder target = filter.receiverList.receiver.asBinder();
630 for (int i=dest.size()-1; i>=0; i--) {
631 if (dest.get(i).receiverList.receiver.asBinder() == target) {
632 return false;
633 }
634 }
635 return true;
636 }
637 };
638
639 /**
640 * State of all active sticky broadcasts. Keys are the action of the
641 * sticky Intent, values are an ArrayList of all broadcasted intents with
642 * that action (which should usually be one).
643 */
644 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
645 new HashMap<String, ArrayList<Intent>>();
646
647 /**
648 * All currently running services.
649 */
650 final HashMap<ComponentName, ServiceRecord> mServices =
651 new HashMap<ComponentName, ServiceRecord>();
652
653 /**
654 * All currently running services indexed by the Intent used to start them.
655 */
656 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
657 new HashMap<Intent.FilterComparison, ServiceRecord>();
658
659 /**
660 * All currently bound service connections. Keys are the IBinder of
661 * the client's IServiceConnection.
662 */
663 final HashMap<IBinder, ConnectionRecord> mServiceConnections
664 = new HashMap<IBinder, ConnectionRecord>();
665
666 /**
667 * List of services that we have been asked to start,
668 * but haven't yet been able to. It is used to hold start requests
669 * while waiting for their corresponding application thread to get
670 * going.
671 */
672 final ArrayList<ServiceRecord> mPendingServices
673 = new ArrayList<ServiceRecord>();
674
675 /**
676 * List of services that are scheduled to restart following a crash.
677 */
678 final ArrayList<ServiceRecord> mRestartingServices
679 = new ArrayList<ServiceRecord>();
680
681 /**
682 * List of services that are in the process of being stopped.
683 */
684 final ArrayList<ServiceRecord> mStoppingServices
685 = new ArrayList<ServiceRecord>();
686
687 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700688 * Backup/restore process management
689 */
690 String mBackupAppName = null;
691 BackupRecord mBackupTarget = null;
692
693 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 * List of PendingThumbnailsRecord objects of clients who are still
695 * waiting to receive all of the thumbnails for a task.
696 */
697 final ArrayList mPendingThumbnails = new ArrayList();
698
699 /**
700 * List of HistoryRecord objects that have been finished and must
701 * still report back to a pending thumbnail receiver.
702 */
703 final ArrayList mCancelledThumbnails = new ArrayList();
704
705 /**
706 * All of the currently running global content providers. Keys are a
707 * string containing the provider name and values are a
708 * ContentProviderRecord object containing the data about it. Note
709 * that a single provider may be published under multiple names, so
710 * there may be multiple entries here for a single one in mProvidersByClass.
711 */
712 final HashMap mProvidersByName = new HashMap();
713
714 /**
715 * All of the currently running global content providers. Keys are a
716 * string containing the provider's implementation class and values are a
717 * ContentProviderRecord object containing the data about it.
718 */
719 final HashMap mProvidersByClass = new HashMap();
720
721 /**
722 * List of content providers who have clients waiting for them. The
723 * application is currently being launched and the provider will be
724 * removed from this list once it is published.
725 */
726 final ArrayList mLaunchingProviders = new ArrayList();
727
728 /**
729 * Global set of specific Uri permissions that have been granted.
730 */
731 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
732 = new SparseArray<HashMap<Uri, UriPermission>>();
733
734 /**
735 * Thread-local storage used to carry caller permissions over through
736 * indirect content-provider access.
737 * @see #ActivityManagerService.openContentUri()
738 */
739 private class Identity {
740 public int pid;
741 public int uid;
742
743 Identity(int _pid, int _uid) {
744 pid = _pid;
745 uid = _uid;
746 }
747 }
748 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
749
750 /**
751 * All information we have collected about the runtime performance of
752 * any user id that can impact battery performance.
753 */
754 final BatteryStatsService mBatteryStatsService;
755
756 /**
757 * information about component usage
758 */
759 final UsageStatsService mUsageStatsService;
760
761 /**
762 * Current configuration information. HistoryRecord objects are given
763 * a reference to this object to indicate which configuration they are
764 * currently running in, so this object must be kept immutable.
765 */
766 Configuration mConfiguration = new Configuration();
767
768 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700769 * Hardware-reported OpenGLES version.
770 */
771 final int GL_ES_VERSION;
772
773 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 * List of initialization arguments to pass to all processes when binding applications to them.
775 * For example, references to the commonly used services.
776 */
777 HashMap<String, IBinder> mAppBindArgs;
778
779 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700780 * Temporary to avoid allocations. Protected by main lock.
781 */
782 final StringBuilder mStringBuilder = new StringBuilder(256);
783
784 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 * Used to control how we initialize the service.
786 */
787 boolean mStartRunning = false;
788 ComponentName mTopComponent;
789 String mTopAction;
790 String mTopData;
791 boolean mSystemReady = false;
792 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700793 boolean mWaitingUpdate = false;
794 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795
796 Context mContext;
797
798 int mFactoryTest;
799
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700800 boolean mCheckedForSetup;
801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700803 * The time at which we will allow normal application switches again,
804 * after a call to {@link #stopAppSwitches()}.
805 */
806 long mAppSwitchesAllowedTime;
807
808 /**
809 * This is set to true after the first switch after mAppSwitchesAllowedTime
810 * is set; any switches after that will clear the time.
811 */
812 boolean mDidAppSwitch;
813
814 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 * Set while we are wanting to sleep, to prevent any
816 * activities from being started/resumed.
817 */
818 boolean mSleeping = false;
819
820 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700821 * Set if we are shutting down the system, similar to sleeping.
822 */
823 boolean mShuttingDown = false;
824
825 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 * Set when the system is going to sleep, until we have
827 * successfully paused the current activity and released our wake lock.
828 * At that point the system is allowed to actually sleep.
829 */
830 PowerManager.WakeLock mGoingToSleep;
831
832 /**
833 * We don't want to allow the device to go to sleep while in the process
834 * of launching an activity. This is primarily to allow alarm intent
835 * receivers to launch an activity and get that to run before the device
836 * goes back to sleep.
837 */
838 PowerManager.WakeLock mLaunchingActivity;
839
840 /**
841 * Task identifier that activities are currently being started
842 * in. Incremented each time a new task is created.
843 * todo: Replace this with a TokenSpace class that generates non-repeating
844 * integers that won't wrap.
845 */
846 int mCurTask = 1;
847
848 /**
849 * Current sequence id for oom_adj computation traversal.
850 */
851 int mAdjSeq = 0;
852
853 /**
854 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
855 * is set, indicating the user wants processes started in such a way
856 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
857 * running in each process (thus no pre-initialized process, etc).
858 */
859 boolean mSimpleProcessManagement = false;
860
861 /**
862 * System monitoring: number of processes that died since the last
863 * N procs were started.
864 */
865 int[] mProcDeaths = new int[20];
866
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700867 /**
868 * This is set if we had to do a delayed dexopt of an app before launching
869 * it, to increasing the ANR timeouts in that case.
870 */
871 boolean mDidDexOpt;
872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 String mDebugApp = null;
874 boolean mWaitForDebugger = false;
875 boolean mDebugTransient = false;
876 String mOrigDebugApp = null;
877 boolean mOrigWaitForDebugger = false;
878 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700879 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700881 final RemoteCallbackList<IActivityWatcher> mWatchers
882 = new RemoteCallbackList<IActivityWatcher>();
883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 /**
885 * Callback of last caller to {@link #requestPss}.
886 */
887 Runnable mRequestPssCallback;
888
889 /**
890 * Remaining processes for which we are waiting results from the last
891 * call to {@link #requestPss}.
892 */
893 final ArrayList<ProcessRecord> mRequestPssList
894 = new ArrayList<ProcessRecord>();
895
896 /**
897 * Runtime statistics collection thread. This object's lock is used to
898 * protect all related state.
899 */
900 final Thread mProcessStatsThread;
901
902 /**
903 * Used to collect process stats when showing not responding dialog.
904 * Protected by mProcessStatsThread.
905 */
906 final ProcessStats mProcessStats = new ProcessStats(
907 MONITOR_THREAD_CPU_USAGE);
908 long mLastCpuTime = 0;
909 long mLastWriteTime = 0;
910
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700911 long mInitialStartTime = 0;
912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 /**
914 * Set to true after the system has finished booting.
915 */
916 boolean mBooted = false;
917
918 int mProcessLimit = 0;
919
920 WindowManagerService mWindowManager;
921
922 static ActivityManagerService mSelf;
923 static ActivityThread mSystemThread;
924
925 private final class AppDeathRecipient implements IBinder.DeathRecipient {
926 final ProcessRecord mApp;
927 final int mPid;
928 final IApplicationThread mAppThread;
929
930 AppDeathRecipient(ProcessRecord app, int pid,
931 IApplicationThread thread) {
932 if (localLOGV) Log.v(
933 TAG, "New death recipient " + this
934 + " for thread " + thread.asBinder());
935 mApp = app;
936 mPid = pid;
937 mAppThread = thread;
938 }
939
940 public void binderDied() {
941 if (localLOGV) Log.v(
942 TAG, "Death received in " + this
943 + " for thread " + mAppThread.asBinder());
944 removeRequestedPss(mApp);
945 synchronized(ActivityManagerService.this) {
946 appDiedLocked(mApp, mPid, mAppThread);
947 }
948 }
949 }
950
951 static final int SHOW_ERROR_MSG = 1;
952 static final int SHOW_NOT_RESPONDING_MSG = 2;
953 static final int SHOW_FACTORY_ERROR_MSG = 3;
954 static final int UPDATE_CONFIGURATION_MSG = 4;
955 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
956 static final int WAIT_FOR_DEBUGGER_MSG = 6;
957 static final int BROADCAST_INTENT_MSG = 7;
958 static final int BROADCAST_TIMEOUT_MSG = 8;
959 static final int PAUSE_TIMEOUT_MSG = 9;
960 static final int IDLE_TIMEOUT_MSG = 10;
961 static final int IDLE_NOW_MSG = 11;
962 static final int SERVICE_TIMEOUT_MSG = 12;
963 static final int UPDATE_TIME_ZONE = 13;
964 static final int SHOW_UID_ERROR_MSG = 14;
965 static final int IM_FEELING_LUCKY_MSG = 15;
966 static final int LAUNCH_TIMEOUT_MSG = 16;
967 static final int DESTROY_TIMEOUT_MSG = 17;
968 static final int SERVICE_ERROR_MSG = 18;
969 static final int RESUME_TOP_ACTIVITY_MSG = 19;
970 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700971 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700972 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973
974 AlertDialog mUidAlert;
975
976 final Handler mHandler = new Handler() {
977 //public Handler() {
978 // if (localLOGV) Log.v(TAG, "Handler started!");
979 //}
980
981 public void handleMessage(Message msg) {
982 switch (msg.what) {
983 case SHOW_ERROR_MSG: {
984 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 synchronized (ActivityManagerService.this) {
986 ProcessRecord proc = (ProcessRecord)data.get("app");
987 if (proc != null && proc.crashDialog != null) {
988 Log.e(TAG, "App already has crash dialog: " + proc);
989 return;
990 }
991 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700992 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -0800993 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 d.show();
995 proc.crashDialog = d;
996 } else {
997 // The device is asleep, so just pretend that the user
998 // saw a crash dialog and hit "force quit".
999 res.set(0);
1000 }
1001 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001002
1003 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 } break;
1005 case SHOW_NOT_RESPONDING_MSG: {
1006 synchronized (ActivityManagerService.this) {
1007 HashMap data = (HashMap) msg.obj;
1008 ProcessRecord proc = (ProcessRecord)data.get("app");
1009 if (proc != null && proc.anrDialog != null) {
1010 Log.e(TAG, "App already has anr dialog: " + proc);
1011 return;
1012 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001013
1014 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1015 null, null, 0, null, null, null,
1016 false, false, MY_PID, Process.SYSTEM_UID);
1017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1019 mContext, proc, (HistoryRecord)data.get("activity"));
1020 d.show();
1021 proc.anrDialog = d;
1022 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001023
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001024 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 } break;
1026 case SHOW_FACTORY_ERROR_MSG: {
1027 Dialog d = new FactoryErrorDialog(
1028 mContext, msg.getData().getCharSequence("msg"));
1029 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001030 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 } break;
1032 case UPDATE_CONFIGURATION_MSG: {
1033 final ContentResolver resolver = mContext.getContentResolver();
1034 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1035 } break;
1036 case GC_BACKGROUND_PROCESSES_MSG: {
1037 synchronized (ActivityManagerService.this) {
1038 performAppGcsIfAppropriateLocked();
1039 }
1040 } break;
1041 case WAIT_FOR_DEBUGGER_MSG: {
1042 synchronized (ActivityManagerService.this) {
1043 ProcessRecord app = (ProcessRecord)msg.obj;
1044 if (msg.arg1 != 0) {
1045 if (!app.waitedForDebugger) {
1046 Dialog d = new AppWaitingForDebuggerDialog(
1047 ActivityManagerService.this,
1048 mContext, app);
1049 app.waitDialog = d;
1050 app.waitedForDebugger = true;
1051 d.show();
1052 }
1053 } else {
1054 if (app.waitDialog != null) {
1055 app.waitDialog.dismiss();
1056 app.waitDialog = null;
1057 }
1058 }
1059 }
1060 } break;
1061 case BROADCAST_INTENT_MSG: {
1062 if (DEBUG_BROADCAST) Log.v(
1063 TAG, "Received BROADCAST_INTENT_MSG");
1064 processNextBroadcast(true);
1065 } break;
1066 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001067 if (mDidDexOpt) {
1068 mDidDexOpt = false;
1069 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1070 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1071 return;
1072 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 broadcastTimeout();
1074 } break;
1075 case PAUSE_TIMEOUT_MSG: {
1076 IBinder token = (IBinder)msg.obj;
1077 // We don't at this point know if the activity is fullscreen,
1078 // so we need to be conservative and assume it isn't.
1079 Log.w(TAG, "Activity pause timeout for " + token);
1080 activityPaused(token, null, true);
1081 } break;
1082 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001083 if (mDidDexOpt) {
1084 mDidDexOpt = false;
1085 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1086 nmsg.obj = msg.obj;
1087 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1088 return;
1089 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 // We don't at this point know if the activity is fullscreen,
1091 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001092 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001094 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 } break;
1096 case DESTROY_TIMEOUT_MSG: {
1097 IBinder token = (IBinder)msg.obj;
1098 // We don't at this point know if the activity is fullscreen,
1099 // so we need to be conservative and assume it isn't.
1100 Log.w(TAG, "Activity destroy timeout for " + token);
1101 activityDestroyed(token);
1102 } break;
1103 case IDLE_NOW_MSG: {
1104 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001105 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 } break;
1107 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001108 if (mDidDexOpt) {
1109 mDidDexOpt = false;
1110 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1111 nmsg.obj = msg.obj;
1112 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1113 return;
1114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 serviceTimeout((ProcessRecord)msg.obj);
1116 } break;
1117 case UPDATE_TIME_ZONE: {
1118 synchronized (ActivityManagerService.this) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001119 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
1120 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 if (r.thread != null) {
1122 try {
1123 r.thread.updateTimeZone();
1124 } catch (RemoteException ex) {
1125 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1126 }
1127 }
1128 }
1129 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001130 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 case SHOW_UID_ERROR_MSG: {
1132 // XXX This is a temporary dialog, no need to localize.
1133 AlertDialog d = new BaseErrorDialog(mContext);
1134 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1135 d.setCancelable(false);
1136 d.setTitle("System UIDs Inconsistent");
1137 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1138 d.setButton("I'm Feeling Lucky",
1139 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1140 mUidAlert = d;
1141 d.show();
1142 } break;
1143 case IM_FEELING_LUCKY_MSG: {
1144 if (mUidAlert != null) {
1145 mUidAlert.dismiss();
1146 mUidAlert = null;
1147 }
1148 } break;
1149 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001150 if (mDidDexOpt) {
1151 mDidDexOpt = false;
1152 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1153 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1154 return;
1155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 synchronized (ActivityManagerService.this) {
1157 if (mLaunchingActivity.isHeld()) {
1158 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1159 mLaunchingActivity.release();
1160 }
1161 }
1162 } break;
1163 case SERVICE_ERROR_MSG: {
1164 ServiceRecord srv = (ServiceRecord)msg.obj;
1165 // This needs to be *un*synchronized to avoid deadlock.
1166 Checkin.logEvent(mContext.getContentResolver(),
1167 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1168 srv.name.toShortString());
1169 } break;
1170 case RESUME_TOP_ACTIVITY_MSG: {
1171 synchronized (ActivityManagerService.this) {
1172 resumeTopActivityLocked(null);
1173 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001174 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001176 if (mDidDexOpt) {
1177 mDidDexOpt = false;
1178 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1179 nmsg.obj = msg.obj;
1180 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1181 return;
1182 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 ProcessRecord app = (ProcessRecord)msg.obj;
1184 synchronized (ActivityManagerService.this) {
1185 processStartTimedOutLocked(app);
1186 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001187 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001188 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1189 synchronized (ActivityManagerService.this) {
1190 doPendingActivityLaunchesLocked(true);
1191 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001192 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001193 case KILL_APPLICATION_MSG: {
1194 synchronized (ActivityManagerService.this) {
1195 int uid = msg.arg1;
1196 boolean restart = (msg.arg2 == 1);
1197 String pkg = (String) msg.obj;
Dianne Hackborn03abb812010-01-04 18:43:19 -08001198 forceStopPackageLocked(pkg, uid, restart);
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001199 }
1200 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 }
1202 }
1203 };
1204
1205 public static void setSystemProcess() {
1206 try {
1207 ActivityManagerService m = mSelf;
1208
1209 ServiceManager.addService("activity", m);
1210 ServiceManager.addService("meminfo", new MemBinder(m));
1211 if (MONITOR_CPU_USAGE) {
1212 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 ServiceManager.addService("permission", new PermissionController(m));
1215
1216 ApplicationInfo info =
1217 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001218 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001219 mSystemThread.installSystemApplicationInfo(info);
1220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 synchronized (mSelf) {
1222 ProcessRecord app = mSelf.newProcessRecordLocked(
1223 mSystemThread.getApplicationThread(), info,
1224 info.processName);
1225 app.persistent = true;
Dan Egnor42471dd2010-01-07 17:25:22 -08001226 app.pid = MY_PID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 app.maxAdj = SYSTEM_ADJ;
1228 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1229 synchronized (mSelf.mPidsSelfLocked) {
1230 mSelf.mPidsSelfLocked.put(app.pid, app);
1231 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001232 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 }
1234 } catch (PackageManager.NameNotFoundException e) {
1235 throw new RuntimeException(
1236 "Unable to find android system package", e);
1237 }
1238 }
1239
1240 public void setWindowManager(WindowManagerService wm) {
1241 mWindowManager = wm;
1242 }
1243
1244 public static final Context main(int factoryTest) {
1245 AThread thr = new AThread();
1246 thr.start();
1247
1248 synchronized (thr) {
1249 while (thr.mService == null) {
1250 try {
1251 thr.wait();
1252 } catch (InterruptedException e) {
1253 }
1254 }
1255 }
1256
1257 ActivityManagerService m = thr.mService;
1258 mSelf = m;
1259 ActivityThread at = ActivityThread.systemMain();
1260 mSystemThread = at;
1261 Context context = at.getSystemContext();
1262 m.mContext = context;
1263 m.mFactoryTest = factoryTest;
1264 PowerManager pm =
1265 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1266 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1267 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1268 m.mLaunchingActivity.setReferenceCounted(false);
1269
1270 m.mBatteryStatsService.publish(context);
1271 m.mUsageStatsService.publish(context);
1272
1273 synchronized (thr) {
1274 thr.mReady = true;
1275 thr.notifyAll();
1276 }
1277
1278 m.startRunning(null, null, null, null);
1279
1280 return context;
1281 }
1282
1283 public static ActivityManagerService self() {
1284 return mSelf;
1285 }
1286
1287 static class AThread extends Thread {
1288 ActivityManagerService mService;
1289 boolean mReady = false;
1290
1291 public AThread() {
1292 super("ActivityManager");
1293 }
1294
1295 public void run() {
1296 Looper.prepare();
1297
1298 android.os.Process.setThreadPriority(
1299 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1300
1301 ActivityManagerService m = new ActivityManagerService();
1302
1303 synchronized (this) {
1304 mService = m;
1305 notifyAll();
1306 }
1307
1308 synchronized (this) {
1309 while (!mReady) {
1310 try {
1311 wait();
1312 } catch (InterruptedException e) {
1313 }
1314 }
1315 }
1316
1317 Looper.loop();
1318 }
1319 }
1320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 static class MemBinder extends Binder {
1322 ActivityManagerService mActivityManagerService;
1323 MemBinder(ActivityManagerService activityManagerService) {
1324 mActivityManagerService = activityManagerService;
1325 }
1326
1327 @Override
1328 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1329 ActivityManagerService service = mActivityManagerService;
1330 ArrayList<ProcessRecord> procs;
1331 synchronized (mActivityManagerService) {
1332 if (args != null && args.length > 0
1333 && args[0].charAt(0) != '-') {
1334 procs = new ArrayList<ProcessRecord>();
1335 int pid = -1;
1336 try {
1337 pid = Integer.parseInt(args[0]);
1338 } catch (NumberFormatException e) {
1339
1340 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001341 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1342 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 if (proc.pid == pid) {
1344 procs.add(proc);
1345 } else if (proc.processName.equals(args[0])) {
1346 procs.add(proc);
1347 }
1348 }
1349 if (procs.size() <= 0) {
1350 pw.println("No process found for: " + args[0]);
1351 return;
1352 }
1353 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001354 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 }
1356 }
1357 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1358 }
1359 }
1360
1361 static class CpuBinder extends Binder {
1362 ActivityManagerService mActivityManagerService;
1363 CpuBinder(ActivityManagerService activityManagerService) {
1364 mActivityManagerService = activityManagerService;
1365 }
1366
1367 @Override
1368 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1369 synchronized (mActivityManagerService.mProcessStatsThread) {
1370 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1371 }
1372 }
1373 }
1374
1375 private ActivityManagerService() {
1376 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1377 if (v != null && Integer.getInteger(v) != 0) {
1378 mSimpleProcessManagement = true;
1379 }
1380 v = System.getenv("ANDROID_DEBUG_APP");
1381 if (v != null) {
1382 mSimpleProcessManagement = true;
1383 }
1384
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001385 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 File dataDir = Environment.getDataDirectory();
1388 File systemDir = new File(dataDir, "system");
1389 systemDir.mkdirs();
1390 mBatteryStatsService = new BatteryStatsService(new File(
1391 systemDir, "batterystats.bin").toString());
1392 mBatteryStatsService.getActiveStatistics().readLocked();
1393 mBatteryStatsService.getActiveStatistics().writeLocked();
1394
1395 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001396 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397
Jack Palevichb90d28c2009-07-22 15:35:24 -07001398 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1399 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 mConfiguration.makeDefault();
1402 mProcessStats.init();
1403
1404 // Add ourself to the Watchdog monitors.
1405 Watchdog.getInstance().addMonitor(this);
1406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001407 mProcessStatsThread = new Thread("ProcessStats") {
1408 public void run() {
1409 while (true) {
1410 try {
1411 try {
1412 synchronized(this) {
1413 final long now = SystemClock.uptimeMillis();
1414 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1415 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1416 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1417 // + ", write delay=" + nextWriteDelay);
1418 if (nextWriteDelay < nextCpuDelay) {
1419 nextCpuDelay = nextWriteDelay;
1420 }
1421 if (nextCpuDelay > 0) {
1422 this.wait(nextCpuDelay);
1423 }
1424 }
1425 } catch (InterruptedException e) {
1426 }
1427
1428 updateCpuStatsNow();
1429 } catch (Exception e) {
1430 Log.e(TAG, "Unexpected exception collecting process stats", e);
1431 }
1432 }
1433 }
1434 };
1435 mProcessStatsThread.start();
1436 }
1437
1438 @Override
1439 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1440 throws RemoteException {
1441 try {
1442 return super.onTransact(code, data, reply, flags);
1443 } catch (RuntimeException e) {
1444 // The activity manager only throws security exceptions, so let's
1445 // log all others.
1446 if (!(e instanceof SecurityException)) {
1447 Log.e(TAG, "Activity Manager Crash", e);
1448 }
1449 throw e;
1450 }
1451 }
1452
1453 void updateCpuStats() {
1454 synchronized (mProcessStatsThread) {
1455 final long now = SystemClock.uptimeMillis();
1456 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1457 mProcessStatsThread.notify();
1458 }
1459 }
1460 }
1461
1462 void updateCpuStatsNow() {
1463 synchronized (mProcessStatsThread) {
1464 final long now = SystemClock.uptimeMillis();
1465 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 if (MONITOR_CPU_USAGE &&
1468 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1469 mLastCpuTime = now;
1470 haveNewCpuStats = true;
1471 mProcessStats.update();
1472 //Log.i(TAG, mProcessStats.printCurrentState());
1473 //Log.i(TAG, "Total CPU usage: "
1474 // + mProcessStats.getTotalCpuPercent() + "%");
1475
1476 // Log the cpu usage if the property is set.
1477 if ("true".equals(SystemProperties.get("events.cpu"))) {
1478 int user = mProcessStats.getLastUserTime();
1479 int system = mProcessStats.getLastSystemTime();
1480 int iowait = mProcessStats.getLastIoWaitTime();
1481 int irq = mProcessStats.getLastIrqTime();
1482 int softIrq = mProcessStats.getLastSoftIrqTime();
1483 int idle = mProcessStats.getLastIdleTime();
1484
1485 int total = user + system + iowait + irq + softIrq + idle;
1486 if (total == 0) total = 1;
1487
Doug Zongker2bec3d42009-12-04 12:52:44 -08001488 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 ((user+system+iowait+irq+softIrq) * 100) / total,
1490 (user * 100) / total,
1491 (system * 100) / total,
1492 (iowait * 100) / total,
1493 (irq * 100) / total,
1494 (softIrq * 100) / total);
1495 }
1496 }
1497
Amith Yamasanie43530a2009-08-21 13:11:37 -07001498 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001499 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001500 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 synchronized(mPidsSelfLocked) {
1502 if (haveNewCpuStats) {
1503 if (mBatteryStatsService.isOnBattery()) {
1504 final int N = mProcessStats.countWorkingStats();
1505 for (int i=0; i<N; i++) {
1506 ProcessStats.Stats st
1507 = mProcessStats.getWorkingStats(i);
1508 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1509 if (pr != null) {
1510 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1511 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001512 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001513 } else {
1514 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001515 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001516 if (ps != null) {
1517 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001518 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 }
1521 }
1522 }
1523 }
1524 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1527 mLastWriteTime = now;
1528 mBatteryStatsService.getActiveStatistics().writeLocked();
1529 }
1530 }
1531 }
1532 }
1533
1534 /**
1535 * Initialize the application bind args. These are passed to each
1536 * process when the bindApplication() IPC is sent to the process. They're
1537 * lazily setup to make sure the services are running when they're asked for.
1538 */
1539 private HashMap<String, IBinder> getCommonServicesLocked() {
1540 if (mAppBindArgs == null) {
1541 mAppBindArgs = new HashMap<String, IBinder>();
1542
1543 // Setup the application init args
1544 mAppBindArgs.put("package", ServiceManager.getService("package"));
1545 mAppBindArgs.put("window", ServiceManager.getService("window"));
1546 mAppBindArgs.put(Context.ALARM_SERVICE,
1547 ServiceManager.getService(Context.ALARM_SERVICE));
1548 }
1549 return mAppBindArgs;
1550 }
1551
1552 private final void setFocusedActivityLocked(HistoryRecord r) {
1553 if (mFocusedActivity != r) {
1554 mFocusedActivity = r;
1555 mWindowManager.setFocusedApp(r, true);
1556 }
1557 }
1558
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001559 private final void updateLruProcessLocked(ProcessRecord app,
1560 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001562 int lrui = mLruProcesses.indexOf(app);
1563 if (lrui >= 0) mLruProcesses.remove(lrui);
1564
1565 int i = mLruProcesses.size()-1;
1566 int skipTop = 0;
1567
1568 // compute the new weight for this process.
1569 if (updateActivityTime) {
1570 app.lastActivityTime = SystemClock.uptimeMillis();
1571 }
1572 if (app.activities.size() > 0) {
1573 // If this process has activities, we more strongly want to keep
1574 // it around.
1575 app.lruWeight = app.lastActivityTime;
1576 } else if (app.pubProviders.size() > 0) {
1577 // If this process contains content providers, we want to keep
1578 // it a little more strongly.
1579 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1580 // Also don't let it kick out the first few "real" hidden processes.
1581 skipTop = MIN_HIDDEN_APPS;
1582 } else {
1583 // If this process doesn't have activities, we less strongly
1584 // want to keep it around, and generally want to avoid getting
1585 // in front of any very recently used activities.
1586 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1587 // Also don't let it kick out the first few "real" hidden processes.
1588 skipTop = MIN_HIDDEN_APPS;
1589 }
1590 while (i >= 0) {
1591 ProcessRecord p = mLruProcesses.get(i);
1592 // If this app shouldn't be in front of the first N background
1593 // apps, then skip over that many that are currently hidden.
1594 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1595 skipTop--;
1596 }
1597 if (p.lruWeight <= app.lruWeight){
1598 mLruProcesses.add(i+1, app);
1599 break;
1600 }
1601 i--;
1602 }
1603 if (i < 0) {
1604 mLruProcesses.add(0, app);
1605 }
1606
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 //Log.i(TAG, "Putting proc to front: " + app.processName);
1608 if (oomAdj) {
1609 updateOomAdjLocked();
1610 }
1611 }
1612
1613 private final boolean updateLRUListLocked(HistoryRecord r) {
1614 final boolean hadit = mLRUActivities.remove(r);
1615 mLRUActivities.add(r);
1616 return hadit;
1617 }
1618
1619 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1620 int i = mHistory.size()-1;
1621 while (i >= 0) {
1622 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1623 if (!r.finishing && r != notTop) {
1624 return r;
1625 }
1626 i--;
1627 }
1628 return null;
1629 }
1630
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001631 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1632 int i = mHistory.size()-1;
1633 while (i >= 0) {
1634 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1635 if (!r.finishing && !r.delayedResume && r != notTop) {
1636 return r;
1637 }
1638 i--;
1639 }
1640 return null;
1641 }
1642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 /**
1644 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001645 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 *
1647 * @param token If non-null, any history records matching this token will be skipped.
1648 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1649 *
1650 * @return Returns the HistoryRecord of the next activity on the stack.
1651 */
1652 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1653 int i = mHistory.size()-1;
1654 while (i >= 0) {
1655 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1656 // Note: the taskId check depends on real taskId fields being non-zero
1657 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1658 return r;
1659 }
1660 i--;
1661 }
1662 return null;
1663 }
1664
1665 private final ProcessRecord getProcessRecordLocked(
1666 String processName, int uid) {
1667 if (uid == Process.SYSTEM_UID) {
1668 // The system gets to run in any process. If there are multiple
1669 // processes with the same uid, just pick the first (this
1670 // should never happen).
1671 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1672 processName);
1673 return procs != null ? procs.valueAt(0) : null;
1674 }
1675 ProcessRecord proc = mProcessNames.get(processName, uid);
1676 return proc;
1677 }
1678
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001679 private void ensurePackageDexOpt(String packageName) {
1680 IPackageManager pm = ActivityThread.getPackageManager();
1681 try {
1682 if (pm.performDexOpt(packageName)) {
1683 mDidDexOpt = true;
1684 }
1685 } catch (RemoteException e) {
1686 }
1687 }
1688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 private boolean isNextTransitionForward() {
1690 int transit = mWindowManager.getPendingAppTransition();
1691 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1692 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1693 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1694 }
1695
1696 private final boolean realStartActivityLocked(HistoryRecord r,
1697 ProcessRecord app, boolean andResume, boolean checkConfig)
1698 throws RemoteException {
1699
1700 r.startFreezingScreenLocked(app, 0);
1701 mWindowManager.setAppVisibility(r, true);
1702
1703 // Have the window manager re-evaluate the orientation of
1704 // the screen based on the new activity order. Note that
1705 // as a result of this, it can call back into the activity
1706 // manager with a new orientation. We don't care about that,
1707 // because the activity is not currently running so we are
1708 // just restarting it anyway.
1709 if (checkConfig) {
1710 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001711 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 r.mayFreezeScreenLocked(app) ? r : null);
1713 updateConfigurationLocked(config, r);
1714 }
1715
1716 r.app = app;
1717
1718 if (localLOGV) Log.v(TAG, "Launching: " + r);
1719
1720 int idx = app.activities.indexOf(r);
1721 if (idx < 0) {
1722 app.activities.add(r);
1723 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001724 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725
1726 try {
1727 if (app.thread == null) {
1728 throw new RemoteException();
1729 }
1730 List<ResultInfo> results = null;
1731 List<Intent> newIntents = null;
1732 if (andResume) {
1733 results = r.results;
1734 newIntents = r.newIntents;
1735 }
1736 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1737 + " icicle=" + r.icicle
1738 + " with results=" + results + " newIntents=" + newIntents
1739 + " andResume=" + andResume);
1740 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001741 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 System.identityHashCode(r),
1743 r.task.taskId, r.shortComponentName);
1744 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001745 if (r.isHomeActivity) {
1746 mHomeProcess = app;
1747 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001748 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001750 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 r.info, r.icicle, results, newIntents, !andResume,
1752 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 } catch (RemoteException e) {
1754 if (r.launchFailed) {
1755 // This is the second time we failed -- finish activity
1756 // and give up.
1757 Log.e(TAG, "Second failure launching "
1758 + r.intent.getComponent().flattenToShortString()
1759 + ", giving up", e);
1760 appDiedLocked(app, app.pid, app.thread);
1761 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1762 "2nd-crash");
1763 return false;
1764 }
1765
1766 // This is the first time we failed -- restart process and
1767 // retry.
1768 app.activities.remove(r);
1769 throw e;
1770 }
1771
1772 r.launchFailed = false;
1773 if (updateLRUListLocked(r)) {
1774 Log.w(TAG, "Activity " + r
1775 + " being launched, but already in LRU list");
1776 }
1777
1778 if (andResume) {
1779 // As part of the process of launching, ActivityThread also performs
1780 // a resume.
1781 r.state = ActivityState.RESUMED;
1782 r.icicle = null;
1783 r.haveState = false;
1784 r.stopped = false;
1785 mResumedActivity = r;
1786 r.task.touchActiveTime();
1787 completeResumeLocked(r);
1788 pauseIfSleepingLocked();
1789 } else {
1790 // This activity is not starting in the resumed state... which
1791 // should look like we asked it to pause+stop (but remain visible),
1792 // and it has done so and reported back the current icicle and
1793 // other state.
1794 r.state = ActivityState.STOPPED;
1795 r.stopped = true;
1796 }
1797
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001798 // Launch the new version setup screen if needed. We do this -after-
1799 // launching the initial activity (that is, home), so that it can have
1800 // a chance to initialize itself while in the background, making the
1801 // switch back to it faster and look better.
1802 startSetupActivityLocked();
1803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 return true;
1805 }
1806
1807 private final void startSpecificActivityLocked(HistoryRecord r,
1808 boolean andResume, boolean checkConfig) {
1809 // Is this activity's application already running?
1810 ProcessRecord app = getProcessRecordLocked(r.processName,
1811 r.info.applicationInfo.uid);
1812
1813 if (r.startTime == 0) {
1814 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001815 if (mInitialStartTime == 0) {
1816 mInitialStartTime = r.startTime;
1817 }
1818 } else if (mInitialStartTime == 0) {
1819 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 }
1821
1822 if (app != null && app.thread != null) {
1823 try {
1824 realStartActivityLocked(r, app, andResume, checkConfig);
1825 return;
1826 } catch (RemoteException e) {
1827 Log.w(TAG, "Exception when starting activity "
1828 + r.intent.getComponent().flattenToShortString(), e);
1829 }
1830
1831 // If a dead object exception was thrown -- fall through to
1832 // restart the application.
1833 }
1834
1835 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001836 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 }
1838
1839 private final ProcessRecord startProcessLocked(String processName,
1840 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001841 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1843 // We don't have to do anything more if:
1844 // (1) There is an existing application record; and
1845 // (2) The caller doesn't think it is dead, OR there is no thread
1846 // object attached to it so we know it couldn't have crashed; and
1847 // (3) There is a pid assigned to it, so it is either starting or
1848 // already running.
1849 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1850 + " app=" + app + " knownToBeDead=" + knownToBeDead
1851 + " thread=" + (app != null ? app.thread : null)
1852 + " pid=" + (app != null ? app.pid : -1));
1853 if (app != null &&
1854 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1855 return app;
1856 }
1857
1858 String hostingNameStr = hostingName != null
1859 ? hostingName.flattenToShortString() : null;
1860
1861 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1862 // If we are in the background, then check to see if this process
1863 // is bad. If so, we will just silently fail.
1864 if (mBadProcesses.get(info.processName, info.uid) != null) {
1865 return null;
1866 }
1867 } else {
1868 // When the user is explicitly starting a process, then clear its
1869 // crash count so that we won't make it bad until they see at
1870 // least one crash dialog again, and make the process good again
1871 // if it had been bad.
1872 mProcessCrashTimes.remove(info.processName, info.uid);
1873 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001874 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 info.processName);
1876 mBadProcesses.remove(info.processName, info.uid);
1877 if (app != null) {
1878 app.bad = false;
1879 }
1880 }
1881 }
1882
1883 if (app == null) {
1884 app = newProcessRecordLocked(null, info, processName);
1885 mProcessNames.put(processName, info.uid, app);
1886 } else {
1887 // If this is a new package in the process, add the package to the list
1888 app.addPackage(info.packageName);
1889 }
1890
1891 // If the system is not ready yet, then hold off on starting this
1892 // process until it is.
1893 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001894 && !isAllowedWhileBooting(info)
1895 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 if (!mProcessesOnHold.contains(app)) {
1897 mProcessesOnHold.add(app);
1898 }
1899 return app;
1900 }
1901
1902 startProcessLocked(app, hostingType, hostingNameStr);
1903 return (app.pid != 0) ? app : null;
1904 }
1905
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001906 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1907 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1908 }
1909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 private final void startProcessLocked(ProcessRecord app,
1911 String hostingType, String hostingNameStr) {
1912 if (app.pid > 0 && app.pid != MY_PID) {
1913 synchronized (mPidsSelfLocked) {
1914 mPidsSelfLocked.remove(app.pid);
1915 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1916 }
1917 app.pid = 0;
1918 }
1919
1920 mProcessesOnHold.remove(app);
1921
1922 updateCpuStats();
1923
1924 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1925 mProcDeaths[0] = 0;
1926
1927 try {
1928 int uid = app.info.uid;
1929 int[] gids = null;
1930 try {
1931 gids = mContext.getPackageManager().getPackageGids(
1932 app.info.packageName);
1933 } catch (PackageManager.NameNotFoundException e) {
1934 Log.w(TAG, "Unable to retrieve gids", e);
1935 }
1936 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1937 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1938 && mTopComponent != null
1939 && app.processName.equals(mTopComponent.getPackageName())) {
1940 uid = 0;
1941 }
1942 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1943 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1944 uid = 0;
1945 }
1946 }
1947 int debugFlags = 0;
1948 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1949 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1950 }
1951 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1952 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1953 }
1954 if ("1".equals(SystemProperties.get("debug.assert"))) {
1955 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1956 }
1957 int pid = Process.start("android.app.ActivityThread",
1958 mSimpleProcessManagement ? app.processName : null, uid, uid,
1959 gids, debugFlags, null);
1960 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1961 synchronized (bs) {
1962 if (bs.isOnBattery()) {
1963 app.batteryStats.incStartsLocked();
1964 }
1965 }
1966
Doug Zongker2bec3d42009-12-04 12:52:44 -08001967 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 app.processName, hostingType,
1969 hostingNameStr != null ? hostingNameStr : "");
1970
1971 if (app.persistent) {
1972 Watchdog.getInstance().processStarted(app, app.processName, pid);
1973 }
1974
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001975 StringBuilder buf = mStringBuilder;
1976 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 buf.append("Start proc ");
1978 buf.append(app.processName);
1979 buf.append(" for ");
1980 buf.append(hostingType);
1981 if (hostingNameStr != null) {
1982 buf.append(" ");
1983 buf.append(hostingNameStr);
1984 }
1985 buf.append(": pid=");
1986 buf.append(pid);
1987 buf.append(" uid=");
1988 buf.append(uid);
1989 buf.append(" gids={");
1990 if (gids != null) {
1991 for (int gi=0; gi<gids.length; gi++) {
1992 if (gi != 0) buf.append(", ");
1993 buf.append(gids[gi]);
1994
1995 }
1996 }
1997 buf.append("}");
1998 Log.i(TAG, buf.toString());
1999 if (pid == 0 || pid == MY_PID) {
2000 // Processes are being emulated with threads.
2001 app.pid = MY_PID;
2002 app.removed = false;
2003 mStartingProcesses.add(app);
2004 } else if (pid > 0) {
2005 app.pid = pid;
2006 app.removed = false;
2007 synchronized (mPidsSelfLocked) {
2008 this.mPidsSelfLocked.put(pid, app);
2009 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2010 msg.obj = app;
2011 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2012 }
2013 } else {
2014 app.pid = 0;
2015 RuntimeException e = new RuntimeException(
2016 "Failure starting process " + app.processName
2017 + ": returned pid=" + pid);
2018 Log.e(TAG, e.getMessage(), e);
2019 }
2020 } catch (RuntimeException e) {
2021 // XXX do better error recovery.
2022 app.pid = 0;
2023 Log.e(TAG, "Failure starting process " + app.processName, e);
2024 }
2025 }
2026
2027 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2028 if (mPausingActivity != null) {
2029 RuntimeException e = new RuntimeException();
2030 Log.e(TAG, "Trying to pause when pause is already pending for "
2031 + mPausingActivity, e);
2032 }
2033 HistoryRecord prev = mResumedActivity;
2034 if (prev == null) {
2035 RuntimeException e = new RuntimeException();
2036 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2037 resumeTopActivityLocked(null);
2038 return;
2039 }
2040 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2041 mResumedActivity = null;
2042 mPausingActivity = prev;
2043 mLastPausedActivity = prev;
2044 prev.state = ActivityState.PAUSING;
2045 prev.task.touchActiveTime();
2046
2047 updateCpuStats();
2048
2049 if (prev.app != null && prev.app.thread != null) {
2050 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2051 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002052 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 System.identityHashCode(prev),
2054 prev.shortComponentName);
2055 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2056 prev.configChangeFlags);
2057 updateUsageStats(prev, false);
2058 } catch (Exception e) {
2059 // Ignore exception, if process died other code will cleanup.
2060 Log.w(TAG, "Exception thrown during pause", e);
2061 mPausingActivity = null;
2062 mLastPausedActivity = null;
2063 }
2064 } else {
2065 mPausingActivity = null;
2066 mLastPausedActivity = null;
2067 }
2068
2069 // If we are not going to sleep, we want to ensure the device is
2070 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002071 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002072 mLaunchingActivity.acquire();
2073 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2074 // To be safe, don't allow the wake lock to be held for too long.
2075 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2076 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2077 }
2078 }
2079
2080
2081 if (mPausingActivity != null) {
2082 // Have the window manager pause its key dispatching until the new
2083 // activity has started. If we're pausing the activity just because
2084 // the screen is being turned off and the UI is sleeping, don't interrupt
2085 // key dispatch; the same activity will pick it up again on wakeup.
2086 if (!uiSleeping) {
2087 prev.pauseKeyDispatchingLocked();
2088 } else {
2089 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2090 }
2091
2092 // Schedule a pause timeout in case the app doesn't respond.
2093 // We don't give it much time because this directly impacts the
2094 // responsiveness seen by the user.
2095 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2096 msg.obj = prev;
2097 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2098 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2099 } else {
2100 // This activity failed to schedule the
2101 // pause, so just treat it as being paused now.
2102 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2103 resumeTopActivityLocked(null);
2104 }
2105 }
2106
2107 private final void completePauseLocked() {
2108 HistoryRecord prev = mPausingActivity;
2109 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2110
2111 if (prev != null) {
2112 if (prev.finishing) {
2113 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2114 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2115 } else if (prev.app != null) {
2116 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2117 if (prev.waitingVisible) {
2118 prev.waitingVisible = false;
2119 mWaitingVisibleActivities.remove(prev);
2120 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2121 TAG, "Complete pause, no longer waiting: " + prev);
2122 }
2123 if (prev.configDestroy) {
2124 // The previous is being paused because the configuration
2125 // is changing, which means it is actually stopping...
2126 // To juggle the fact that we are also starting a new
2127 // instance right now, we need to first completely stop
2128 // the current instance before starting the new one.
2129 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2130 destroyActivityLocked(prev, true);
2131 } else {
2132 mStoppingActivities.add(prev);
2133 if (mStoppingActivities.size() > 3) {
2134 // If we already have a few activities waiting to stop,
2135 // then give up on things going idle and start clearing
2136 // them out.
2137 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2138 Message msg = Message.obtain();
2139 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2140 mHandler.sendMessage(msg);
2141 }
2142 }
2143 } else {
2144 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2145 prev = null;
2146 }
2147 mPausingActivity = null;
2148 }
2149
Dianne Hackborn55280a92009-05-07 15:53:46 -07002150 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 resumeTopActivityLocked(prev);
2152 } else {
2153 if (mGoingToSleep.isHeld()) {
2154 mGoingToSleep.release();
2155 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002156 if (mShuttingDown) {
2157 notifyAll();
2158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159 }
2160
2161 if (prev != null) {
2162 prev.resumeKeyDispatchingLocked();
2163 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002164
2165 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2166 long diff = 0;
2167 synchronized (mProcessStatsThread) {
2168 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2169 }
2170 if (diff > 0) {
2171 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2172 synchronized (bsi) {
2173 BatteryStatsImpl.Uid.Proc ps =
2174 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2175 prev.info.packageName);
2176 if (ps != null) {
2177 ps.addForegroundTimeLocked(diff);
2178 }
2179 }
2180 }
2181 }
2182 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 }
2184
2185 /**
2186 * Once we know that we have asked an application to put an activity in
2187 * the resumed state (either by launching it or explicitly telling it),
2188 * this function updates the rest of our state to match that fact.
2189 */
2190 private final void completeResumeLocked(HistoryRecord next) {
2191 next.idle = false;
2192 next.results = null;
2193 next.newIntents = null;
2194
2195 // schedule an idle timeout in case the app doesn't do it for us.
2196 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2197 msg.obj = next;
2198 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2199
2200 if (false) {
2201 // The activity was never told to pause, so just keep
2202 // things going as-is. To maintain our own state,
2203 // we need to emulate it coming back and saying it is
2204 // idle.
2205 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2206 msg.obj = next;
2207 mHandler.sendMessage(msg);
2208 }
2209
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002210 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212 next.thumbnail = null;
2213 setFocusedActivityLocked(next);
2214 next.resumeKeyDispatchingLocked();
2215 ensureActivitiesVisibleLocked(null, 0);
2216 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002217 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002218
2219 // Mark the point when the activity is resuming
2220 // TODO: To be more accurate, the mark should be before the onCreate,
2221 // not after the onResume. But for subsequent starts, onResume is fine.
2222 if (next.app != null) {
2223 synchronized (mProcessStatsThread) {
2224 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2225 }
2226 } else {
2227 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2228 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002229 }
2230
2231 /**
2232 * Make sure that all activities that need to be visible (that is, they
2233 * currently can be seen by the user) actually are.
2234 */
2235 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2236 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2237 if (DEBUG_VISBILITY) Log.v(
2238 TAG, "ensureActivitiesVisible behind " + top
2239 + " configChanges=0x" + Integer.toHexString(configChanges));
2240
2241 // If the top activity is not fullscreen, then we need to
2242 // make sure any activities under it are now visible.
2243 final int count = mHistory.size();
2244 int i = count-1;
2245 while (mHistory.get(i) != top) {
2246 i--;
2247 }
2248 HistoryRecord r;
2249 boolean behindFullscreen = false;
2250 for (; i>=0; i--) {
2251 r = (HistoryRecord)mHistory.get(i);
2252 if (DEBUG_VISBILITY) Log.v(
2253 TAG, "Make visible? " + r + " finishing=" + r.finishing
2254 + " state=" + r.state);
2255 if (r.finishing) {
2256 continue;
2257 }
2258
2259 final boolean doThisProcess = onlyThisProcess == null
2260 || onlyThisProcess.equals(r.processName);
2261
2262 // First: if this is not the current activity being started, make
2263 // sure it matches the current configuration.
2264 if (r != starting && doThisProcess) {
2265 ensureActivityConfigurationLocked(r, 0);
2266 }
2267
2268 if (r.app == null || r.app.thread == null) {
2269 if (onlyThisProcess == null
2270 || onlyThisProcess.equals(r.processName)) {
2271 // This activity needs to be visible, but isn't even
2272 // running... get it started, but don't resume it
2273 // at this point.
2274 if (DEBUG_VISBILITY) Log.v(
2275 TAG, "Start and freeze screen for " + r);
2276 if (r != starting) {
2277 r.startFreezingScreenLocked(r.app, configChanges);
2278 }
2279 if (!r.visible) {
2280 if (DEBUG_VISBILITY) Log.v(
2281 TAG, "Starting and making visible: " + r);
2282 mWindowManager.setAppVisibility(r, true);
2283 }
2284 if (r != starting) {
2285 startSpecificActivityLocked(r, false, false);
2286 }
2287 }
2288
2289 } else if (r.visible) {
2290 // If this activity is already visible, then there is nothing
2291 // else to do here.
2292 if (DEBUG_VISBILITY) Log.v(
2293 TAG, "Skipping: already visible at " + r);
2294 r.stopFreezingScreenLocked(false);
2295
2296 } else if (onlyThisProcess == null) {
2297 // This activity is not currently visible, but is running.
2298 // Tell it to become visible.
2299 r.visible = true;
2300 if (r.state != ActivityState.RESUMED && r != starting) {
2301 // If this activity is paused, tell it
2302 // to now show its window.
2303 if (DEBUG_VISBILITY) Log.v(
2304 TAG, "Making visible and scheduling visibility: " + r);
2305 try {
2306 mWindowManager.setAppVisibility(r, true);
2307 r.app.thread.scheduleWindowVisibility(r, true);
2308 r.stopFreezingScreenLocked(false);
2309 } catch (Exception e) {
2310 // Just skip on any failure; we'll make it
2311 // visible when it next restarts.
2312 Log.w(TAG, "Exception thrown making visibile: "
2313 + r.intent.getComponent(), e);
2314 }
2315 }
2316 }
2317
2318 // Aggregate current change flags.
2319 configChanges |= r.configChangeFlags;
2320
2321 if (r.fullscreen) {
2322 // At this point, nothing else needs to be shown
2323 if (DEBUG_VISBILITY) Log.v(
2324 TAG, "Stopping: fullscreen at " + r);
2325 behindFullscreen = true;
2326 i--;
2327 break;
2328 }
2329 }
2330
2331 // Now for any activities that aren't visible to the user, make
2332 // sure they no longer are keeping the screen frozen.
2333 while (i >= 0) {
2334 r = (HistoryRecord)mHistory.get(i);
2335 if (DEBUG_VISBILITY) Log.v(
2336 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2337 + " state=" + r.state
2338 + " behindFullscreen=" + behindFullscreen);
2339 if (!r.finishing) {
2340 if (behindFullscreen) {
2341 if (r.visible) {
2342 if (DEBUG_VISBILITY) Log.v(
2343 TAG, "Making invisible: " + r);
2344 r.visible = false;
2345 try {
2346 mWindowManager.setAppVisibility(r, false);
2347 if ((r.state == ActivityState.STOPPING
2348 || r.state == ActivityState.STOPPED)
2349 && r.app != null && r.app.thread != null) {
2350 if (DEBUG_VISBILITY) Log.v(
2351 TAG, "Scheduling invisibility: " + r);
2352 r.app.thread.scheduleWindowVisibility(r, false);
2353 }
2354 } catch (Exception e) {
2355 // Just skip on any failure; we'll make it
2356 // visible when it next restarts.
2357 Log.w(TAG, "Exception thrown making hidden: "
2358 + r.intent.getComponent(), e);
2359 }
2360 } else {
2361 if (DEBUG_VISBILITY) Log.v(
2362 TAG, "Already invisible: " + r);
2363 }
2364 } else if (r.fullscreen) {
2365 if (DEBUG_VISBILITY) Log.v(
2366 TAG, "Now behindFullscreen: " + r);
2367 behindFullscreen = true;
2368 }
2369 }
2370 i--;
2371 }
2372 }
2373
2374 /**
2375 * Version of ensureActivitiesVisible that can easily be called anywhere.
2376 */
2377 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2378 int configChanges) {
2379 HistoryRecord r = topRunningActivityLocked(null);
2380 if (r != null) {
2381 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2382 }
2383 }
2384
2385 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2386 if (resumed) {
2387 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2388 } else {
2389 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2390 }
2391 }
2392
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002393 private boolean startHomeActivityLocked() {
2394 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2395 && mTopAction == null) {
2396 // We are running in factory test mode, but unable to find
2397 // the factory test app, so just sit around displaying the
2398 // error message and don't try to start anything.
2399 return false;
2400 }
2401 Intent intent = new Intent(
2402 mTopAction,
2403 mTopData != null ? Uri.parse(mTopData) : null);
2404 intent.setComponent(mTopComponent);
2405 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2406 intent.addCategory(Intent.CATEGORY_HOME);
2407 }
2408 ActivityInfo aInfo =
2409 intent.resolveActivityInfo(mContext.getPackageManager(),
2410 STOCK_PM_FLAGS);
2411 if (aInfo != null) {
2412 intent.setComponent(new ComponentName(
2413 aInfo.applicationInfo.packageName, aInfo.name));
2414 // Don't do this if the home app is currently being
2415 // instrumented.
2416 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2417 aInfo.applicationInfo.uid);
2418 if (app == null || app.instrumentationClass == null) {
2419 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2420 startActivityLocked(null, intent, null, null, 0, aInfo,
2421 null, null, 0, 0, 0, false, false);
2422 }
2423 }
2424
2425
2426 return true;
2427 }
2428
2429 /**
2430 * Starts the "new version setup screen" if appropriate.
2431 */
2432 private void startSetupActivityLocked() {
2433 // Only do this once per boot.
2434 if (mCheckedForSetup) {
2435 return;
2436 }
2437
2438 // We will show this screen if the current one is a different
2439 // version than the last one shown, and we are not running in
2440 // low-level factory test mode.
2441 final ContentResolver resolver = mContext.getContentResolver();
2442 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2443 Settings.Secure.getInt(resolver,
2444 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2445 mCheckedForSetup = true;
2446
2447 // See if we should be showing the platform update setup UI.
2448 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2449 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2450 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2451
2452 // We don't allow third party apps to replace this.
2453 ResolveInfo ri = null;
2454 for (int i=0; ris != null && i<ris.size(); i++) {
2455 if ((ris.get(i).activityInfo.applicationInfo.flags
2456 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2457 ri = ris.get(i);
2458 break;
2459 }
2460 }
2461
2462 if (ri != null) {
2463 String vers = ri.activityInfo.metaData != null
2464 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2465 : null;
2466 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2467 vers = ri.activityInfo.applicationInfo.metaData.getString(
2468 Intent.METADATA_SETUP_VERSION);
2469 }
2470 String lastVers = Settings.Secure.getString(
2471 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2472 if (vers != null && !vers.equals(lastVers)) {
2473 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2474 intent.setComponent(new ComponentName(
2475 ri.activityInfo.packageName, ri.activityInfo.name));
2476 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2477 null, null, 0, 0, 0, false, false);
2478 }
2479 }
2480 }
2481 }
2482
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002483 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002484 //Log.i(TAG, "**** REPORT RESUME: " + r);
2485
2486 final int identHash = System.identityHashCode(r);
2487 updateUsageStats(r, true);
2488
2489 int i = mWatchers.beginBroadcast();
2490 while (i > 0) {
2491 i--;
2492 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2493 if (w != null) {
2494 try {
2495 w.activityResuming(identHash);
2496 } catch (RemoteException e) {
2497 }
2498 }
2499 }
2500 mWatchers.finishBroadcast();
2501 }
2502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002503 /**
2504 * Ensure that the top activity in the stack is resumed.
2505 *
2506 * @param prev The previously resumed activity, for when in the process
2507 * of pausing; can be null to call from elsewhere.
2508 *
2509 * @return Returns true if something is being resumed, or false if
2510 * nothing happened.
2511 */
2512 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2513 // Find the first activity that is not finishing.
2514 HistoryRecord next = topRunningActivityLocked(null);
2515
2516 // Remember how we'll process this pause/resume situation, and ensure
2517 // that the state is reset however we wind up proceeding.
2518 final boolean userLeaving = mUserLeaving;
2519 mUserLeaving = false;
2520
2521 if (next == null) {
2522 // There are no more activities! Let's just start up the
2523 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002524 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002525 }
2526
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002527 next.delayedResume = false;
2528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 // If the top activity is the resumed one, nothing to do.
2530 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2531 // Make sure we have executed any pending transitions, since there
2532 // should be nothing left to do at this point.
2533 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002534 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002535 return false;
2536 }
2537
2538 // If we are sleeping, and there is no resumed activity, and the top
2539 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002540 if ((mSleeping || mShuttingDown)
2541 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002542 // Make sure we have executed any pending transitions, since there
2543 // should be nothing left to do at this point.
2544 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002545 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 return false;
2547 }
2548
2549 // The activity may be waiting for stop, but that is no longer
2550 // appropriate for it.
2551 mStoppingActivities.remove(next);
2552 mWaitingVisibleActivities.remove(next);
2553
2554 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2555
2556 // If we are currently pausing an activity, then don't do anything
2557 // until that is done.
2558 if (mPausingActivity != null) {
2559 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2560 return false;
2561 }
2562
2563 // We need to start pausing the current activity so the top one
2564 // can be resumed...
2565 if (mResumedActivity != null) {
2566 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2567 startPausingLocked(userLeaving, false);
2568 return true;
2569 }
2570
2571 if (prev != null && prev != next) {
2572 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2573 prev.waitingVisible = true;
2574 mWaitingVisibleActivities.add(prev);
2575 if (DEBUG_SWITCH) Log.v(
2576 TAG, "Resuming top, waiting visible to hide: " + prev);
2577 } else {
2578 // The next activity is already visible, so hide the previous
2579 // activity's windows right now so we can show the new one ASAP.
2580 // We only do this if the previous is finishing, which should mean
2581 // it is on top of the one being resumed so hiding it quickly
2582 // is good. Otherwise, we want to do the normal route of allowing
2583 // the resumed activity to be shown so we can decide if the
2584 // previous should actually be hidden depending on whether the
2585 // new one is found to be full-screen or not.
2586 if (prev.finishing) {
2587 mWindowManager.setAppVisibility(prev, false);
2588 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2589 + prev + ", waitingVisible="
2590 + (prev != null ? prev.waitingVisible : null)
2591 + ", nowVisible=" + next.nowVisible);
2592 } else {
2593 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2594 + prev + ", waitingVisible="
2595 + (prev != null ? prev.waitingVisible : null)
2596 + ", nowVisible=" + next.nowVisible);
2597 }
2598 }
2599 }
2600
2601 // We are starting up the next activity, so tell the window manager
2602 // that the previous one will be hidden soon. This way it can know
2603 // to ignore it when computing the desired screen orientation.
2604 if (prev != null) {
2605 if (prev.finishing) {
2606 if (DEBUG_TRANSITION) Log.v(TAG,
2607 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002608 if (mNoAnimActivities.contains(prev)) {
2609 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2610 } else {
2611 mWindowManager.prepareAppTransition(prev.task == next.task
2612 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2613 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002615 mWindowManager.setAppWillBeHidden(prev);
2616 mWindowManager.setAppVisibility(prev, false);
2617 } else {
2618 if (DEBUG_TRANSITION) Log.v(TAG,
2619 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002620 if (mNoAnimActivities.contains(next)) {
2621 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2622 } else {
2623 mWindowManager.prepareAppTransition(prev.task == next.task
2624 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2625 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2626 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002627 }
2628 if (false) {
2629 mWindowManager.setAppWillBeHidden(prev);
2630 mWindowManager.setAppVisibility(prev, false);
2631 }
2632 } else if (mHistory.size() > 1) {
2633 if (DEBUG_TRANSITION) Log.v(TAG,
2634 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002635 if (mNoAnimActivities.contains(next)) {
2636 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2637 } else {
2638 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002640 }
2641
2642 if (next.app != null && next.app.thread != null) {
2643 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2644
2645 // This activity is now becoming visible.
2646 mWindowManager.setAppVisibility(next, true);
2647
2648 HistoryRecord lastResumedActivity = mResumedActivity;
2649 ActivityState lastState = next.state;
2650
2651 updateCpuStats();
2652
2653 next.state = ActivityState.RESUMED;
2654 mResumedActivity = next;
2655 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002656 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 updateLRUListLocked(next);
2658
2659 // Have the window manager re-evaluate the orientation of
2660 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002661 boolean updated;
2662 synchronized (this) {
2663 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2664 mConfiguration,
2665 next.mayFreezeScreenLocked(next.app) ? next : null);
2666 if (config != null) {
2667 /*
2668 * Explicitly restore the locale to the one from the
2669 * old configuration, since the one that comes back from
2670 * the window manager has the default (boot) locale.
2671 *
2672 * It looks like previously the locale picker only worked
2673 * by coincidence: usually it would do its setting of
2674 * the locale after the activity transition, so it didn't
2675 * matter that this lost it. With the synchronized
2676 * block now keeping them from happening at the same time,
2677 * this one always would happen second and undo what the
2678 * locale picker had just done.
2679 */
2680 config.locale = mConfiguration.locale;
2681 next.frozenBeforeDestroy = true;
2682 }
2683 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002684 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002685 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002686 // The configuration update wasn't able to keep the existing
2687 // instance of the activity, and instead started a new one.
2688 // We should be all done, but let's just make sure our activity
2689 // is still at the top and schedule another run if something
2690 // weird happened.
2691 HistoryRecord nextNext = topRunningActivityLocked(null);
2692 if (DEBUG_SWITCH) Log.i(TAG,
2693 "Activity config changed during resume: " + next
2694 + ", new next: " + nextNext);
2695 if (nextNext != next) {
2696 // Do over!
2697 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2698 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002699 setFocusedActivityLocked(next);
2700 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002701 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002702 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002703 return true;
2704 }
2705
2706 try {
2707 // Deliver all pending results.
2708 ArrayList a = next.results;
2709 if (a != null) {
2710 final int N = a.size();
2711 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002712 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002713 TAG, "Delivering results to " + next
2714 + ": " + a);
2715 next.app.thread.scheduleSendResult(next, a);
2716 }
2717 }
2718
2719 if (next.newIntents != null) {
2720 next.app.thread.scheduleNewIntent(next.newIntents, next);
2721 }
2722
Doug Zongker2bec3d42009-12-04 12:52:44 -08002723 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 System.identityHashCode(next),
2725 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726
2727 next.app.thread.scheduleResumeActivity(next,
2728 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 pauseIfSleepingLocked();
2731
2732 } catch (Exception e) {
2733 // Whoops, need to restart this activity!
2734 next.state = lastState;
2735 mResumedActivity = lastResumedActivity;
Dianne Hackborn03abb812010-01-04 18:43:19 -08002736 Log.i(TAG, "Restarting because process died: " + next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737 if (!next.hasBeenLaunched) {
2738 next.hasBeenLaunched = true;
2739 } else {
2740 if (SHOW_APP_STARTING_ICON) {
2741 mWindowManager.setAppStartingWindow(
2742 next, next.packageName, next.theme,
2743 next.nonLocalizedLabel,
2744 next.labelRes, next.icon, null, true);
2745 }
2746 }
2747 startSpecificActivityLocked(next, true, false);
2748 return true;
2749 }
2750
2751 // From this point on, if something goes wrong there is no way
2752 // to recover the activity.
2753 try {
2754 next.visible = true;
2755 completeResumeLocked(next);
2756 } catch (Exception e) {
2757 // If any exception gets thrown, toss away this
2758 // activity and try the next one.
2759 Log.w(TAG, "Exception thrown during resume of " + next, e);
2760 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2761 "resume-exception");
2762 return true;
2763 }
2764
2765 // Didn't need to use the icicle, and it is now out of date.
2766 next.icicle = null;
2767 next.haveState = false;
2768 next.stopped = false;
2769
2770 } else {
2771 // Whoops, need to restart this activity!
2772 if (!next.hasBeenLaunched) {
2773 next.hasBeenLaunched = true;
2774 } else {
2775 if (SHOW_APP_STARTING_ICON) {
2776 mWindowManager.setAppStartingWindow(
2777 next, next.packageName, next.theme,
2778 next.nonLocalizedLabel,
2779 next.labelRes, next.icon, null, true);
2780 }
2781 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2782 }
2783 startSpecificActivityLocked(next, true, true);
2784 }
2785
2786 return true;
2787 }
2788
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002789 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2790 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002791 final int NH = mHistory.size();
2792
2793 int addPos = -1;
2794
2795 if (!newTask) {
2796 // If starting in an existing task, find where that is...
2797 HistoryRecord next = null;
2798 boolean startIt = true;
2799 for (int i = NH-1; i >= 0; i--) {
2800 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2801 if (p.finishing) {
2802 continue;
2803 }
2804 if (p.task == r.task) {
2805 // Here it is! Now, if this is not yet visible to the
2806 // user, then just add it without starting; it will
2807 // get started when the user navigates back to it.
2808 addPos = i+1;
2809 if (!startIt) {
2810 mHistory.add(addPos, r);
2811 r.inHistory = true;
2812 r.task.numActivities++;
2813 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2814 r.info.screenOrientation, r.fullscreen);
2815 if (VALIDATE_TOKENS) {
2816 mWindowManager.validateAppTokens(mHistory);
2817 }
2818 return;
2819 }
2820 break;
2821 }
2822 if (p.fullscreen) {
2823 startIt = false;
2824 }
2825 next = p;
2826 }
2827 }
2828
2829 // Place a new activity at top of stack, so it is next to interact
2830 // with the user.
2831 if (addPos < 0) {
2832 addPos = mHistory.size();
2833 }
2834
2835 // If we are not placing the new activity frontmost, we do not want
2836 // to deliver the onUserLeaving callback to the actual frontmost
2837 // activity
2838 if (addPos < NH) {
2839 mUserLeaving = false;
2840 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2841 }
2842
2843 // Slot the activity into the history stack and proceed
2844 mHistory.add(addPos, r);
2845 r.inHistory = true;
2846 r.frontOfTask = newTask;
2847 r.task.numActivities++;
2848 if (NH > 0) {
2849 // We want to show the starting preview window if we are
2850 // switching to a new task, or the next activity's process is
2851 // not currently running.
2852 boolean showStartingIcon = newTask;
2853 ProcessRecord proc = r.app;
2854 if (proc == null) {
2855 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2856 }
2857 if (proc == null || proc.thread == null) {
2858 showStartingIcon = true;
2859 }
2860 if (DEBUG_TRANSITION) Log.v(TAG,
2861 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002862 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2863 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2864 mNoAnimActivities.add(r);
2865 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2866 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2867 mNoAnimActivities.remove(r);
2868 } else {
2869 mWindowManager.prepareAppTransition(newTask
2870 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2871 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2872 mNoAnimActivities.remove(r);
2873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002874 mWindowManager.addAppToken(
2875 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2876 boolean doShow = true;
2877 if (newTask) {
2878 // Even though this activity is starting fresh, we still need
2879 // to reset it to make sure we apply affinities to move any
2880 // existing activities from other tasks in to it.
2881 // If the caller has requested that the target task be
2882 // reset, then do so.
2883 if ((r.intent.getFlags()
2884 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2885 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002886 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002887 }
2888 }
2889 if (SHOW_APP_STARTING_ICON && doShow) {
2890 // Figure out if we are transitioning from another activity that is
2891 // "has the same starting icon" as the next one. This allows the
2892 // window manager to keep the previous window it had previously
2893 // created, if it still had one.
2894 HistoryRecord prev = mResumedActivity;
2895 if (prev != null) {
2896 // We don't want to reuse the previous starting preview if:
2897 // (1) The current activity is in a different task.
2898 if (prev.task != r.task) prev = null;
2899 // (2) The current activity is already displayed.
2900 else if (prev.nowVisible) prev = null;
2901 }
2902 mWindowManager.setAppStartingWindow(
2903 r, r.packageName, r.theme, r.nonLocalizedLabel,
2904 r.labelRes, r.icon, prev, showStartingIcon);
2905 }
2906 } else {
2907 // If this is the first activity, don't do any fancy animations,
2908 // because there is nothing for it to animate on top of.
2909 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2910 r.info.screenOrientation, r.fullscreen);
2911 }
2912 if (VALIDATE_TOKENS) {
2913 mWindowManager.validateAppTokens(mHistory);
2914 }
2915
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002916 if (doResume) {
2917 resumeTopActivityLocked(null);
2918 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002919 }
2920
2921 /**
2922 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002923 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2924 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925 * an instance of that activity in the stack and, if found, finish all
2926 * activities on top of it and return the instance.
2927 *
2928 * @param newR Description of the new activity being started.
2929 * @return Returns the old activity that should be continue to be used,
2930 * or null if none was found.
2931 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002932 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002933 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002934 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002935
2936 // First find the requested task.
2937 while (i > 0) {
2938 i--;
2939 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2940 if (r.task.taskId == taskId) {
2941 i++;
2942 break;
2943 }
2944 }
2945
2946 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002947 while (i > 0) {
2948 i--;
2949 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2950 if (r.finishing) {
2951 continue;
2952 }
2953 if (r.task.taskId != taskId) {
2954 return null;
2955 }
2956 if (r.realActivity.equals(newR.realActivity)) {
2957 // Here it is! Now finish everything in front...
2958 HistoryRecord ret = r;
2959 if (doClear) {
2960 while (i < (mHistory.size()-1)) {
2961 i++;
2962 r = (HistoryRecord)mHistory.get(i);
2963 if (r.finishing) {
2964 continue;
2965 }
2966 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2967 null, "clear")) {
2968 i--;
2969 }
2970 }
2971 }
2972
2973 // Finally, if this is a normal launch mode (that is, not
2974 // expecting onNewIntent()), then we will finish the current
2975 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002976 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2977 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002978 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002979 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 if (index >= 0) {
2981 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2982 null, "clear");
2983 }
2984 return null;
2985 }
2986 }
2987
2988 return ret;
2989 }
2990 }
2991
2992 return null;
2993 }
2994
2995 /**
2996 * Find the activity in the history stack within the given task. Returns
2997 * the index within the history at which it's found, or < 0 if not found.
2998 */
2999 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3000 int i = mHistory.size();
3001 while (i > 0) {
3002 i--;
3003 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3004 if (candidate.task.taskId != task) {
3005 break;
3006 }
3007 if (candidate.realActivity.equals(r.realActivity)) {
3008 return i;
3009 }
3010 }
3011
3012 return -1;
3013 }
3014
3015 /**
3016 * Reorder the history stack so that the activity at the given index is
3017 * brought to the front.
3018 */
3019 private final HistoryRecord moveActivityToFrontLocked(int where) {
3020 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3021 int top = mHistory.size();
3022 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3023 mHistory.add(top, newTop);
3024 oldTop.frontOfTask = false;
3025 newTop.frontOfTask = true;
3026 return newTop;
3027 }
3028
3029 /**
3030 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3031 * method will be called at the proper time.
3032 */
3033 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3034 boolean sent = false;
3035 if (r.state == ActivityState.RESUMED
3036 && r.app != null && r.app.thread != null) {
3037 try {
3038 ArrayList<Intent> ar = new ArrayList<Intent>();
3039 ar.add(new Intent(intent));
3040 r.app.thread.scheduleNewIntent(ar, r);
3041 sent = true;
3042 } catch (Exception e) {
3043 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3044 }
3045 }
3046 if (!sent) {
3047 r.addNewIntentLocked(new Intent(intent));
3048 }
3049 }
3050
3051 private final void logStartActivity(int tag, HistoryRecord r,
3052 TaskRecord task) {
3053 EventLog.writeEvent(tag,
3054 System.identityHashCode(r), task.taskId,
3055 r.shortComponentName, r.intent.getAction(),
3056 r.intent.getType(), r.intent.getDataString(),
3057 r.intent.getFlags());
3058 }
3059
3060 private final int startActivityLocked(IApplicationThread caller,
3061 Intent intent, String resolvedType,
3062 Uri[] grantedUriPermissions,
3063 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3064 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003065 int callingPid, int callingUid, boolean onlyIfNeeded,
3066 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003067 Log.i(TAG, "Starting activity: " + intent);
3068
3069 HistoryRecord sourceRecord = null;
3070 HistoryRecord resultRecord = null;
3071 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003072 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003073 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3075 if (index >= 0) {
3076 sourceRecord = (HistoryRecord)mHistory.get(index);
3077 if (requestCode >= 0 && !sourceRecord.finishing) {
3078 resultRecord = sourceRecord;
3079 }
3080 }
3081 }
3082
3083 int launchFlags = intent.getFlags();
3084
3085 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3086 && sourceRecord != null) {
3087 // Transfer the result target from the source activity to the new
3088 // one being started, including any failures.
3089 if (requestCode >= 0) {
3090 return START_FORWARD_AND_REQUEST_CONFLICT;
3091 }
3092 resultRecord = sourceRecord.resultTo;
3093 resultWho = sourceRecord.resultWho;
3094 requestCode = sourceRecord.requestCode;
3095 sourceRecord.resultTo = null;
3096 if (resultRecord != null) {
3097 resultRecord.removeResultsLocked(
3098 sourceRecord, resultWho, requestCode);
3099 }
3100 }
3101
3102 int err = START_SUCCESS;
3103
3104 if (intent.getComponent() == null) {
3105 // We couldn't find a class that can handle the given Intent.
3106 // That's the end of that!
3107 err = START_INTENT_NOT_RESOLVED;
3108 }
3109
3110 if (err == START_SUCCESS && aInfo == null) {
3111 // We couldn't find the specific class specified in the Intent.
3112 // Also the end of the line.
3113 err = START_CLASS_NOT_FOUND;
3114 }
3115
3116 ProcessRecord callerApp = null;
3117 if (err == START_SUCCESS && caller != null) {
3118 callerApp = getRecordForAppLocked(caller);
3119 if (callerApp != null) {
3120 callingPid = callerApp.pid;
3121 callingUid = callerApp.info.uid;
3122 } else {
3123 Log.w(TAG, "Unable to find app for caller " + caller
3124 + " (pid=" + callingPid + ") when starting: "
3125 + intent.toString());
3126 err = START_PERMISSION_DENIED;
3127 }
3128 }
3129
3130 if (err != START_SUCCESS) {
3131 if (resultRecord != null) {
3132 sendActivityResultLocked(-1,
3133 resultRecord, resultWho, requestCode,
3134 Activity.RESULT_CANCELED, null);
3135 }
3136 return err;
3137 }
3138
3139 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3140 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3141 if (perm != PackageManager.PERMISSION_GRANTED) {
3142 if (resultRecord != null) {
3143 sendActivityResultLocked(-1,
3144 resultRecord, resultWho, requestCode,
3145 Activity.RESULT_CANCELED, null);
3146 }
3147 String msg = "Permission Denial: starting " + intent.toString()
3148 + " from " + callerApp + " (pid=" + callingPid
3149 + ", uid=" + callingUid + ")"
3150 + " requires " + aInfo.permission;
3151 Log.w(TAG, msg);
3152 throw new SecurityException(msg);
3153 }
3154
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003155 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003156 boolean abort = false;
3157 try {
3158 // The Intent we give to the watcher has the extra data
3159 // stripped off, since it can contain private information.
3160 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003161 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003162 aInfo.applicationInfo.packageName);
3163 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003164 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003165 }
3166
3167 if (abort) {
3168 if (resultRecord != null) {
3169 sendActivityResultLocked(-1,
3170 resultRecord, resultWho, requestCode,
3171 Activity.RESULT_CANCELED, null);
3172 }
3173 // We pretend to the caller that it was really started, but
3174 // they will just get a cancel result.
3175 return START_SUCCESS;
3176 }
3177 }
3178
3179 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3180 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003181 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003183 if (mResumedActivity == null
3184 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3185 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3186 PendingActivityLaunch pal = new PendingActivityLaunch();
3187 pal.r = r;
3188 pal.sourceRecord = sourceRecord;
3189 pal.grantedUriPermissions = grantedUriPermissions;
3190 pal.grantedMode = grantedMode;
3191 pal.onlyIfNeeded = onlyIfNeeded;
3192 mPendingActivityLaunches.add(pal);
3193 return START_SWITCHES_CANCELED;
3194 }
3195 }
3196
3197 if (mDidAppSwitch) {
3198 // This is the second allowed switch since we stopped switches,
3199 // so now just generally allow switches. Use case: user presses
3200 // home (switches disabled, switch to home, mDidAppSwitch now true);
3201 // user taps a home icon (coming from home so allowed, we hit here
3202 // and now allow anyone to switch again).
3203 mAppSwitchesAllowedTime = 0;
3204 } else {
3205 mDidAppSwitch = true;
3206 }
3207
3208 doPendingActivityLaunchesLocked(false);
3209
3210 return startActivityUncheckedLocked(r, sourceRecord,
3211 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3212 }
3213
3214 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3215 final int N = mPendingActivityLaunches.size();
3216 if (N <= 0) {
3217 return;
3218 }
3219 for (int i=0; i<N; i++) {
3220 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3221 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3222 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3223 doResume && i == (N-1));
3224 }
3225 mPendingActivityLaunches.clear();
3226 }
3227
3228 private final int startActivityUncheckedLocked(HistoryRecord r,
3229 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3230 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3231 final Intent intent = r.intent;
3232 final int callingUid = r.launchedFromUid;
3233
3234 int launchFlags = intent.getFlags();
3235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 // We'll invoke onUserLeaving before onPause only if the launching
3237 // activity did not explicitly state that this is an automated launch.
3238 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3239 if (DEBUG_USER_LEAVING) Log.v(TAG,
3240 "startActivity() => mUserLeaving=" + mUserLeaving);
3241
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003242 // If the caller has asked not to resume at this point, we make note
3243 // of this in the record so that we can skip it when trying to find
3244 // the top running activity.
3245 if (!doResume) {
3246 r.delayedResume = true;
3247 }
3248
3249 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3250 != 0 ? r : null;
3251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003252 // If the onlyIfNeeded flag is set, then we can do this if the activity
3253 // being launched is the same as the one making the call... or, as
3254 // a special case, if we do not know the caller then we count the
3255 // current top activity as the caller.
3256 if (onlyIfNeeded) {
3257 HistoryRecord checkedCaller = sourceRecord;
3258 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003259 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003260 }
3261 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3262 // Caller is not the same as launcher, so always needed.
3263 onlyIfNeeded = false;
3264 }
3265 }
3266
3267 if (grantedUriPermissions != null && callingUid > 0) {
3268 for (int i=0; i<grantedUriPermissions.length; i++) {
3269 grantUriPermissionLocked(callingUid, r.packageName,
3270 grantedUriPermissions[i], grantedMode, r);
3271 }
3272 }
3273
3274 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3275 intent, r);
3276
3277 if (sourceRecord == null) {
3278 // This activity is not being started from another... in this
3279 // case we -always- start a new task.
3280 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3281 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3282 + intent);
3283 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3284 }
3285 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3286 // The original activity who is starting us is running as a single
3287 // instance... this new activity it is starting must go on its
3288 // own task.
3289 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3290 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3291 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3292 // The activity being started is a single instance... it always
3293 // gets launched into its own task.
3294 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3295 }
3296
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003297 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003298 // For whatever reason this activity is being launched into a new
3299 // task... yet the caller has requested a result back. Well, that
3300 // is pretty messed up, so instead immediately send back a cancel
3301 // and let the new task continue launched as normal without a
3302 // dependency on its originator.
3303 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3304 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003305 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003306 Activity.RESULT_CANCELED, null);
3307 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003308 }
3309
3310 boolean addingToTask = false;
3311 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3312 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3313 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3314 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3315 // If bring to front is requested, and no result is requested, and
3316 // we can find a task that was started with this same
3317 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003318 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 // See if there is a task to bring to the front. If this is
3320 // a SINGLE_INSTANCE activity, there can be one and only one
3321 // instance of it in the history, and it is always in its own
3322 // unique task, so we do a special search.
3323 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3324 ? findTaskLocked(intent, r.info)
3325 : findActivityLocked(intent, r.info);
3326 if (taskTop != null) {
3327 if (taskTop.task.intent == null) {
3328 // This task was started because of movement of
3329 // the activity based on affinity... now that we
3330 // are actually launching it, we can assign the
3331 // base intent.
3332 taskTop.task.setIntent(intent, r.info);
3333 }
3334 // If the target task is not in the front, then we need
3335 // to bring it to the front... except... well, with
3336 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3337 // to have the same behavior as if a new instance was
3338 // being started, which means not bringing it to the front
3339 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003340 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003341 if (curTop.task != taskTop.task) {
3342 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3343 boolean callerAtFront = sourceRecord == null
3344 || curTop.task == sourceRecord.task;
3345 if (callerAtFront) {
3346 // We really do want to push this one into the
3347 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003348 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003349 }
3350 }
3351 // If the caller has requested that the target task be
3352 // reset, then do so.
3353 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3354 taskTop = resetTaskIfNeededLocked(taskTop, r);
3355 }
3356 if (onlyIfNeeded) {
3357 // We don't need to start a new activity, and
3358 // the client said not to do anything if that
3359 // is the case, so this is it! And for paranoia, make
3360 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003361 if (doResume) {
3362 resumeTopActivityLocked(null);
3363 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 return START_RETURN_INTENT_TO_CALLER;
3365 }
3366 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3367 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3368 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3369 // In this situation we want to remove all activities
3370 // from the task up to the one being started. In most
3371 // cases this means we are resetting the task to its
3372 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003373 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003374 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003375 if (top != null) {
3376 if (top.frontOfTask) {
3377 // Activity aliases may mean we use different
3378 // intents for the top activity, so make sure
3379 // the task now has the identity of the new
3380 // intent.
3381 top.task.setIntent(r.intent, r.info);
3382 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003383 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003384 deliverNewIntentLocked(top, r.intent);
3385 } else {
3386 // A special case: we need to
3387 // start the activity because it is not currently
3388 // running, and the caller has asked to clear the
3389 // current task to have this activity at the top.
3390 addingToTask = true;
3391 // Now pretend like this activity is being started
3392 // by the top of its task, so it is put in the
3393 // right place.
3394 sourceRecord = taskTop;
3395 }
3396 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3397 // In this case the top activity on the task is the
3398 // same as the one being launched, so we take that
3399 // as a request to bring the task to the foreground.
3400 // If the top activity in the task is the root
3401 // activity, deliver this new intent to it if it
3402 // desires.
3403 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3404 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003405 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003406 if (taskTop.frontOfTask) {
3407 taskTop.task.setIntent(r.intent, r.info);
3408 }
3409 deliverNewIntentLocked(taskTop, r.intent);
3410 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3411 // In this case we are launching the root activity
3412 // of the task, but with a different intent. We
3413 // should start a new instance on top.
3414 addingToTask = true;
3415 sourceRecord = taskTop;
3416 }
3417 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3418 // In this case an activity is being launched in to an
3419 // existing task, without resetting that task. This
3420 // is typically the situation of launching an activity
3421 // from a notification or shortcut. We want to place
3422 // the new activity on top of the current task.
3423 addingToTask = true;
3424 sourceRecord = taskTop;
3425 } else if (!taskTop.task.rootWasReset) {
3426 // In this case we are launching in to an existing task
3427 // that has not yet been started from its front door.
3428 // The current task has been brought to the front.
3429 // Ideally, we'd probably like to place this new task
3430 // at the bottom of its stack, but that's a little hard
3431 // to do with the current organization of the code so
3432 // for now we'll just drop it.
3433 taskTop.task.setIntent(r.intent, r.info);
3434 }
3435 if (!addingToTask) {
3436 // We didn't do anything... but it was needed (a.k.a., client
3437 // don't use that intent!) And for paranoia, make
3438 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003439 if (doResume) {
3440 resumeTopActivityLocked(null);
3441 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003442 return START_TASK_TO_FRONT;
3443 }
3444 }
3445 }
3446 }
3447
3448 //String uri = r.intent.toURI();
3449 //Intent intent2 = new Intent(uri);
3450 //Log.i(TAG, "Given intent: " + r.intent);
3451 //Log.i(TAG, "URI is: " + uri);
3452 //Log.i(TAG, "To intent: " + intent2);
3453
3454 if (r.packageName != null) {
3455 // If the activity being launched is the same as the one currently
3456 // at the top, then we need to check if it should only be launched
3457 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003458 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3459 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 if (top.realActivity.equals(r.realActivity)) {
3461 if (top.app != null && top.app.thread != null) {
3462 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3463 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3464 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003465 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003466 // For paranoia, make sure we have correctly
3467 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003468 if (doResume) {
3469 resumeTopActivityLocked(null);
3470 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003471 if (onlyIfNeeded) {
3472 // We don't need to start a new activity, and
3473 // the client said not to do anything if that
3474 // is the case, so this is it!
3475 return START_RETURN_INTENT_TO_CALLER;
3476 }
3477 deliverNewIntentLocked(top, r.intent);
3478 return START_DELIVERED_TO_TOP;
3479 }
3480 }
3481 }
3482 }
3483
3484 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003485 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003487 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 Activity.RESULT_CANCELED, null);
3489 }
3490 return START_CLASS_NOT_FOUND;
3491 }
3492
3493 boolean newTask = false;
3494
3495 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003496 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003497 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3498 // todo: should do better management of integers.
3499 mCurTask++;
3500 if (mCurTask <= 0) {
3501 mCurTask = 1;
3502 }
3503 r.task = new TaskRecord(mCurTask, r.info, intent,
3504 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3505 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3506 + " in new task " + r.task);
3507 newTask = true;
3508 addRecentTask(r.task);
3509
3510 } else if (sourceRecord != null) {
3511 if (!addingToTask &&
3512 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3513 // In this case, we are adding the activity to an existing
3514 // task, but the caller has asked to clear that task if the
3515 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003516 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003517 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003518 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003519 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 deliverNewIntentLocked(top, r.intent);
3521 // For paranoia, make sure we have correctly
3522 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003523 if (doResume) {
3524 resumeTopActivityLocked(null);
3525 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003526 return START_DELIVERED_TO_TOP;
3527 }
3528 } else if (!addingToTask &&
3529 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3530 // In this case, we are launching an activity in our own task
3531 // that may already be running somewhere in the history, and
3532 // we want to shuffle it to the front of the stack if so.
3533 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3534 if (where >= 0) {
3535 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003536 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003537 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003538 if (doResume) {
3539 resumeTopActivityLocked(null);
3540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003541 return START_DELIVERED_TO_TOP;
3542 }
3543 }
3544 // An existing activity is starting this new activity, so we want
3545 // to keep the new one in the same task as the one that is starting
3546 // it.
3547 r.task = sourceRecord.task;
3548 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3549 + " in existing task " + r.task);
3550
3551 } else {
3552 // This not being started from an existing activity, and not part
3553 // of a new task... just put it in the top task, though these days
3554 // this case should never happen.
3555 final int N = mHistory.size();
3556 HistoryRecord prev =
3557 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3558 r.task = prev != null
3559 ? prev.task
3560 : new TaskRecord(mCurTask, r.info, intent,
3561 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3562 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3563 + " in new guessed " + r.task);
3564 }
3565 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003566 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003567 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003568 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003569 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003570 return START_SUCCESS;
3571 }
3572
3573 public final int startActivity(IApplicationThread caller,
3574 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3575 int grantedMode, IBinder resultTo,
3576 String resultWho, int requestCode, boolean onlyIfNeeded,
3577 boolean debug) {
3578 // Refuse possible leaked file descriptors
3579 if (intent != null && intent.hasFileDescriptors()) {
3580 throw new IllegalArgumentException("File descriptors passed in Intent");
3581 }
3582
The Android Open Source Project4df24232009-03-05 14:34:35 -08003583 final boolean componentSpecified = intent.getComponent() != null;
3584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003585 // Don't modify the client's object!
3586 intent = new Intent(intent);
3587
3588 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003589 ActivityInfo aInfo;
3590 try {
3591 ResolveInfo rInfo =
3592 ActivityThread.getPackageManager().resolveIntent(
3593 intent, resolvedType,
3594 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003595 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003596 aInfo = rInfo != null ? rInfo.activityInfo : null;
3597 } catch (RemoteException e) {
3598 aInfo = null;
3599 }
3600
3601 if (aInfo != null) {
3602 // Store the found target back into the intent, because now that
3603 // we have it we never want to do this again. For example, if the
3604 // user navigates back to this point in the history, we should
3605 // always restart the exact same activity.
3606 intent.setComponent(new ComponentName(
3607 aInfo.applicationInfo.packageName, aInfo.name));
3608
3609 // Don't debug things in the system process
3610 if (debug) {
3611 if (!aInfo.processName.equals("system")) {
3612 setDebugApp(aInfo.processName, true, false);
3613 }
3614 }
3615 }
3616
3617 synchronized(this) {
3618 final long origId = Binder.clearCallingIdentity();
3619 int res = startActivityLocked(caller, intent, resolvedType,
3620 grantedUriPermissions, grantedMode, aInfo,
3621 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003622 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003623 Binder.restoreCallingIdentity(origId);
3624 return res;
3625 }
3626 }
3627
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003628 public int startActivityIntentSender(IApplicationThread caller,
3629 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003630 IBinder resultTo, String resultWho, int requestCode,
3631 int flagsMask, int flagsValues) {
3632 // Refuse possible leaked file descriptors
3633 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3634 throw new IllegalArgumentException("File descriptors passed in Intent");
3635 }
3636
3637 IIntentSender sender = intent.getTarget();
3638 if (!(sender instanceof PendingIntentRecord)) {
3639 throw new IllegalArgumentException("Bad PendingIntent object");
3640 }
3641
3642 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003643
3644 synchronized (this) {
3645 // If this is coming from the currently resumed activity, it is
3646 // effectively saying that app switches are allowed at this point.
3647 if (mResumedActivity != null
3648 && mResumedActivity.info.applicationInfo.uid ==
3649 Binder.getCallingUid()) {
3650 mAppSwitchesAllowedTime = 0;
3651 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003652 }
3653
3654 return pir.sendInner(0, fillInIntent, resolvedType,
3655 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3656 }
3657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003658 public boolean startNextMatchingActivity(IBinder callingActivity,
3659 Intent intent) {
3660 // Refuse possible leaked file descriptors
3661 if (intent != null && intent.hasFileDescriptors() == true) {
3662 throw new IllegalArgumentException("File descriptors passed in Intent");
3663 }
3664
3665 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003666 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003667 if (index < 0) {
3668 return false;
3669 }
3670 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3671 if (r.app == null || r.app.thread == null) {
3672 // The caller is not running... d'oh!
3673 return false;
3674 }
3675 intent = new Intent(intent);
3676 // The caller is not allowed to change the data.
3677 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3678 // And we are resetting to find the next component...
3679 intent.setComponent(null);
3680
3681 ActivityInfo aInfo = null;
3682 try {
3683 List<ResolveInfo> resolves =
3684 ActivityThread.getPackageManager().queryIntentActivities(
3685 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003686 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003687
3688 // Look for the original activity in the list...
3689 final int N = resolves != null ? resolves.size() : 0;
3690 for (int i=0; i<N; i++) {
3691 ResolveInfo rInfo = resolves.get(i);
3692 if (rInfo.activityInfo.packageName.equals(r.packageName)
3693 && rInfo.activityInfo.name.equals(r.info.name)) {
3694 // We found the current one... the next matching is
3695 // after it.
3696 i++;
3697 if (i<N) {
3698 aInfo = resolves.get(i).activityInfo;
3699 }
3700 break;
3701 }
3702 }
3703 } catch (RemoteException e) {
3704 }
3705
3706 if (aInfo == null) {
3707 // Nobody who is next!
3708 return false;
3709 }
3710
3711 intent.setComponent(new ComponentName(
3712 aInfo.applicationInfo.packageName, aInfo.name));
3713 intent.setFlags(intent.getFlags()&~(
3714 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3715 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3716 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3717 Intent.FLAG_ACTIVITY_NEW_TASK));
3718
3719 // Okay now we need to start the new activity, replacing the
3720 // currently running activity. This is a little tricky because
3721 // we want to start the new one as if the current one is finished,
3722 // but not finish the current one first so that there is no flicker.
3723 // And thus...
3724 final boolean wasFinishing = r.finishing;
3725 r.finishing = true;
3726
3727 // Propagate reply information over to the new activity.
3728 final HistoryRecord resultTo = r.resultTo;
3729 final String resultWho = r.resultWho;
3730 final int requestCode = r.requestCode;
3731 r.resultTo = null;
3732 if (resultTo != null) {
3733 resultTo.removeResultsLocked(r, resultWho, requestCode);
3734 }
3735
3736 final long origId = Binder.clearCallingIdentity();
3737 // XXX we are not dealing with propagating grantedUriPermissions...
3738 // those are not yet exposed to user code, so there is no need.
3739 int res = startActivityLocked(r.app.thread, intent,
3740 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003741 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003742 Binder.restoreCallingIdentity(origId);
3743
3744 r.finishing = wasFinishing;
3745 if (res != START_SUCCESS) {
3746 return false;
3747 }
3748 return true;
3749 }
3750 }
3751
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003752 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003753 Intent intent, String resolvedType, IBinder resultTo,
3754 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003755
3756 // This is so super not safe, that only the system (or okay root)
3757 // can do it.
3758 final int callingUid = Binder.getCallingUid();
3759 if (callingUid != 0 && callingUid != Process.myUid()) {
3760 throw new SecurityException(
3761 "startActivityInPackage only available to the system");
3762 }
3763
The Android Open Source Project4df24232009-03-05 14:34:35 -08003764 final boolean componentSpecified = intent.getComponent() != null;
3765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003766 // Don't modify the client's object!
3767 intent = new Intent(intent);
3768
3769 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003770 ActivityInfo aInfo;
3771 try {
3772 ResolveInfo rInfo =
3773 ActivityThread.getPackageManager().resolveIntent(
3774 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003775 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003776 aInfo = rInfo != null ? rInfo.activityInfo : null;
3777 } catch (RemoteException e) {
3778 aInfo = null;
3779 }
3780
3781 if (aInfo != null) {
3782 // Store the found target back into the intent, because now that
3783 // we have it we never want to do this again. For example, if the
3784 // user navigates back to this point in the history, we should
3785 // always restart the exact same activity.
3786 intent.setComponent(new ComponentName(
3787 aInfo.applicationInfo.packageName, aInfo.name));
3788 }
3789
3790 synchronized(this) {
3791 return startActivityLocked(null, intent, resolvedType,
3792 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003793 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794 }
3795 }
3796
3797 private final void addRecentTask(TaskRecord task) {
3798 // Remove any existing entries that are the same kind of task.
3799 int N = mRecentTasks.size();
3800 for (int i=0; i<N; i++) {
3801 TaskRecord tr = mRecentTasks.get(i);
3802 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3803 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3804 mRecentTasks.remove(i);
3805 i--;
3806 N--;
3807 if (task.intent == null) {
3808 // If the new recent task we are adding is not fully
3809 // specified, then replace it with the existing recent task.
3810 task = tr;
3811 }
3812 }
3813 }
3814 if (N >= MAX_RECENT_TASKS) {
3815 mRecentTasks.remove(N-1);
3816 }
3817 mRecentTasks.add(0, task);
3818 }
3819
3820 public void setRequestedOrientation(IBinder token,
3821 int requestedOrientation) {
3822 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003823 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003824 if (index < 0) {
3825 return;
3826 }
3827 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3828 final long origId = Binder.clearCallingIdentity();
3829 mWindowManager.setAppOrientation(r, requestedOrientation);
3830 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003831 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003832 r.mayFreezeScreenLocked(r.app) ? r : null);
3833 if (config != null) {
3834 r.frozenBeforeDestroy = true;
3835 if (!updateConfigurationLocked(config, r)) {
3836 resumeTopActivityLocked(null);
3837 }
3838 }
3839 Binder.restoreCallingIdentity(origId);
3840 }
3841 }
3842
3843 public int getRequestedOrientation(IBinder token) {
3844 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003845 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003846 if (index < 0) {
3847 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3848 }
3849 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3850 return mWindowManager.getAppOrientation(r);
3851 }
3852 }
3853
3854 private final void stopActivityLocked(HistoryRecord r) {
3855 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3856 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3857 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3858 if (!r.finishing) {
3859 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3860 "no-history");
3861 }
3862 } else if (r.app != null && r.app.thread != null) {
3863 if (mFocusedActivity == r) {
3864 setFocusedActivityLocked(topRunningActivityLocked(null));
3865 }
3866 r.resumeKeyDispatchingLocked();
3867 try {
3868 r.stopped = false;
3869 r.state = ActivityState.STOPPING;
3870 if (DEBUG_VISBILITY) Log.v(
3871 TAG, "Stopping visible=" + r.visible + " for " + r);
3872 if (!r.visible) {
3873 mWindowManager.setAppVisibility(r, false);
3874 }
3875 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3876 } catch (Exception e) {
3877 // Maybe just ignore exceptions here... if the process
3878 // has crashed, our death notification will clean things
3879 // up.
3880 Log.w(TAG, "Exception thrown during pause", e);
3881 // Just in case, assume it to be stopped.
3882 r.stopped = true;
3883 r.state = ActivityState.STOPPED;
3884 if (r.configDestroy) {
3885 destroyActivityLocked(r, true);
3886 }
3887 }
3888 }
3889 }
3890
3891 /**
3892 * @return Returns true if the activity is being finished, false if for
3893 * some reason it is being left as-is.
3894 */
3895 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3896 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003897 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003898 TAG, "Finishing activity: token=" + token
3899 + ", result=" + resultCode + ", data=" + resultData);
3900
Dianne Hackborn75b03852009-06-12 15:43:26 -07003901 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003902 if (index < 0) {
3903 return false;
3904 }
3905 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3906
3907 // Is this the last activity left?
3908 boolean lastActivity = true;
3909 for (int i=mHistory.size()-1; i>=0; i--) {
3910 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3911 if (!p.finishing && p != r) {
3912 lastActivity = false;
3913 break;
3914 }
3915 }
3916
3917 // If this is the last activity, but it is the home activity, then
3918 // just don't finish it.
3919 if (lastActivity) {
3920 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3921 return false;
3922 }
3923 }
3924
3925 finishActivityLocked(r, index, resultCode, resultData, reason);
3926 return true;
3927 }
3928
3929 /**
3930 * @return Returns true if this activity has been removed from the history
3931 * list, or false if it is still in the list and will be removed later.
3932 */
3933 private final boolean finishActivityLocked(HistoryRecord r, int index,
3934 int resultCode, Intent resultData, String reason) {
3935 if (r.finishing) {
3936 Log.w(TAG, "Duplicate finish request for " + r);
3937 return false;
3938 }
3939
3940 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003941 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003942 System.identityHashCode(r),
3943 r.task.taskId, r.shortComponentName, reason);
3944 r.task.numActivities--;
3945 if (r.frontOfTask && index < (mHistory.size()-1)) {
3946 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3947 if (next.task == r.task) {
3948 next.frontOfTask = true;
3949 }
3950 }
3951
3952 r.pauseKeyDispatchingLocked();
3953 if (mFocusedActivity == r) {
3954 setFocusedActivityLocked(topRunningActivityLocked(null));
3955 }
3956
3957 // send the result
3958 HistoryRecord resultTo = r.resultTo;
3959 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003960 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3961 + " who=" + r.resultWho + " req=" + r.requestCode
3962 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003963 if (r.info.applicationInfo.uid > 0) {
3964 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3965 r.packageName, resultData, r);
3966 }
3967 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3968 resultData);
3969 r.resultTo = null;
3970 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003971 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003972
3973 // Make sure this HistoryRecord is not holding on to other resources,
3974 // because clients have remote IPC references to this object so we
3975 // can't assume that will go away and want to avoid circular IPC refs.
3976 r.results = null;
3977 r.pendingResults = null;
3978 r.newIntents = null;
3979 r.icicle = null;
3980
3981 if (mPendingThumbnails.size() > 0) {
3982 // There are clients waiting to receive thumbnails so, in case
3983 // this is an activity that someone is waiting for, add it
3984 // to the pending list so we can correctly update the clients.
3985 mCancelledThumbnails.add(r);
3986 }
3987
3988 if (mResumedActivity == r) {
3989 boolean endTask = index <= 0
3990 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3991 if (DEBUG_TRANSITION) Log.v(TAG,
3992 "Prepare close transition: finishing " + r);
3993 mWindowManager.prepareAppTransition(endTask
3994 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3995 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3996
3997 // Tell window manager to prepare for this one to be removed.
3998 mWindowManager.setAppVisibility(r, false);
3999
4000 if (mPausingActivity == null) {
4001 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4002 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4003 startPausingLocked(false, false);
4004 }
4005
4006 } else if (r.state != ActivityState.PAUSING) {
4007 // If the activity is PAUSING, we will complete the finish once
4008 // it is done pausing; else we can just directly finish it here.
4009 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4010 return finishCurrentActivityLocked(r, index,
4011 FINISH_AFTER_PAUSE) == null;
4012 } else {
4013 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4014 }
4015
4016 return false;
4017 }
4018
4019 private static final int FINISH_IMMEDIATELY = 0;
4020 private static final int FINISH_AFTER_PAUSE = 1;
4021 private static final int FINISH_AFTER_VISIBLE = 2;
4022
4023 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4024 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004025 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004026 if (index < 0) {
4027 return null;
4028 }
4029
4030 return finishCurrentActivityLocked(r, index, mode);
4031 }
4032
4033 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4034 int index, int mode) {
4035 // First things first: if this activity is currently visible,
4036 // and the resumed activity is not yet visible, then hold off on
4037 // finishing until the resumed one becomes visible.
4038 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4039 if (!mStoppingActivities.contains(r)) {
4040 mStoppingActivities.add(r);
4041 if (mStoppingActivities.size() > 3) {
4042 // If we already have a few activities waiting to stop,
4043 // then give up on things going idle and start clearing
4044 // them out.
4045 Message msg = Message.obtain();
4046 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4047 mHandler.sendMessage(msg);
4048 }
4049 }
4050 r.state = ActivityState.STOPPING;
4051 updateOomAdjLocked();
4052 return r;
4053 }
4054
4055 // make sure the record is cleaned out of other places.
4056 mStoppingActivities.remove(r);
4057 mWaitingVisibleActivities.remove(r);
4058 if (mResumedActivity == r) {
4059 mResumedActivity = null;
4060 }
4061 final ActivityState prevState = r.state;
4062 r.state = ActivityState.FINISHING;
4063
4064 if (mode == FINISH_IMMEDIATELY
4065 || prevState == ActivityState.STOPPED
4066 || prevState == ActivityState.INITIALIZING) {
4067 // If this activity is already stopped, we can just finish
4068 // it right now.
4069 return destroyActivityLocked(r, true) ? null : r;
4070 } else {
4071 // Need to go through the full pause cycle to get this
4072 // activity into the stopped state and then finish it.
4073 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4074 mFinishingActivities.add(r);
4075 resumeTopActivityLocked(null);
4076 }
4077 return r;
4078 }
4079
4080 /**
4081 * This is the internal entry point for handling Activity.finish().
4082 *
4083 * @param token The Binder token referencing the Activity we want to finish.
4084 * @param resultCode Result code, if any, from this Activity.
4085 * @param resultData Result data (Intent), if any, from this Activity.
4086 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004087 * @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 -08004088 */
4089 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4090 // Refuse possible leaked file descriptors
4091 if (resultData != null && resultData.hasFileDescriptors() == true) {
4092 throw new IllegalArgumentException("File descriptors passed in Intent");
4093 }
4094
4095 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004096 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004097 // Find the first activity that is not finishing.
4098 HistoryRecord next = topRunningActivityLocked(token, 0);
4099 if (next != null) {
4100 // ask watcher if this is allowed
4101 boolean resumeOK = true;
4102 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004103 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004104 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004105 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004106 }
4107
4108 if (!resumeOK) {
4109 return false;
4110 }
4111 }
4112 }
4113 final long origId = Binder.clearCallingIdentity();
4114 boolean res = requestFinishActivityLocked(token, resultCode,
4115 resultData, "app-request");
4116 Binder.restoreCallingIdentity(origId);
4117 return res;
4118 }
4119 }
4120
4121 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4122 String resultWho, int requestCode, int resultCode, Intent data) {
4123
4124 if (callingUid > 0) {
4125 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4126 data, r);
4127 }
4128
The Android Open Source Project10592532009-03-18 17:39:46 -07004129 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4130 + " : who=" + resultWho + " req=" + requestCode
4131 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4133 try {
4134 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4135 list.add(new ResultInfo(resultWho, requestCode,
4136 resultCode, data));
4137 r.app.thread.scheduleSendResult(r, list);
4138 return;
4139 } catch (Exception e) {
4140 Log.w(TAG, "Exception thrown sending result to " + r, e);
4141 }
4142 }
4143
4144 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4145 }
4146
4147 public final void finishSubActivity(IBinder token, String resultWho,
4148 int requestCode) {
4149 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004150 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004151 if (index < 0) {
4152 return;
4153 }
4154 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4155
4156 final long origId = Binder.clearCallingIdentity();
4157
4158 int i;
4159 for (i=mHistory.size()-1; i>=0; i--) {
4160 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4161 if (r.resultTo == self && r.requestCode == requestCode) {
4162 if ((r.resultWho == null && resultWho == null) ||
4163 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4164 finishActivityLocked(r, i,
4165 Activity.RESULT_CANCELED, null, "request-sub");
4166 }
4167 }
4168 }
4169
4170 Binder.restoreCallingIdentity(origId);
4171 }
4172 }
4173
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004174 public void overridePendingTransition(IBinder token, String packageName,
4175 int enterAnim, int exitAnim) {
4176 synchronized(this) {
4177 int index = indexOfTokenLocked(token);
4178 if (index < 0) {
4179 return;
4180 }
4181 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4182
4183 final long origId = Binder.clearCallingIdentity();
4184
4185 if (self.state == ActivityState.RESUMED
4186 || self.state == ActivityState.PAUSING) {
4187 mWindowManager.overridePendingAppTransition(packageName,
4188 enterAnim, exitAnim);
4189 }
4190
4191 Binder.restoreCallingIdentity(origId);
4192 }
4193 }
4194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004195 /**
4196 * Perform clean-up of service connections in an activity record.
4197 */
4198 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4199 // Throw away any services that have been bound by this activity.
4200 if (r.connections != null) {
4201 Iterator<ConnectionRecord> it = r.connections.iterator();
4202 while (it.hasNext()) {
4203 ConnectionRecord c = it.next();
4204 removeConnectionLocked(c, null, r);
4205 }
4206 r.connections = null;
4207 }
4208 }
4209
4210 /**
4211 * Perform the common clean-up of an activity record. This is called both
4212 * as part of destroyActivityLocked() (when destroying the client-side
4213 * representation) and cleaning things up as a result of its hosting
4214 * processing going away, in which case there is no remaining client-side
4215 * state to destroy so only the cleanup here is needed.
4216 */
4217 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4218 if (mResumedActivity == r) {
4219 mResumedActivity = null;
4220 }
4221 if (mFocusedActivity == r) {
4222 mFocusedActivity = null;
4223 }
4224
4225 r.configDestroy = false;
4226 r.frozenBeforeDestroy = false;
4227
4228 // Make sure this record is no longer in the pending finishes list.
4229 // This could happen, for example, if we are trimming activities
4230 // down to the max limit while they are still waiting to finish.
4231 mFinishingActivities.remove(r);
4232 mWaitingVisibleActivities.remove(r);
4233
4234 // Remove any pending results.
4235 if (r.finishing && r.pendingResults != null) {
4236 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4237 PendingIntentRecord rec = apr.get();
4238 if (rec != null) {
4239 cancelIntentSenderLocked(rec, false);
4240 }
4241 }
4242 r.pendingResults = null;
4243 }
4244
4245 if (cleanServices) {
4246 cleanUpActivityServicesLocked(r);
4247 }
4248
4249 if (mPendingThumbnails.size() > 0) {
4250 // There are clients waiting to receive thumbnails so, in case
4251 // this is an activity that someone is waiting for, add it
4252 // to the pending list so we can correctly update the clients.
4253 mCancelledThumbnails.add(r);
4254 }
4255
4256 // Get rid of any pending idle timeouts.
4257 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4258 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4259 }
4260
4261 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4262 if (r.state != ActivityState.DESTROYED) {
4263 mHistory.remove(r);
4264 r.inHistory = false;
4265 r.state = ActivityState.DESTROYED;
4266 mWindowManager.removeAppToken(r);
4267 if (VALIDATE_TOKENS) {
4268 mWindowManager.validateAppTokens(mHistory);
4269 }
4270 cleanUpActivityServicesLocked(r);
4271 removeActivityUriPermissionsLocked(r);
4272 }
4273 }
4274
4275 /**
4276 * Destroy the current CLIENT SIDE instance of an activity. This may be
4277 * called both when actually finishing an activity, or when performing
4278 * a configuration switch where we destroy the current client-side object
4279 * but then create a new client-side object for this same HistoryRecord.
4280 */
4281 private final boolean destroyActivityLocked(HistoryRecord r,
4282 boolean removeFromApp) {
4283 if (DEBUG_SWITCH) Log.v(
4284 TAG, "Removing activity: token=" + r
4285 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004286 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004287 System.identityHashCode(r),
4288 r.task.taskId, r.shortComponentName);
4289
4290 boolean removedFromHistory = false;
4291
4292 cleanUpActivityLocked(r, false);
4293
Dianne Hackborn03abb812010-01-04 18:43:19 -08004294 final boolean hadApp = r.app != null;
4295
4296 if (hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004297 if (removeFromApp) {
4298 int idx = r.app.activities.indexOf(r);
4299 if (idx >= 0) {
4300 r.app.activities.remove(idx);
4301 }
4302 if (r.persistent) {
4303 decPersistentCountLocked(r.app);
4304 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004305 if (r.app.activities.size() == 0) {
4306 // No longer have activities, so update location in
4307 // LRU list.
4308 updateLruProcessLocked(r.app, true, false);
4309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004310 }
4311
4312 boolean skipDestroy = false;
4313
4314 try {
4315 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4316 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4317 r.configChangeFlags);
4318 } catch (Exception e) {
4319 // We can just ignore exceptions here... if the process
4320 // has crashed, our death notification will clean things
4321 // up.
4322 //Log.w(TAG, "Exception thrown during finish", e);
4323 if (r.finishing) {
4324 removeActivityFromHistoryLocked(r);
4325 removedFromHistory = true;
4326 skipDestroy = true;
4327 }
4328 }
4329
4330 r.app = null;
4331 r.nowVisible = false;
4332
4333 if (r.finishing && !skipDestroy) {
4334 r.state = ActivityState.DESTROYING;
4335 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4336 msg.obj = r;
4337 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4338 } else {
4339 r.state = ActivityState.DESTROYED;
4340 }
4341 } else {
4342 // remove this record from the history.
4343 if (r.finishing) {
4344 removeActivityFromHistoryLocked(r);
4345 removedFromHistory = true;
4346 } else {
4347 r.state = ActivityState.DESTROYED;
4348 }
4349 }
4350
4351 r.configChangeFlags = 0;
4352
Dianne Hackborn03abb812010-01-04 18:43:19 -08004353 if (!mLRUActivities.remove(r) && hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004354 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4355 }
4356
4357 return removedFromHistory;
4358 }
4359
Dianne Hackborn03abb812010-01-04 18:43:19 -08004360 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004361 int i = list.size();
4362 if (localLOGV) Log.v(
4363 TAG, "Removing app " + app + " from list " + list
4364 + " with " + i + " entries");
4365 while (i > 0) {
4366 i--;
4367 HistoryRecord r = (HistoryRecord)list.get(i);
4368 if (localLOGV) Log.v(
4369 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4370 if (r.app == app) {
4371 if (localLOGV) Log.v(TAG, "Removing this entry!");
4372 list.remove(i);
4373 }
4374 }
4375 }
4376
4377 /**
4378 * Main function for removing an existing process from the activity manager
4379 * as a result of that process going away. Clears out all connections
4380 * to the process.
4381 */
4382 private final void handleAppDiedLocked(ProcessRecord app,
4383 boolean restarting) {
4384 cleanUpApplicationRecordLocked(app, restarting, -1);
4385 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004386 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004387 }
4388
4389 // Just in case...
4390 if (mPausingActivity != null && mPausingActivity.app == app) {
4391 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4392 mPausingActivity = null;
4393 }
4394 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4395 mLastPausedActivity = null;
4396 }
4397
4398 // Remove this application's activities from active lists.
4399 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4400 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4401 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4402 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4403
4404 boolean atTop = true;
4405 boolean hasVisibleActivities = false;
4406
4407 // Clean out the history list.
4408 int i = mHistory.size();
4409 if (localLOGV) Log.v(
4410 TAG, "Removing app " + app + " from history with " + i + " entries");
4411 while (i > 0) {
4412 i--;
4413 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4414 if (localLOGV) Log.v(
4415 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4416 if (r.app == app) {
4417 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4418 if (localLOGV) Log.v(
4419 TAG, "Removing this entry! frozen=" + r.haveState
4420 + " finishing=" + r.finishing);
4421 mHistory.remove(i);
4422
4423 r.inHistory = false;
4424 mWindowManager.removeAppToken(r);
4425 if (VALIDATE_TOKENS) {
4426 mWindowManager.validateAppTokens(mHistory);
4427 }
4428 removeActivityUriPermissionsLocked(r);
4429
4430 } else {
4431 // We have the current state for this activity, so
4432 // it can be restarted later when needed.
4433 if (localLOGV) Log.v(
4434 TAG, "Keeping entry, setting app to null");
4435 if (r.visible) {
4436 hasVisibleActivities = true;
4437 }
4438 r.app = null;
4439 r.nowVisible = false;
4440 if (!r.haveState) {
4441 r.icicle = null;
4442 }
4443 }
4444
4445 cleanUpActivityLocked(r, true);
4446 r.state = ActivityState.STOPPED;
4447 }
4448 atTop = false;
4449 }
4450
4451 app.activities.clear();
4452
4453 if (app.instrumentationClass != null) {
4454 Log.w(TAG, "Crash of app " + app.processName
4455 + " running instrumentation " + app.instrumentationClass);
4456 Bundle info = new Bundle();
4457 info.putString("shortMsg", "Process crashed.");
4458 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4459 }
4460
4461 if (!restarting) {
4462 if (!resumeTopActivityLocked(null)) {
4463 // If there was nothing to resume, and we are not already
4464 // restarting this process, but there is a visible activity that
4465 // is hosted by the process... then make sure all visible
4466 // activities are running, taking care of restarting this
4467 // process.
4468 if (hasVisibleActivities) {
4469 ensureActivitiesVisibleLocked(null, 0);
4470 }
4471 }
4472 }
4473 }
4474
4475 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4476 IBinder threadBinder = thread.asBinder();
4477
4478 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004479 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4480 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004481 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4482 return i;
4483 }
4484 }
4485 return -1;
4486 }
4487
4488 private final ProcessRecord getRecordForAppLocked(
4489 IApplicationThread thread) {
4490 if (thread == null) {
4491 return null;
4492 }
4493
4494 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004495 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004496 }
4497
4498 private final void appDiedLocked(ProcessRecord app, int pid,
4499 IApplicationThread thread) {
4500
4501 mProcDeaths[0]++;
4502
4503 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4504 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4505 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004506 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004507 if (localLOGV) Log.v(
4508 TAG, "Dying app: " + app + ", pid: " + pid
4509 + ", thread: " + thread.asBinder());
4510 boolean doLowMem = app.instrumentationClass == null;
4511 handleAppDiedLocked(app, false);
4512
4513 if (doLowMem) {
4514 // If there are no longer any background processes running,
4515 // and the app that died was not running instrumentation,
4516 // then tell everyone we are now low on memory.
4517 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004518 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4519 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004520 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4521 haveBg = true;
4522 break;
4523 }
4524 }
4525
4526 if (!haveBg) {
4527 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004528 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004529 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004530 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4531 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004532 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004533 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4534 // The low memory report is overriding any current
4535 // state for a GC request. Make sure to do
4536 // visible/foreground processes first.
4537 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4538 rec.lastRequestedGc = 0;
4539 } else {
4540 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004541 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004542 rec.reportLowMemory = true;
4543 rec.lastLowMemory = now;
4544 mProcessesToGc.remove(rec);
4545 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004546 }
4547 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004548 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004549 }
4550 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004551 } else if (DEBUG_PROCESSES) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004552 Log.d(TAG, "Received spurious death notification for thread "
4553 + thread.asBinder());
4554 }
4555 }
4556
Dan Egnor42471dd2010-01-07 17:25:22 -08004557 /**
4558 * If a stack trace dump file is configured, dump process stack traces.
4559 * @param pids of dalvik VM processes to dump stack traces for
4560 * @return file containing stack traces, or null if no dump file is configured
4561 */
4562 private static File dumpStackTraces(ArrayList<Integer> pids) {
4563 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4564 if (tracesPath == null || tracesPath.length() == 0) {
4565 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004566 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004567
4568 File tracesFile = new File(tracesPath);
4569 try {
4570 File tracesDir = tracesFile.getParentFile();
4571 if (!tracesDir.exists()) tracesFile.mkdirs();
4572 FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
4573
4574 if (tracesFile.exists()) tracesFile.delete();
4575 tracesFile.createNewFile();
4576 FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
4577 } catch (IOException e) {
4578 Log.w(TAG, "Unable to prepare ANR traces file: " + tracesPath, e);
4579 return null;
4580 }
4581
4582 // Use a FileObserver to detect when traces finish writing.
4583 // The order of traces is considered important to maintain for legibility.
4584 FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
4585 public synchronized void onEvent(int event, String path) { notify(); }
4586 };
4587
4588 try {
4589 observer.startWatching();
4590 int num = pids.size();
4591 for (int i = 0; i < num; i++) {
4592 synchronized (observer) {
4593 Process.sendSignal(pids.get(i), Process.SIGNAL_QUIT);
4594 observer.wait(200); // Wait for write-close, give up after 200msec
4595 }
4596 }
4597 } catch (InterruptedException e) {
4598 Log.wtf(TAG, e);
4599 } finally {
4600 observer.stopWatching();
4601 }
4602
4603 return tracesFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004604 }
4605
Dan Egnor42471dd2010-01-07 17:25:22 -08004606 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4607 HistoryRecord parent, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 if (app.notResponding || app.crashing) {
4609 return;
4610 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004612 // Log the ANR to the event log.
Dan Egnor2780e732010-01-22 14:47:35 -08004613 EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
4614 annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004615
Dan Egnor42471dd2010-01-07 17:25:22 -08004616 // Dump thread traces as quickly as we can, starting with "interesting" processes.
4617 ArrayList<Integer> pids = new ArrayList<Integer>(20);
4618 pids.add(app.pid);
4619
4620 int parentPid = app.pid;
4621 if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
4622 if (parentPid != app.pid) pids.add(parentPid);
4623
4624 if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
4625
4626 for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
4627 ProcessRecord r = mLruProcesses.get(i);
4628 if (r != null && r.thread != null) {
4629 int pid = r.pid;
4630 if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004631 }
4632 }
4633
Dan Egnor42471dd2010-01-07 17:25:22 -08004634 File tracesFile = dumpStackTraces(pids);
4635
4636 // Log the ANR to the main log.
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004637 StringBuilder info = mStringBuilder;
4638 info.setLength(0);
Dan Egnor42471dd2010-01-07 17:25:22 -08004639 info.append("ANR in ").append(app.processName);
4640 if (activity != null && activity.shortComponentName != null) {
4641 info.append(" (").append(activity.shortComponentName).append(")");
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004643 if (annotation != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004644 info.append("\nReason: ").append(annotation).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004645 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004646 if (parent != null && parent != activity) {
4647 info.append("\nParent: ").append(parent.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004648 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004649
Dan Egnor42471dd2010-01-07 17:25:22 -08004650 String cpuInfo = null;
4651 if (MONITOR_CPU_USAGE) {
4652 updateCpuStatsNow();
4653 synchronized (mProcessStatsThread) { cpuInfo = mProcessStats.printCurrentState(); }
4654 info.append(cpuInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004655 }
4656
Dan Egnor42471dd2010-01-07 17:25:22 -08004657 Log.e(TAG, info.toString());
4658 if (tracesFile == null) {
4659 // There is no trace file, so dump (only) the alleged culprit's threads to the log
4660 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4661 }
4662
4663 addErrorToDropBox("anr", app, activity, parent, annotation, cpuInfo, tracesFile, null);
4664
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004665 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004666 try {
Dan Egnor42471dd2010-01-07 17:25:22 -08004667 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
4668 int res = mController.appNotResponding(app.processName, app.pid, info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004669 if (res != 0) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004670 if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
4671 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004672 }
4673 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004674 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004675 }
4676 }
4677
Dan Egnor42471dd2010-01-07 17:25:22 -08004678 // Unless configured otherwise, swallow ANRs in background processes & kill the process.
4679 boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
4680 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
4681 if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
4682 Process.killProcess(app.pid);
4683 return;
4684 }
4685
4686 // Set the app's notResponding state, and look up the errorReportReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004687 makeAppNotRespondingLocked(app,
4688 activity != null ? activity.shortComponentName : null,
4689 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004690 info.toString());
Dan Egnor42471dd2010-01-07 17:25:22 -08004691
4692 // Bring up the infamous App Not Responding dialog
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004693 Message msg = Message.obtain();
4694 HashMap map = new HashMap();
4695 msg.what = SHOW_NOT_RESPONDING_MSG;
4696 msg.obj = map;
4697 map.put("app", app);
4698 if (activity != null) {
4699 map.put("activity", activity);
4700 }
4701
4702 mHandler.sendMessage(msg);
4703 return;
4704 }
4705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004706 private final void decPersistentCountLocked(ProcessRecord app)
4707 {
4708 app.persistentActivities--;
4709 if (app.persistentActivities > 0) {
4710 // Still more of 'em...
4711 return;
4712 }
4713 if (app.persistent) {
4714 // Ah, but the application itself is persistent. Whatever!
4715 return;
4716 }
4717
4718 // App is no longer persistent... make sure it and the ones
4719 // following it in the LRU list have the correc oom_adj.
4720 updateOomAdjLocked();
4721 }
4722
4723 public void setPersistent(IBinder token, boolean isPersistent) {
4724 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4725 != PackageManager.PERMISSION_GRANTED) {
4726 String msg = "Permission Denial: setPersistent() from pid="
4727 + Binder.getCallingPid()
4728 + ", uid=" + Binder.getCallingUid()
4729 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4730 Log.w(TAG, msg);
4731 throw new SecurityException(msg);
4732 }
4733
4734 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004735 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004736 if (index < 0) {
4737 return;
4738 }
4739 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4740 ProcessRecord app = r.app;
4741
4742 if (localLOGV) Log.v(
4743 TAG, "Setting persistence " + isPersistent + ": " + r);
4744
4745 if (isPersistent) {
4746 if (r.persistent) {
4747 // Okay okay, I heard you already!
4748 if (localLOGV) Log.v(TAG, "Already persistent!");
4749 return;
4750 }
4751 r.persistent = true;
4752 app.persistentActivities++;
4753 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4754 if (app.persistentActivities > 1) {
4755 // We aren't the first...
4756 if (localLOGV) Log.v(TAG, "Not the first!");
4757 return;
4758 }
4759 if (app.persistent) {
4760 // This would be redundant.
4761 if (localLOGV) Log.v(TAG, "App is persistent!");
4762 return;
4763 }
4764
4765 // App is now persistent... make sure it and the ones
4766 // following it now have the correct oom_adj.
4767 final long origId = Binder.clearCallingIdentity();
4768 updateOomAdjLocked();
4769 Binder.restoreCallingIdentity(origId);
4770
4771 } else {
4772 if (!r.persistent) {
4773 // Okay okay, I heard you already!
4774 return;
4775 }
4776 r.persistent = false;
4777 final long origId = Binder.clearCallingIdentity();
4778 decPersistentCountLocked(app);
4779 Binder.restoreCallingIdentity(origId);
4780
4781 }
4782 }
4783 }
4784
4785 public boolean clearApplicationUserData(final String packageName,
4786 final IPackageDataObserver observer) {
4787 int uid = Binder.getCallingUid();
4788 int pid = Binder.getCallingPid();
4789 long callingId = Binder.clearCallingIdentity();
4790 try {
4791 IPackageManager pm = ActivityThread.getPackageManager();
4792 int pkgUid = -1;
4793 synchronized(this) {
4794 try {
4795 pkgUid = pm.getPackageUid(packageName);
4796 } catch (RemoteException e) {
4797 }
4798 if (pkgUid == -1) {
4799 Log.w(TAG, "Invalid packageName:" + packageName);
4800 return false;
4801 }
4802 if (uid == pkgUid || checkComponentPermission(
4803 android.Manifest.permission.CLEAR_APP_USER_DATA,
4804 pid, uid, -1)
4805 == PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08004806 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004807 } else {
4808 throw new SecurityException(pid+" does not have permission:"+
4809 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4810 "for process:"+packageName);
4811 }
4812 }
4813
4814 try {
4815 //clear application user data
4816 pm.clearApplicationUserData(packageName, observer);
4817 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4818 Uri.fromParts("package", packageName, null));
4819 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4820 broadcastIntentLocked(null, null, intent,
4821 null, null, 0, null, null, null,
4822 false, false, MY_PID, Process.SYSTEM_UID);
4823 } catch (RemoteException e) {
4824 }
4825 } finally {
4826 Binder.restoreCallingIdentity(callingId);
4827 }
4828 return true;
4829 }
4830
Dianne Hackborn03abb812010-01-04 18:43:19 -08004831 public void killBackgroundProcesses(final String packageName) {
4832 if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
4833 != PackageManager.PERMISSION_GRANTED &&
4834 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4835 != PackageManager.PERMISSION_GRANTED) {
4836 String msg = "Permission Denial: killBackgroundProcesses() from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004837 + Binder.getCallingPid()
4838 + ", uid=" + Binder.getCallingUid()
Dianne Hackborn03abb812010-01-04 18:43:19 -08004839 + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004840 Log.w(TAG, msg);
4841 throw new SecurityException(msg);
4842 }
4843
4844 long callingId = Binder.clearCallingIdentity();
4845 try {
4846 IPackageManager pm = ActivityThread.getPackageManager();
4847 int pkgUid = -1;
4848 synchronized(this) {
4849 try {
4850 pkgUid = pm.getPackageUid(packageName);
4851 } catch (RemoteException e) {
4852 }
4853 if (pkgUid == -1) {
4854 Log.w(TAG, "Invalid packageName: " + packageName);
4855 return;
4856 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004857 killPackageProcessesLocked(packageName, pkgUid,
4858 SECONDARY_SERVER_ADJ, false);
4859 }
4860 } finally {
4861 Binder.restoreCallingIdentity(callingId);
4862 }
4863 }
4864
4865 public void forceStopPackage(final String packageName) {
4866 if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
4867 != PackageManager.PERMISSION_GRANTED) {
4868 String msg = "Permission Denial: forceStopPackage() from pid="
4869 + Binder.getCallingPid()
4870 + ", uid=" + Binder.getCallingUid()
4871 + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
4872 Log.w(TAG, msg);
4873 throw new SecurityException(msg);
4874 }
4875
4876 long callingId = Binder.clearCallingIdentity();
4877 try {
4878 IPackageManager pm = ActivityThread.getPackageManager();
4879 int pkgUid = -1;
4880 synchronized(this) {
4881 try {
4882 pkgUid = pm.getPackageUid(packageName);
4883 } catch (RemoteException e) {
4884 }
4885 if (pkgUid == -1) {
4886 Log.w(TAG, "Invalid packageName: " + packageName);
4887 return;
4888 }
4889 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004890 }
4891 } finally {
4892 Binder.restoreCallingIdentity(callingId);
4893 }
4894 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004895
4896 /*
4897 * The pkg name and uid have to be specified.
4898 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4899 */
4900 public void killApplicationWithUid(String pkg, int uid) {
4901 if (pkg == null) {
4902 return;
4903 }
4904 // Make sure the uid is valid.
4905 if (uid < 0) {
4906 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4907 return;
4908 }
4909 int callerUid = Binder.getCallingUid();
4910 // Only the system server can kill an application
4911 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004912 // Post an aysnc message to kill the application
4913 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4914 msg.arg1 = uid;
4915 msg.arg2 = 0;
4916 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004917 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004918 } else {
4919 throw new SecurityException(callerUid + " cannot kill pkg: " +
4920 pkg);
4921 }
4922 }
4923
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004924 public void closeSystemDialogs(String reason) {
4925 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4926 if (reason != null) {
4927 intent.putExtra("reason", reason);
4928 }
4929
4930 final int uid = Binder.getCallingUid();
4931 final long origId = Binder.clearCallingIdentity();
4932 synchronized (this) {
4933 int i = mWatchers.beginBroadcast();
4934 while (i > 0) {
4935 i--;
4936 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4937 if (w != null) {
4938 try {
4939 w.closingSystemDialogs(reason);
4940 } catch (RemoteException e) {
4941 }
4942 }
4943 }
4944 mWatchers.finishBroadcast();
4945
Dianne Hackbornffa42482009-09-23 22:20:11 -07004946 mWindowManager.closeSystemDialogs(reason);
4947
4948 for (i=mHistory.size()-1; i>=0; i--) {
4949 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4950 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4951 finishActivityLocked(r, i,
4952 Activity.RESULT_CANCELED, null, "close-sys");
4953 }
4954 }
4955
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004956 broadcastIntentLocked(null, null, intent, null,
4957 null, 0, null, null, null, false, false, -1, uid);
4958 }
4959 Binder.restoreCallingIdentity(origId);
4960 }
4961
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004962 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004963 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004964 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4965 for (int i=pids.length-1; i>=0; i--) {
4966 infos[i] = new Debug.MemoryInfo();
4967 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004968 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004969 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004970 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004971
4972 public void killApplicationProcess(String processName, int uid) {
4973 if (processName == null) {
4974 return;
4975 }
4976
4977 int callerUid = Binder.getCallingUid();
4978 // Only the system server can kill an application
4979 if (callerUid == Process.SYSTEM_UID) {
4980 synchronized (this) {
4981 ProcessRecord app = getProcessRecordLocked(processName, uid);
4982 if (app != null) {
4983 try {
4984 app.thread.scheduleSuicide();
4985 } catch (RemoteException e) {
4986 // If the other end already died, then our work here is done.
4987 }
4988 } else {
4989 Log.w(TAG, "Process/uid not found attempting kill of "
4990 + processName + " / " + uid);
4991 }
4992 }
4993 } else {
4994 throw new SecurityException(callerUid + " cannot kill app process: " +
4995 processName);
4996 }
4997 }
4998
Dianne Hackborn03abb812010-01-04 18:43:19 -08004999 private void forceStopPackageLocked(final String packageName, int uid) {
5000 forceStopPackageLocked(packageName, uid, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005001 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5002 Uri.fromParts("package", packageName, null));
5003 intent.putExtra(Intent.EXTRA_UID, uid);
5004 broadcastIntentLocked(null, null, intent,
5005 null, null, 0, null, null, null,
5006 false, false, MY_PID, Process.SYSTEM_UID);
5007 }
5008
Dianne Hackborn03abb812010-01-04 18:43:19 -08005009 private final void killPackageProcessesLocked(String packageName, int uid,
5010 int minOomAdj, boolean callerWillRestart) {
5011 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005012
Dianne Hackborn03abb812010-01-04 18:43:19 -08005013 // Remove all processes this package may have touched: all with the
5014 // same UID (except for the system or root user), and all whose name
5015 // matches the package name.
5016 final String procNamePrefix = packageName + ":";
5017 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5018 final int NA = apps.size();
5019 for (int ia=0; ia<NA; ia++) {
5020 ProcessRecord app = apps.valueAt(ia);
5021 if (app.removed) {
5022 procs.add(app);
5023 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5024 || app.processName.equals(packageName)
5025 || app.processName.startsWith(procNamePrefix)) {
5026 if (app.setAdj >= minOomAdj) {
5027 app.removed = true;
5028 procs.add(app);
5029 }
5030 }
5031 }
5032 }
5033
5034 int N = procs.size();
5035 for (int i=0; i<N; i++) {
5036 removeProcessLocked(procs.get(i), callerWillRestart);
5037 }
5038 }
5039
5040 private final void forceStopPackageLocked(String name, int uid,
5041 boolean callerWillRestart) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005042 int i, N;
5043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005044 if (uid < 0) {
5045 try {
5046 uid = ActivityThread.getPackageManager().getPackageUid(name);
5047 } catch (RemoteException e) {
5048 }
5049 }
5050
Dianne Hackborn03abb812010-01-04 18:43:19 -08005051 Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
5052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005053 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5054 while (badApps.hasNext()) {
5055 SparseArray<Long> ba = badApps.next();
5056 if (ba.get(uid) != null) {
5057 badApps.remove();
5058 }
5059 }
5060
Dianne Hackborn03abb812010-01-04 18:43:19 -08005061 killPackageProcessesLocked(name, uid, -100, callerWillRestart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005062
5063 for (i=mHistory.size()-1; i>=0; i--) {
5064 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5065 if (r.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005066 Log.i(TAG, " Force finishing activity " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005067 if (r.app != null) {
5068 r.app.removed = true;
5069 }
5070 r.app = null;
5071 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5072 }
5073 }
5074
5075 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5076 for (ServiceRecord service : mServices.values()) {
5077 if (service.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005078 Log.i(TAG, " Force stopping service " + service);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005079 if (service.app != null) {
5080 service.app.removed = true;
5081 }
5082 service.app = null;
5083 services.add(service);
5084 }
5085 }
5086
5087 N = services.size();
5088 for (i=0; i<N; i++) {
5089 bringDownServiceLocked(services.get(i), true);
5090 }
5091
5092 resumeTopActivityLocked(null);
5093 }
5094
5095 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5096 final String name = app.processName;
5097 final int uid = app.info.uid;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005098 if (DEBUG_PROCESSES) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005099 TAG, "Force removing process " + app + " (" + name
5100 + "/" + uid + ")");
5101
5102 mProcessNames.remove(name, uid);
5103 boolean needRestart = false;
5104 if (app.pid > 0 && app.pid != MY_PID) {
5105 int pid = app.pid;
5106 synchronized (mPidsSelfLocked) {
5107 mPidsSelfLocked.remove(pid);
5108 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5109 }
5110 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005111 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005112 Process.killProcess(pid);
5113
5114 if (app.persistent) {
5115 if (!callerWillRestart) {
5116 addAppLocked(app.info);
5117 } else {
5118 needRestart = true;
5119 }
5120 }
5121 } else {
5122 mRemovedProcesses.add(app);
5123 }
5124
5125 return needRestart;
5126 }
5127
5128 private final void processStartTimedOutLocked(ProcessRecord app) {
5129 final int pid = app.pid;
5130 boolean gone = false;
5131 synchronized (mPidsSelfLocked) {
5132 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5133 if (knownApp != null && knownApp.thread == null) {
5134 mPidsSelfLocked.remove(pid);
5135 gone = true;
5136 }
5137 }
5138
5139 if (gone) {
5140 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005141 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005142 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005143 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005144 // Take care of any launching providers waiting for this process.
5145 checkAppInLaunchingProvidersLocked(app, true);
5146 // Take care of any services that are waiting for the process.
5147 for (int i=0; i<mPendingServices.size(); i++) {
5148 ServiceRecord sr = mPendingServices.get(i);
5149 if (app.info.uid == sr.appInfo.uid
5150 && app.processName.equals(sr.processName)) {
5151 Log.w(TAG, "Forcing bringing down service: " + sr);
5152 mPendingServices.remove(i);
5153 i--;
5154 bringDownServiceLocked(sr, true);
5155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005156 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005157 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005158 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5159 Log.w(TAG, "Unattached app died before backup, skipping");
5160 try {
5161 IBackupManager bm = IBackupManager.Stub.asInterface(
5162 ServiceManager.getService(Context.BACKUP_SERVICE));
5163 bm.agentDisconnected(app.info.packageName);
5164 } catch (RemoteException e) {
5165 // Can't happen; the backup manager is local
5166 }
5167 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005168 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5169 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5170 mPendingBroadcast = null;
5171 scheduleBroadcastsLocked();
5172 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005173 } else {
5174 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5175 }
5176 }
5177
5178 private final boolean attachApplicationLocked(IApplicationThread thread,
5179 int pid) {
5180
5181 // Find the application record that is being attached... either via
5182 // the pid if we are running in multiple processes, or just pull the
5183 // next app record if we are emulating process with anonymous threads.
5184 ProcessRecord app;
5185 if (pid != MY_PID && pid >= 0) {
5186 synchronized (mPidsSelfLocked) {
5187 app = mPidsSelfLocked.get(pid);
5188 }
5189 } else if (mStartingProcesses.size() > 0) {
5190 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005191 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 } else {
5193 app = null;
5194 }
5195
5196 if (app == null) {
5197 Log.w(TAG, "No pending application record for pid " + pid
5198 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005199 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005200 if (pid > 0 && pid != MY_PID) {
5201 Process.killProcess(pid);
5202 } else {
5203 try {
5204 thread.scheduleExit();
5205 } catch (Exception e) {
5206 // Ignore exceptions.
5207 }
5208 }
5209 return false;
5210 }
5211
5212 // If this application record is still attached to a previous
5213 // process, clean it up now.
5214 if (app.thread != null) {
5215 handleAppDiedLocked(app, true);
5216 }
5217
5218 // Tell the process all about itself.
5219
5220 if (localLOGV) Log.v(
5221 TAG, "Binding process pid " + pid + " to record " + app);
5222
5223 String processName = app.processName;
5224 try {
5225 thread.asBinder().linkToDeath(new AppDeathRecipient(
5226 app, pid, thread), 0);
5227 } catch (RemoteException e) {
5228 app.resetPackageList();
5229 startProcessLocked(app, "link fail", processName);
5230 return false;
5231 }
5232
Doug Zongker2bec3d42009-12-04 12:52:44 -08005233 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005234
5235 app.thread = thread;
5236 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005237 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5238 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005239 app.forcingToForeground = null;
5240 app.foregroundServices = false;
5241 app.debugging = false;
5242
5243 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5244
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005245 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5246 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005247
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005248 if (!normalMode) {
5249 Log.i(TAG, "Launching preboot mode app: " + app);
5250 }
5251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005252 if (localLOGV) Log.v(
5253 TAG, "New app record " + app
5254 + " thread=" + thread.asBinder() + " pid=" + pid);
5255 try {
5256 int testMode = IApplicationThread.DEBUG_OFF;
5257 if (mDebugApp != null && mDebugApp.equals(processName)) {
5258 testMode = mWaitForDebugger
5259 ? IApplicationThread.DEBUG_WAIT
5260 : IApplicationThread.DEBUG_ON;
5261 app.debugging = true;
5262 if (mDebugTransient) {
5263 mDebugApp = mOrigDebugApp;
5264 mWaitForDebugger = mOrigWaitForDebugger;
5265 }
5266 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005267
Christopher Tate181fafa2009-05-14 11:12:14 -07005268 // If the app is being launched for restore or full backup, set it up specially
5269 boolean isRestrictedBackupMode = false;
5270 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5271 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5272 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5273 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005274
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005275 ensurePackageDexOpt(app.instrumentationInfo != null
5276 ? app.instrumentationInfo.packageName
5277 : app.info.packageName);
5278 if (app.instrumentationClass != null) {
5279 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005280 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005281 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5282 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005283 thread.bindApplication(processName, app.instrumentationInfo != null
5284 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005285 app.instrumentationClass, app.instrumentationProfileFile,
5286 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005287 isRestrictedBackupMode || !normalMode,
5288 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005289 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005290 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005291 } catch (Exception e) {
5292 // todo: Yikes! What should we do? For now we will try to
5293 // start another process, but that could easily get us in
5294 // an infinite loop of restarting processes...
5295 Log.w(TAG, "Exception thrown during bind!", e);
5296
5297 app.resetPackageList();
5298 startProcessLocked(app, "bind fail", processName);
5299 return false;
5300 }
5301
5302 // Remove this record from the list of starting applications.
5303 mPersistentStartingProcesses.remove(app);
5304 mProcessesOnHold.remove(app);
5305
5306 boolean badApp = false;
5307 boolean didSomething = false;
5308
5309 // See if the top visible activity is waiting to run in this process...
5310 HistoryRecord hr = topRunningActivityLocked(null);
5311 if (hr != null) {
5312 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5313 && processName.equals(hr.processName)) {
5314 try {
5315 if (realStartActivityLocked(hr, app, true, true)) {
5316 didSomething = true;
5317 }
5318 } catch (Exception e) {
5319 Log.w(TAG, "Exception in new application when starting activity "
5320 + hr.intent.getComponent().flattenToShortString(), e);
5321 badApp = true;
5322 }
5323 } else {
5324 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5325 }
5326 }
5327
5328 // Find any services that should be running in this process...
5329 if (!badApp && mPendingServices.size() > 0) {
5330 ServiceRecord sr = null;
5331 try {
5332 for (int i=0; i<mPendingServices.size(); i++) {
5333 sr = mPendingServices.get(i);
5334 if (app.info.uid != sr.appInfo.uid
5335 || !processName.equals(sr.processName)) {
5336 continue;
5337 }
5338
5339 mPendingServices.remove(i);
5340 i--;
5341 realStartServiceLocked(sr, app);
5342 didSomething = true;
5343 }
5344 } catch (Exception e) {
5345 Log.w(TAG, "Exception in new application when starting service "
5346 + sr.shortName, e);
5347 badApp = true;
5348 }
5349 }
5350
5351 // Check if the next broadcast receiver is in this process...
5352 BroadcastRecord br = mPendingBroadcast;
5353 if (!badApp && br != null && br.curApp == app) {
5354 try {
5355 mPendingBroadcast = null;
5356 processCurBroadcastLocked(br, app);
5357 didSomething = true;
5358 } catch (Exception e) {
5359 Log.w(TAG, "Exception in new application when starting receiver "
5360 + br.curComponent.flattenToShortString(), e);
5361 badApp = true;
5362 logBroadcastReceiverDiscard(br);
5363 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5364 br.resultExtras, br.resultAbort, true);
5365 scheduleBroadcastsLocked();
5366 }
5367 }
5368
Christopher Tate181fafa2009-05-14 11:12:14 -07005369 // Check whether the next backup agent is in this process...
5370 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5371 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005372 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005373 try {
5374 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5375 } catch (Exception e) {
5376 Log.w(TAG, "Exception scheduling backup agent creation: ");
5377 e.printStackTrace();
5378 }
5379 }
5380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005381 if (badApp) {
5382 // todo: Also need to kill application to deal with all
5383 // kinds of exceptions.
5384 handleAppDiedLocked(app, false);
5385 return false;
5386 }
5387
5388 if (!didSomething) {
5389 updateOomAdjLocked();
5390 }
5391
5392 return true;
5393 }
5394
5395 public final void attachApplication(IApplicationThread thread) {
5396 synchronized (this) {
5397 int callingPid = Binder.getCallingPid();
5398 final long origId = Binder.clearCallingIdentity();
5399 attachApplicationLocked(thread, callingPid);
5400 Binder.restoreCallingIdentity(origId);
5401 }
5402 }
5403
Dianne Hackborne88846e2009-09-30 21:34:25 -07005404 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005405 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005406 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005407 Binder.restoreCallingIdentity(origId);
5408 }
5409
5410 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5411 boolean remove) {
5412 int N = mStoppingActivities.size();
5413 if (N <= 0) return null;
5414
5415 ArrayList<HistoryRecord> stops = null;
5416
5417 final boolean nowVisible = mResumedActivity != null
5418 && mResumedActivity.nowVisible
5419 && !mResumedActivity.waitingVisible;
5420 for (int i=0; i<N; i++) {
5421 HistoryRecord s = mStoppingActivities.get(i);
5422 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5423 + nowVisible + " waitingVisible=" + s.waitingVisible
5424 + " finishing=" + s.finishing);
5425 if (s.waitingVisible && nowVisible) {
5426 mWaitingVisibleActivities.remove(s);
5427 s.waitingVisible = false;
5428 if (s.finishing) {
5429 // If this activity is finishing, it is sitting on top of
5430 // everyone else but we now know it is no longer needed...
5431 // so get rid of it. Otherwise, we need to go through the
5432 // normal flow and hide it once we determine that it is
5433 // hidden by the activities in front of it.
5434 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5435 mWindowManager.setAppVisibility(s, false);
5436 }
5437 }
5438 if (!s.waitingVisible && remove) {
5439 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5440 if (stops == null) {
5441 stops = new ArrayList<HistoryRecord>();
5442 }
5443 stops.add(s);
5444 mStoppingActivities.remove(i);
5445 N--;
5446 i--;
5447 }
5448 }
5449
5450 return stops;
5451 }
5452
5453 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005454 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005455 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005456 mWindowManager.enableScreenAfterBoot();
5457 }
5458
Dianne Hackborne88846e2009-09-30 21:34:25 -07005459 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5460 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005461 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5462
5463 ArrayList<HistoryRecord> stops = null;
5464 ArrayList<HistoryRecord> finishes = null;
5465 ArrayList<HistoryRecord> thumbnails = null;
5466 int NS = 0;
5467 int NF = 0;
5468 int NT = 0;
5469 IApplicationThread sendThumbnail = null;
5470 boolean booting = false;
5471 boolean enableScreen = false;
5472
5473 synchronized (this) {
5474 if (token != null) {
5475 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5476 }
5477
5478 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005479 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005480 if (index >= 0) {
5481 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5482
Dianne Hackborne88846e2009-09-30 21:34:25 -07005483 // This is a hack to semi-deal with a race condition
5484 // in the client where it can be constructed with a
5485 // newer configuration from when we asked it to launch.
5486 // We'll update with whatever configuration it now says
5487 // it used to launch.
5488 if (config != null) {
5489 r.configuration = config;
5490 }
5491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005492 // No longer need to keep the device awake.
5493 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5494 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5495 mLaunchingActivity.release();
5496 }
5497
5498 // We are now idle. If someone is waiting for a thumbnail from
5499 // us, we can now deliver.
5500 r.idle = true;
5501 scheduleAppGcsLocked();
5502 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5503 sendThumbnail = r.app.thread;
5504 r.thumbnailNeeded = false;
5505 }
5506
5507 // If this activity is fullscreen, set up to hide those under it.
5508
5509 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5510 ensureActivitiesVisibleLocked(null, 0);
5511
5512 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5513 if (!mBooted && !fromTimeout) {
5514 mBooted = true;
5515 enableScreen = true;
5516 }
5517 }
5518
5519 // Atomically retrieve all of the other things to do.
5520 stops = processStoppingActivitiesLocked(true);
5521 NS = stops != null ? stops.size() : 0;
5522 if ((NF=mFinishingActivities.size()) > 0) {
5523 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5524 mFinishingActivities.clear();
5525 }
5526 if ((NT=mCancelledThumbnails.size()) > 0) {
5527 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5528 mCancelledThumbnails.clear();
5529 }
5530
5531 booting = mBooting;
5532 mBooting = false;
5533 }
5534
5535 int i;
5536
5537 // Send thumbnail if requested.
5538 if (sendThumbnail != null) {
5539 try {
5540 sendThumbnail.requestThumbnail(token);
5541 } catch (Exception e) {
5542 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5543 sendPendingThumbnail(null, token, null, null, true);
5544 }
5545 }
5546
5547 // Stop any activities that are scheduled to do so but have been
5548 // waiting for the next one to start.
5549 for (i=0; i<NS; i++) {
5550 HistoryRecord r = (HistoryRecord)stops.get(i);
5551 synchronized (this) {
5552 if (r.finishing) {
5553 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5554 } else {
5555 stopActivityLocked(r);
5556 }
5557 }
5558 }
5559
5560 // Finish any activities that are scheduled to do so but have been
5561 // waiting for the next one to start.
5562 for (i=0; i<NF; i++) {
5563 HistoryRecord r = (HistoryRecord)finishes.get(i);
5564 synchronized (this) {
5565 destroyActivityLocked(r, true);
5566 }
5567 }
5568
5569 // Report back to any thumbnail receivers.
5570 for (i=0; i<NT; i++) {
5571 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5572 sendPendingThumbnail(r, null, null, null, true);
5573 }
5574
5575 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005576 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005577 }
5578
5579 trimApplications();
5580 //dump();
5581 //mWindowManager.dump();
5582
5583 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005584 enableScreenAfterBoot();
5585 }
5586 }
5587
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005588 final void finishBooting() {
5589 // Ensure that any processes we had put on hold are now started
5590 // up.
5591 final int NP = mProcessesOnHold.size();
5592 if (NP > 0) {
5593 ArrayList<ProcessRecord> procs =
5594 new ArrayList<ProcessRecord>(mProcessesOnHold);
5595 for (int ip=0; ip<NP; ip++) {
5596 this.startProcessLocked(procs.get(ip), "on-hold", null);
5597 }
5598 }
5599 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5600 // Tell anyone interested that we are done booting!
5601 synchronized (this) {
5602 broadcastIntentLocked(null, null,
5603 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5604 null, null, 0, null, null,
5605 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5606 false, false, MY_PID, Process.SYSTEM_UID);
5607 }
5608 }
5609 }
5610
5611 final void ensureBootCompleted() {
5612 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005613 boolean enableScreen;
5614 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005615 booting = mBooting;
5616 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005617 enableScreen = !mBooted;
5618 mBooted = true;
5619 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005620
5621 if (booting) {
5622 finishBooting();
5623 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005624
5625 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005626 enableScreenAfterBoot();
5627 }
5628 }
5629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005630 public final void activityPaused(IBinder token, Bundle icicle) {
5631 // Refuse possible leaked file descriptors
5632 if (icicle != null && icicle.hasFileDescriptors()) {
5633 throw new IllegalArgumentException("File descriptors passed in Bundle");
5634 }
5635
5636 final long origId = Binder.clearCallingIdentity();
5637 activityPaused(token, icicle, false);
5638 Binder.restoreCallingIdentity(origId);
5639 }
5640
5641 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5642 if (DEBUG_PAUSE) Log.v(
5643 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5644 + ", timeout=" + timeout);
5645
5646 HistoryRecord r = null;
5647
5648 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005649 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005650 if (index >= 0) {
5651 r = (HistoryRecord)mHistory.get(index);
5652 if (!timeout) {
5653 r.icicle = icicle;
5654 r.haveState = true;
5655 }
5656 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5657 if (mPausingActivity == r) {
5658 r.state = ActivityState.PAUSED;
5659 completePauseLocked();
5660 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005661 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005662 System.identityHashCode(r), r.shortComponentName,
5663 mPausingActivity != null
5664 ? mPausingActivity.shortComponentName : "(none)");
5665 }
5666 }
5667 }
5668 }
5669
5670 public final void activityStopped(IBinder token, Bitmap thumbnail,
5671 CharSequence description) {
5672 if (localLOGV) Log.v(
5673 TAG, "Activity stopped: token=" + token);
5674
5675 HistoryRecord r = null;
5676
5677 final long origId = Binder.clearCallingIdentity();
5678
5679 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005680 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005681 if (index >= 0) {
5682 r = (HistoryRecord)mHistory.get(index);
5683 r.thumbnail = thumbnail;
5684 r.description = description;
5685 r.stopped = true;
5686 r.state = ActivityState.STOPPED;
5687 if (!r.finishing) {
5688 if (r.configDestroy) {
5689 destroyActivityLocked(r, true);
5690 resumeTopActivityLocked(null);
5691 }
5692 }
5693 }
5694 }
5695
5696 if (r != null) {
5697 sendPendingThumbnail(r, null, null, null, false);
5698 }
5699
5700 trimApplications();
5701
5702 Binder.restoreCallingIdentity(origId);
5703 }
5704
5705 public final void activityDestroyed(IBinder token) {
5706 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5707 synchronized (this) {
5708 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5709
Dianne Hackborn75b03852009-06-12 15:43:26 -07005710 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005711 if (index >= 0) {
5712 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5713 if (r.state == ActivityState.DESTROYING) {
5714 final long origId = Binder.clearCallingIdentity();
5715 removeActivityFromHistoryLocked(r);
5716 Binder.restoreCallingIdentity(origId);
5717 }
5718 }
5719 }
5720 }
5721
5722 public String getCallingPackage(IBinder token) {
5723 synchronized (this) {
5724 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005725 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005726 }
5727 }
5728
5729 public ComponentName getCallingActivity(IBinder token) {
5730 synchronized (this) {
5731 HistoryRecord r = getCallingRecordLocked(token);
5732 return r != null ? r.intent.getComponent() : null;
5733 }
5734 }
5735
5736 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005737 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005738 if (index >= 0) {
5739 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5740 if (r != null) {
5741 return r.resultTo;
5742 }
5743 }
5744 return null;
5745 }
5746
5747 public ComponentName getActivityClassForToken(IBinder token) {
5748 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005749 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005750 if (index >= 0) {
5751 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5752 return r.intent.getComponent();
5753 }
5754 return null;
5755 }
5756 }
5757
5758 public String getPackageForToken(IBinder token) {
5759 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005760 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005761 if (index >= 0) {
5762 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5763 return r.packageName;
5764 }
5765 return null;
5766 }
5767 }
5768
5769 public IIntentSender getIntentSender(int type,
5770 String packageName, IBinder token, String resultWho,
5771 int requestCode, Intent intent, String resolvedType, int flags) {
5772 // Refuse possible leaked file descriptors
5773 if (intent != null && intent.hasFileDescriptors() == true) {
5774 throw new IllegalArgumentException("File descriptors passed in Intent");
5775 }
5776
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005777 if (type == INTENT_SENDER_BROADCAST) {
5778 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5779 throw new IllegalArgumentException(
5780 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5781 }
5782 }
5783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005784 synchronized(this) {
5785 int callingUid = Binder.getCallingUid();
5786 try {
5787 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5788 Process.supportsProcesses()) {
5789 int uid = ActivityThread.getPackageManager()
5790 .getPackageUid(packageName);
5791 if (uid != Binder.getCallingUid()) {
5792 String msg = "Permission Denial: getIntentSender() from pid="
5793 + Binder.getCallingPid()
5794 + ", uid=" + Binder.getCallingUid()
5795 + ", (need uid=" + uid + ")"
5796 + " is not allowed to send as package " + packageName;
5797 Log.w(TAG, msg);
5798 throw new SecurityException(msg);
5799 }
5800 }
5801 } catch (RemoteException e) {
5802 throw new SecurityException(e);
5803 }
5804 HistoryRecord activity = null;
5805 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005806 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005807 if (index < 0) {
5808 return null;
5809 }
5810 activity = (HistoryRecord)mHistory.get(index);
5811 if (activity.finishing) {
5812 return null;
5813 }
5814 }
5815
5816 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5817 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5818 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5819 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5820 |PendingIntent.FLAG_UPDATE_CURRENT);
5821
5822 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5823 type, packageName, activity, resultWho,
5824 requestCode, intent, resolvedType, flags);
5825 WeakReference<PendingIntentRecord> ref;
5826 ref = mIntentSenderRecords.get(key);
5827 PendingIntentRecord rec = ref != null ? ref.get() : null;
5828 if (rec != null) {
5829 if (!cancelCurrent) {
5830 if (updateCurrent) {
5831 rec.key.requestIntent.replaceExtras(intent);
5832 }
5833 return rec;
5834 }
5835 rec.canceled = true;
5836 mIntentSenderRecords.remove(key);
5837 }
5838 if (noCreate) {
5839 return rec;
5840 }
5841 rec = new PendingIntentRecord(this, key, callingUid);
5842 mIntentSenderRecords.put(key, rec.ref);
5843 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5844 if (activity.pendingResults == null) {
5845 activity.pendingResults
5846 = new HashSet<WeakReference<PendingIntentRecord>>();
5847 }
5848 activity.pendingResults.add(rec.ref);
5849 }
5850 return rec;
5851 }
5852 }
5853
5854 public void cancelIntentSender(IIntentSender sender) {
5855 if (!(sender instanceof PendingIntentRecord)) {
5856 return;
5857 }
5858 synchronized(this) {
5859 PendingIntentRecord rec = (PendingIntentRecord)sender;
5860 try {
5861 int uid = ActivityThread.getPackageManager()
5862 .getPackageUid(rec.key.packageName);
5863 if (uid != Binder.getCallingUid()) {
5864 String msg = "Permission Denial: cancelIntentSender() from pid="
5865 + Binder.getCallingPid()
5866 + ", uid=" + Binder.getCallingUid()
5867 + " is not allowed to cancel packges "
5868 + rec.key.packageName;
5869 Log.w(TAG, msg);
5870 throw new SecurityException(msg);
5871 }
5872 } catch (RemoteException e) {
5873 throw new SecurityException(e);
5874 }
5875 cancelIntentSenderLocked(rec, true);
5876 }
5877 }
5878
5879 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5880 rec.canceled = true;
5881 mIntentSenderRecords.remove(rec.key);
5882 if (cleanActivity && rec.key.activity != null) {
5883 rec.key.activity.pendingResults.remove(rec.ref);
5884 }
5885 }
5886
5887 public String getPackageForIntentSender(IIntentSender pendingResult) {
5888 if (!(pendingResult instanceof PendingIntentRecord)) {
5889 return null;
5890 }
5891 synchronized(this) {
5892 try {
5893 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5894 return res.key.packageName;
5895 } catch (ClassCastException e) {
5896 }
5897 }
5898 return null;
5899 }
5900
5901 public void setProcessLimit(int max) {
5902 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5903 "setProcessLimit()");
5904 mProcessLimit = max;
5905 }
5906
5907 public int getProcessLimit() {
5908 return mProcessLimit;
5909 }
5910
5911 void foregroundTokenDied(ForegroundToken token) {
5912 synchronized (ActivityManagerService.this) {
5913 synchronized (mPidsSelfLocked) {
5914 ForegroundToken cur
5915 = mForegroundProcesses.get(token.pid);
5916 if (cur != token) {
5917 return;
5918 }
5919 mForegroundProcesses.remove(token.pid);
5920 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5921 if (pr == null) {
5922 return;
5923 }
5924 pr.forcingToForeground = null;
5925 pr.foregroundServices = false;
5926 }
5927 updateOomAdjLocked();
5928 }
5929 }
5930
5931 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5932 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5933 "setProcessForeground()");
5934 synchronized(this) {
5935 boolean changed = false;
5936
5937 synchronized (mPidsSelfLocked) {
5938 ProcessRecord pr = mPidsSelfLocked.get(pid);
5939 if (pr == null) {
5940 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5941 return;
5942 }
5943 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5944 if (oldToken != null) {
5945 oldToken.token.unlinkToDeath(oldToken, 0);
5946 mForegroundProcesses.remove(pid);
5947 pr.forcingToForeground = null;
5948 changed = true;
5949 }
5950 if (isForeground && token != null) {
5951 ForegroundToken newToken = new ForegroundToken() {
5952 public void binderDied() {
5953 foregroundTokenDied(this);
5954 }
5955 };
5956 newToken.pid = pid;
5957 newToken.token = token;
5958 try {
5959 token.linkToDeath(newToken, 0);
5960 mForegroundProcesses.put(pid, newToken);
5961 pr.forcingToForeground = token;
5962 changed = true;
5963 } catch (RemoteException e) {
5964 // If the process died while doing this, we will later
5965 // do the cleanup with the process death link.
5966 }
5967 }
5968 }
5969
5970 if (changed) {
5971 updateOomAdjLocked();
5972 }
5973 }
5974 }
5975
5976 // =========================================================
5977 // PERMISSIONS
5978 // =========================================================
5979
5980 static class PermissionController extends IPermissionController.Stub {
5981 ActivityManagerService mActivityManagerService;
5982 PermissionController(ActivityManagerService activityManagerService) {
5983 mActivityManagerService = activityManagerService;
5984 }
5985
5986 public boolean checkPermission(String permission, int pid, int uid) {
5987 return mActivityManagerService.checkPermission(permission, pid,
5988 uid) == PackageManager.PERMISSION_GRANTED;
5989 }
5990 }
5991
5992 /**
5993 * This can be called with or without the global lock held.
5994 */
5995 int checkComponentPermission(String permission, int pid, int uid,
5996 int reqUid) {
5997 // We might be performing an operation on behalf of an indirect binder
5998 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5999 // client identity accordingly before proceeding.
6000 Identity tlsIdentity = sCallerIdentity.get();
6001 if (tlsIdentity != null) {
6002 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6003 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6004 uid = tlsIdentity.uid;
6005 pid = tlsIdentity.pid;
6006 }
6007
6008 // Root, system server and our own process get to do everything.
6009 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6010 !Process.supportsProcesses()) {
6011 return PackageManager.PERMISSION_GRANTED;
6012 }
6013 // If the target requires a specific UID, always fail for others.
6014 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006015 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006016 return PackageManager.PERMISSION_DENIED;
6017 }
6018 if (permission == null) {
6019 return PackageManager.PERMISSION_GRANTED;
6020 }
6021 try {
6022 return ActivityThread.getPackageManager()
6023 .checkUidPermission(permission, uid);
6024 } catch (RemoteException e) {
6025 // Should never happen, but if it does... deny!
6026 Log.e(TAG, "PackageManager is dead?!?", e);
6027 }
6028 return PackageManager.PERMISSION_DENIED;
6029 }
6030
6031 /**
6032 * As the only public entry point for permissions checking, this method
6033 * can enforce the semantic that requesting a check on a null global
6034 * permission is automatically denied. (Internally a null permission
6035 * string is used when calling {@link #checkComponentPermission} in cases
6036 * when only uid-based security is needed.)
6037 *
6038 * This can be called with or without the global lock held.
6039 */
6040 public int checkPermission(String permission, int pid, int uid) {
6041 if (permission == null) {
6042 return PackageManager.PERMISSION_DENIED;
6043 }
6044 return checkComponentPermission(permission, pid, uid, -1);
6045 }
6046
6047 /**
6048 * Binder IPC calls go through the public entry point.
6049 * This can be called with or without the global lock held.
6050 */
6051 int checkCallingPermission(String permission) {
6052 return checkPermission(permission,
6053 Binder.getCallingPid(),
6054 Binder.getCallingUid());
6055 }
6056
6057 /**
6058 * This can be called with or without the global lock held.
6059 */
6060 void enforceCallingPermission(String permission, String func) {
6061 if (checkCallingPermission(permission)
6062 == PackageManager.PERMISSION_GRANTED) {
6063 return;
6064 }
6065
6066 String msg = "Permission Denial: " + func + " from pid="
6067 + Binder.getCallingPid()
6068 + ", uid=" + Binder.getCallingUid()
6069 + " requires " + permission;
6070 Log.w(TAG, msg);
6071 throw new SecurityException(msg);
6072 }
6073
6074 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6075 ProviderInfo pi, int uid, int modeFlags) {
6076 try {
6077 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6078 if ((pi.readPermission != null) &&
6079 (pm.checkUidPermission(pi.readPermission, uid)
6080 != PackageManager.PERMISSION_GRANTED)) {
6081 return false;
6082 }
6083 }
6084 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6085 if ((pi.writePermission != null) &&
6086 (pm.checkUidPermission(pi.writePermission, uid)
6087 != PackageManager.PERMISSION_GRANTED)) {
6088 return false;
6089 }
6090 }
6091 return true;
6092 } catch (RemoteException e) {
6093 return false;
6094 }
6095 }
6096
6097 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6098 int modeFlags) {
6099 // Root gets to do everything.
6100 if (uid == 0 || !Process.supportsProcesses()) {
6101 return true;
6102 }
6103 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6104 if (perms == null) return false;
6105 UriPermission perm = perms.get(uri);
6106 if (perm == null) return false;
6107 return (modeFlags&perm.modeFlags) == modeFlags;
6108 }
6109
6110 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6111 // Another redirected-binder-call permissions check as in
6112 // {@link checkComponentPermission}.
6113 Identity tlsIdentity = sCallerIdentity.get();
6114 if (tlsIdentity != null) {
6115 uid = tlsIdentity.uid;
6116 pid = tlsIdentity.pid;
6117 }
6118
6119 // Our own process gets to do everything.
6120 if (pid == MY_PID) {
6121 return PackageManager.PERMISSION_GRANTED;
6122 }
6123 synchronized(this) {
6124 return checkUriPermissionLocked(uri, uid, modeFlags)
6125 ? PackageManager.PERMISSION_GRANTED
6126 : PackageManager.PERMISSION_DENIED;
6127 }
6128 }
6129
6130 private void grantUriPermissionLocked(int callingUid,
6131 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6132 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6133 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6134 if (modeFlags == 0) {
6135 return;
6136 }
6137
6138 final IPackageManager pm = ActivityThread.getPackageManager();
6139
6140 // If this is not a content: uri, we can't do anything with it.
6141 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6142 return;
6143 }
6144
6145 String name = uri.getAuthority();
6146 ProviderInfo pi = null;
6147 ContentProviderRecord cpr
6148 = (ContentProviderRecord)mProvidersByName.get(name);
6149 if (cpr != null) {
6150 pi = cpr.info;
6151 } else {
6152 try {
6153 pi = pm.resolveContentProvider(name,
6154 PackageManager.GET_URI_PERMISSION_PATTERNS);
6155 } catch (RemoteException ex) {
6156 }
6157 }
6158 if (pi == null) {
6159 Log.w(TAG, "No content provider found for: " + name);
6160 return;
6161 }
6162
6163 int targetUid;
6164 try {
6165 targetUid = pm.getPackageUid(targetPkg);
6166 if (targetUid < 0) {
6167 return;
6168 }
6169 } catch (RemoteException ex) {
6170 return;
6171 }
6172
6173 // First... does the target actually need this permission?
6174 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6175 // No need to grant the target this permission.
6176 return;
6177 }
6178
6179 // Second... maybe someone else has already granted the
6180 // permission?
6181 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6182 // No need to grant the target this permission.
6183 return;
6184 }
6185
6186 // Third... is the provider allowing granting of URI permissions?
6187 if (!pi.grantUriPermissions) {
6188 throw new SecurityException("Provider " + pi.packageName
6189 + "/" + pi.name
6190 + " does not allow granting of Uri permissions (uri "
6191 + uri + ")");
6192 }
6193 if (pi.uriPermissionPatterns != null) {
6194 final int N = pi.uriPermissionPatterns.length;
6195 boolean allowed = false;
6196 for (int i=0; i<N; i++) {
6197 if (pi.uriPermissionPatterns[i] != null
6198 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6199 allowed = true;
6200 break;
6201 }
6202 }
6203 if (!allowed) {
6204 throw new SecurityException("Provider " + pi.packageName
6205 + "/" + pi.name
6206 + " does not allow granting of permission to path of Uri "
6207 + uri);
6208 }
6209 }
6210
6211 // Fourth... does the caller itself have permission to access
6212 // this uri?
6213 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6214 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6215 throw new SecurityException("Uid " + callingUid
6216 + " does not have permission to uri " + uri);
6217 }
6218 }
6219
6220 // Okay! So here we are: the caller has the assumed permission
6221 // to the uri, and the target doesn't. Let's now give this to
6222 // the target.
6223
6224 HashMap<Uri, UriPermission> targetUris
6225 = mGrantedUriPermissions.get(targetUid);
6226 if (targetUris == null) {
6227 targetUris = new HashMap<Uri, UriPermission>();
6228 mGrantedUriPermissions.put(targetUid, targetUris);
6229 }
6230
6231 UriPermission perm = targetUris.get(uri);
6232 if (perm == null) {
6233 perm = new UriPermission(targetUid, uri);
6234 targetUris.put(uri, perm);
6235
6236 }
6237 perm.modeFlags |= modeFlags;
6238 if (activity == null) {
6239 perm.globalModeFlags |= modeFlags;
6240 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6241 perm.readActivities.add(activity);
6242 if (activity.readUriPermissions == null) {
6243 activity.readUriPermissions = new HashSet<UriPermission>();
6244 }
6245 activity.readUriPermissions.add(perm);
6246 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6247 perm.writeActivities.add(activity);
6248 if (activity.writeUriPermissions == null) {
6249 activity.writeUriPermissions = new HashSet<UriPermission>();
6250 }
6251 activity.writeUriPermissions.add(perm);
6252 }
6253 }
6254
6255 private void grantUriPermissionFromIntentLocked(int callingUid,
6256 String targetPkg, Intent intent, HistoryRecord activity) {
6257 if (intent == null) {
6258 return;
6259 }
6260 Uri data = intent.getData();
6261 if (data == null) {
6262 return;
6263 }
6264 grantUriPermissionLocked(callingUid, targetPkg, data,
6265 intent.getFlags(), activity);
6266 }
6267
6268 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6269 Uri uri, int modeFlags) {
6270 synchronized(this) {
6271 final ProcessRecord r = getRecordForAppLocked(caller);
6272 if (r == null) {
6273 throw new SecurityException("Unable to find app for caller "
6274 + caller
6275 + " when granting permission to uri " + uri);
6276 }
6277 if (targetPkg == null) {
6278 Log.w(TAG, "grantUriPermission: null target");
6279 return;
6280 }
6281 if (uri == null) {
6282 Log.w(TAG, "grantUriPermission: null uri");
6283 return;
6284 }
6285
6286 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6287 null);
6288 }
6289 }
6290
6291 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6292 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6293 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6294 HashMap<Uri, UriPermission> perms
6295 = mGrantedUriPermissions.get(perm.uid);
6296 if (perms != null) {
6297 perms.remove(perm.uri);
6298 if (perms.size() == 0) {
6299 mGrantedUriPermissions.remove(perm.uid);
6300 }
6301 }
6302 }
6303 }
6304
6305 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6306 if (activity.readUriPermissions != null) {
6307 for (UriPermission perm : activity.readUriPermissions) {
6308 perm.readActivities.remove(activity);
6309 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6310 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6311 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6312 removeUriPermissionIfNeededLocked(perm);
6313 }
6314 }
6315 }
6316 if (activity.writeUriPermissions != null) {
6317 for (UriPermission perm : activity.writeUriPermissions) {
6318 perm.writeActivities.remove(activity);
6319 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6320 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6321 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6322 removeUriPermissionIfNeededLocked(perm);
6323 }
6324 }
6325 }
6326 }
6327
6328 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6329 int modeFlags) {
6330 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6331 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6332 if (modeFlags == 0) {
6333 return;
6334 }
6335
6336 final IPackageManager pm = ActivityThread.getPackageManager();
6337
6338 final String authority = uri.getAuthority();
6339 ProviderInfo pi = null;
6340 ContentProviderRecord cpr
6341 = (ContentProviderRecord)mProvidersByName.get(authority);
6342 if (cpr != null) {
6343 pi = cpr.info;
6344 } else {
6345 try {
6346 pi = pm.resolveContentProvider(authority,
6347 PackageManager.GET_URI_PERMISSION_PATTERNS);
6348 } catch (RemoteException ex) {
6349 }
6350 }
6351 if (pi == null) {
6352 Log.w(TAG, "No content provider found for: " + authority);
6353 return;
6354 }
6355
6356 // Does the caller have this permission on the URI?
6357 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6358 // Right now, if you are not the original owner of the permission,
6359 // you are not allowed to revoke it.
6360 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6361 throw new SecurityException("Uid " + callingUid
6362 + " does not have permission to uri " + uri);
6363 //}
6364 }
6365
6366 // Go through all of the permissions and remove any that match.
6367 final List<String> SEGMENTS = uri.getPathSegments();
6368 if (SEGMENTS != null) {
6369 final int NS = SEGMENTS.size();
6370 int N = mGrantedUriPermissions.size();
6371 for (int i=0; i<N; i++) {
6372 HashMap<Uri, UriPermission> perms
6373 = mGrantedUriPermissions.valueAt(i);
6374 Iterator<UriPermission> it = perms.values().iterator();
6375 toploop:
6376 while (it.hasNext()) {
6377 UriPermission perm = it.next();
6378 Uri targetUri = perm.uri;
6379 if (!authority.equals(targetUri.getAuthority())) {
6380 continue;
6381 }
6382 List<String> targetSegments = targetUri.getPathSegments();
6383 if (targetSegments == null) {
6384 continue;
6385 }
6386 if (targetSegments.size() < NS) {
6387 continue;
6388 }
6389 for (int j=0; j<NS; j++) {
6390 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6391 continue toploop;
6392 }
6393 }
6394 perm.clearModes(modeFlags);
6395 if (perm.modeFlags == 0) {
6396 it.remove();
6397 }
6398 }
6399 if (perms.size() == 0) {
6400 mGrantedUriPermissions.remove(
6401 mGrantedUriPermissions.keyAt(i));
6402 N--;
6403 i--;
6404 }
6405 }
6406 }
6407 }
6408
6409 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6410 int modeFlags) {
6411 synchronized(this) {
6412 final ProcessRecord r = getRecordForAppLocked(caller);
6413 if (r == null) {
6414 throw new SecurityException("Unable to find app for caller "
6415 + caller
6416 + " when revoking permission to uri " + uri);
6417 }
6418 if (uri == null) {
6419 Log.w(TAG, "revokeUriPermission: null uri");
6420 return;
6421 }
6422
6423 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6424 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6425 if (modeFlags == 0) {
6426 return;
6427 }
6428
6429 final IPackageManager pm = ActivityThread.getPackageManager();
6430
6431 final String authority = uri.getAuthority();
6432 ProviderInfo pi = null;
6433 ContentProviderRecord cpr
6434 = (ContentProviderRecord)mProvidersByName.get(authority);
6435 if (cpr != null) {
6436 pi = cpr.info;
6437 } else {
6438 try {
6439 pi = pm.resolveContentProvider(authority,
6440 PackageManager.GET_URI_PERMISSION_PATTERNS);
6441 } catch (RemoteException ex) {
6442 }
6443 }
6444 if (pi == null) {
6445 Log.w(TAG, "No content provider found for: " + authority);
6446 return;
6447 }
6448
6449 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6450 }
6451 }
6452
6453 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6454 synchronized (this) {
6455 ProcessRecord app =
6456 who != null ? getRecordForAppLocked(who) : null;
6457 if (app == null) return;
6458
6459 Message msg = Message.obtain();
6460 msg.what = WAIT_FOR_DEBUGGER_MSG;
6461 msg.obj = app;
6462 msg.arg1 = waiting ? 1 : 0;
6463 mHandler.sendMessage(msg);
6464 }
6465 }
6466
6467 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6468 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006469 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006470 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006471 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006472 }
6473
6474 // =========================================================
6475 // TASK MANAGEMENT
6476 // =========================================================
6477
6478 public List getTasks(int maxNum, int flags,
6479 IThumbnailReceiver receiver) {
6480 ArrayList list = new ArrayList();
6481
6482 PendingThumbnailsRecord pending = null;
6483 IApplicationThread topThumbnail = null;
6484 HistoryRecord topRecord = null;
6485
6486 synchronized(this) {
6487 if (localLOGV) Log.v(
6488 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6489 + ", receiver=" + receiver);
6490
6491 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6492 != PackageManager.PERMISSION_GRANTED) {
6493 if (receiver != null) {
6494 // If the caller wants to wait for pending thumbnails,
6495 // it ain't gonna get them.
6496 try {
6497 receiver.finished();
6498 } catch (RemoteException ex) {
6499 }
6500 }
6501 String msg = "Permission Denial: getTasks() from pid="
6502 + Binder.getCallingPid()
6503 + ", uid=" + Binder.getCallingUid()
6504 + " requires " + android.Manifest.permission.GET_TASKS;
6505 Log.w(TAG, msg);
6506 throw new SecurityException(msg);
6507 }
6508
6509 int pos = mHistory.size()-1;
6510 HistoryRecord next =
6511 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6512 HistoryRecord top = null;
6513 CharSequence topDescription = null;
6514 TaskRecord curTask = null;
6515 int numActivities = 0;
6516 int numRunning = 0;
6517 while (pos >= 0 && maxNum > 0) {
6518 final HistoryRecord r = next;
6519 pos--;
6520 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6521
6522 // Initialize state for next task if needed.
6523 if (top == null ||
6524 (top.state == ActivityState.INITIALIZING
6525 && top.task == r.task)) {
6526 top = r;
6527 topDescription = r.description;
6528 curTask = r.task;
6529 numActivities = numRunning = 0;
6530 }
6531
6532 // Add 'r' into the current task.
6533 numActivities++;
6534 if (r.app != null && r.app.thread != null) {
6535 numRunning++;
6536 }
6537 if (topDescription == null) {
6538 topDescription = r.description;
6539 }
6540
6541 if (localLOGV) Log.v(
6542 TAG, r.intent.getComponent().flattenToShortString()
6543 + ": task=" + r.task);
6544
6545 // If the next one is a different task, generate a new
6546 // TaskInfo entry for what we have.
6547 if (next == null || next.task != curTask) {
6548 ActivityManager.RunningTaskInfo ci
6549 = new ActivityManager.RunningTaskInfo();
6550 ci.id = curTask.taskId;
6551 ci.baseActivity = r.intent.getComponent();
6552 ci.topActivity = top.intent.getComponent();
6553 ci.thumbnail = top.thumbnail;
6554 ci.description = topDescription;
6555 ci.numActivities = numActivities;
6556 ci.numRunning = numRunning;
6557 //System.out.println(
6558 // "#" + maxNum + ": " + " descr=" + ci.description);
6559 if (ci.thumbnail == null && receiver != null) {
6560 if (localLOGV) Log.v(
6561 TAG, "State=" + top.state + "Idle=" + top.idle
6562 + " app=" + top.app
6563 + " thr=" + (top.app != null ? top.app.thread : null));
6564 if (top.state == ActivityState.RESUMED
6565 || top.state == ActivityState.PAUSING) {
6566 if (top.idle && top.app != null
6567 && top.app.thread != null) {
6568 topRecord = top;
6569 topThumbnail = top.app.thread;
6570 } else {
6571 top.thumbnailNeeded = true;
6572 }
6573 }
6574 if (pending == null) {
6575 pending = new PendingThumbnailsRecord(receiver);
6576 }
6577 pending.pendingRecords.add(top);
6578 }
6579 list.add(ci);
6580 maxNum--;
6581 top = null;
6582 }
6583 }
6584
6585 if (pending != null) {
6586 mPendingThumbnails.add(pending);
6587 }
6588 }
6589
6590 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6591
6592 if (topThumbnail != null) {
6593 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6594 try {
6595 topThumbnail.requestThumbnail(topRecord);
6596 } catch (Exception e) {
6597 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6598 sendPendingThumbnail(null, topRecord, null, null, true);
6599 }
6600 }
6601
6602 if (pending == null && receiver != null) {
6603 // In this case all thumbnails were available and the client
6604 // is being asked to be told when the remaining ones come in...
6605 // which is unusually, since the top-most currently running
6606 // activity should never have a canned thumbnail! Oh well.
6607 try {
6608 receiver.finished();
6609 } catch (RemoteException ex) {
6610 }
6611 }
6612
6613 return list;
6614 }
6615
6616 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6617 int flags) {
6618 synchronized (this) {
6619 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6620 "getRecentTasks()");
6621
6622 final int N = mRecentTasks.size();
6623 ArrayList<ActivityManager.RecentTaskInfo> res
6624 = new ArrayList<ActivityManager.RecentTaskInfo>(
6625 maxNum < N ? maxNum : N);
6626 for (int i=0; i<N && maxNum > 0; i++) {
6627 TaskRecord tr = mRecentTasks.get(i);
6628 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6629 || (tr.intent == null)
6630 || ((tr.intent.getFlags()
6631 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6632 ActivityManager.RecentTaskInfo rti
6633 = new ActivityManager.RecentTaskInfo();
6634 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6635 rti.baseIntent = new Intent(
6636 tr.intent != null ? tr.intent : tr.affinityIntent);
6637 rti.origActivity = tr.origActivity;
6638 res.add(rti);
6639 maxNum--;
6640 }
6641 }
6642 return res;
6643 }
6644 }
6645
6646 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6647 int j;
6648 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6649 TaskRecord jt = startTask;
6650
6651 // First look backwards
6652 for (j=startIndex-1; j>=0; j--) {
6653 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6654 if (r.task != jt) {
6655 jt = r.task;
6656 if (affinity.equals(jt.affinity)) {
6657 return j;
6658 }
6659 }
6660 }
6661
6662 // Now look forwards
6663 final int N = mHistory.size();
6664 jt = startTask;
6665 for (j=startIndex+1; j<N; j++) {
6666 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6667 if (r.task != jt) {
6668 if (affinity.equals(jt.affinity)) {
6669 return j;
6670 }
6671 jt = r.task;
6672 }
6673 }
6674
6675 // Might it be at the top?
6676 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6677 return N-1;
6678 }
6679
6680 return -1;
6681 }
6682
6683 /**
6684 * Perform a reset of the given task, if needed as part of launching it.
6685 * Returns the new HistoryRecord at the top of the task.
6686 */
6687 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6688 HistoryRecord newActivity) {
6689 boolean forceReset = (newActivity.info.flags
6690 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6691 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6692 if ((newActivity.info.flags
6693 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6694 forceReset = true;
6695 }
6696 }
6697
6698 final TaskRecord task = taskTop.task;
6699
6700 // We are going to move through the history list so that we can look
6701 // at each activity 'target' with 'below' either the interesting
6702 // activity immediately below it in the stack or null.
6703 HistoryRecord target = null;
6704 int targetI = 0;
6705 int taskTopI = -1;
6706 int replyChainEnd = -1;
6707 int lastReparentPos = -1;
6708 for (int i=mHistory.size()-1; i>=-1; i--) {
6709 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6710
6711 if (below != null && below.finishing) {
6712 continue;
6713 }
6714 if (target == null) {
6715 target = below;
6716 targetI = i;
6717 // If we were in the middle of a reply chain before this
6718 // task, it doesn't appear like the root of the chain wants
6719 // anything interesting, so drop it.
6720 replyChainEnd = -1;
6721 continue;
6722 }
6723
6724 final int flags = target.info.flags;
6725
6726 final boolean finishOnTaskLaunch =
6727 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6728 final boolean allowTaskReparenting =
6729 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6730
6731 if (target.task == task) {
6732 // We are inside of the task being reset... we'll either
6733 // finish this activity, push it out for another task,
6734 // or leave it as-is. We only do this
6735 // for activities that are not the root of the task (since
6736 // if we finish the root, we may no longer have the task!).
6737 if (taskTopI < 0) {
6738 taskTopI = targetI;
6739 }
6740 if (below != null && below.task == task) {
6741 final boolean clearWhenTaskReset =
6742 (target.intent.getFlags()
6743 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006744 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006745 // If this activity is sending a reply to a previous
6746 // activity, we can't do anything with it now until
6747 // we reach the start of the reply chain.
6748 // XXX note that we are assuming the result is always
6749 // to the previous activity, which is almost always
6750 // the case but we really shouldn't count on.
6751 if (replyChainEnd < 0) {
6752 replyChainEnd = targetI;
6753 }
Ed Heyl73798232009-03-24 21:32:21 -07006754 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006755 && target.taskAffinity != null
6756 && !target.taskAffinity.equals(task.affinity)) {
6757 // If this activity has an affinity for another
6758 // task, then we need to move it out of here. We will
6759 // move it as far out of the way as possible, to the
6760 // bottom of the activity stack. This also keeps it
6761 // correctly ordered with any activities we previously
6762 // moved.
6763 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6764 if (target.taskAffinity != null
6765 && target.taskAffinity.equals(p.task.affinity)) {
6766 // If the activity currently at the bottom has the
6767 // same task affinity as the one we are moving,
6768 // then merge it into the same task.
6769 target.task = p.task;
6770 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6771 + " out to bottom task " + p.task);
6772 } else {
6773 mCurTask++;
6774 if (mCurTask <= 0) {
6775 mCurTask = 1;
6776 }
6777 target.task = new TaskRecord(mCurTask, target.info, null,
6778 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6779 target.task.affinityIntent = target.intent;
6780 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6781 + " out to new task " + target.task);
6782 }
6783 mWindowManager.setAppGroupId(target, task.taskId);
6784 if (replyChainEnd < 0) {
6785 replyChainEnd = targetI;
6786 }
6787 int dstPos = 0;
6788 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6789 p = (HistoryRecord)mHistory.get(srcPos);
6790 if (p.finishing) {
6791 continue;
6792 }
6793 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6794 + " out to target's task " + target.task);
6795 task.numActivities--;
6796 p.task = target.task;
6797 target.task.numActivities++;
6798 mHistory.remove(srcPos);
6799 mHistory.add(dstPos, p);
6800 mWindowManager.moveAppToken(dstPos, p);
6801 mWindowManager.setAppGroupId(p, p.task.taskId);
6802 dstPos++;
6803 if (VALIDATE_TOKENS) {
6804 mWindowManager.validateAppTokens(mHistory);
6805 }
6806 i++;
6807 }
6808 if (taskTop == p) {
6809 taskTop = below;
6810 }
6811 if (taskTopI == replyChainEnd) {
6812 taskTopI = -1;
6813 }
6814 replyChainEnd = -1;
6815 addRecentTask(target.task);
6816 } else if (forceReset || finishOnTaskLaunch
6817 || clearWhenTaskReset) {
6818 // If the activity should just be removed -- either
6819 // because it asks for it, or the task should be
6820 // cleared -- then finish it and anything that is
6821 // part of its reply chain.
6822 if (clearWhenTaskReset) {
6823 // In this case, we want to finish this activity
6824 // and everything above it, so be sneaky and pretend
6825 // like these are all in the reply chain.
6826 replyChainEnd = targetI+1;
6827 while (replyChainEnd < mHistory.size() &&
6828 ((HistoryRecord)mHistory.get(
6829 replyChainEnd)).task == task) {
6830 replyChainEnd++;
6831 }
6832 replyChainEnd--;
6833 } else if (replyChainEnd < 0) {
6834 replyChainEnd = targetI;
6835 }
6836 HistoryRecord p = null;
6837 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6838 p = (HistoryRecord)mHistory.get(srcPos);
6839 if (p.finishing) {
6840 continue;
6841 }
6842 if (finishActivityLocked(p, srcPos,
6843 Activity.RESULT_CANCELED, null, "reset")) {
6844 replyChainEnd--;
6845 srcPos--;
6846 }
6847 }
6848 if (taskTop == p) {
6849 taskTop = below;
6850 }
6851 if (taskTopI == replyChainEnd) {
6852 taskTopI = -1;
6853 }
6854 replyChainEnd = -1;
6855 } else {
6856 // If we were in the middle of a chain, well the
6857 // activity that started it all doesn't want anything
6858 // special, so leave it all as-is.
6859 replyChainEnd = -1;
6860 }
6861 } else {
6862 // Reached the bottom of the task -- any reply chain
6863 // should be left as-is.
6864 replyChainEnd = -1;
6865 }
6866
6867 } else if (target.resultTo != null) {
6868 // If this activity is sending a reply to a previous
6869 // activity, we can't do anything with it now until
6870 // we reach the start of the reply chain.
6871 // XXX note that we are assuming the result is always
6872 // to the previous activity, which is almost always
6873 // the case but we really shouldn't count on.
6874 if (replyChainEnd < 0) {
6875 replyChainEnd = targetI;
6876 }
6877
6878 } else if (taskTopI >= 0 && allowTaskReparenting
6879 && task.affinity != null
6880 && task.affinity.equals(target.taskAffinity)) {
6881 // We are inside of another task... if this activity has
6882 // an affinity for our task, then either remove it if we are
6883 // clearing or move it over to our task. Note that
6884 // we currently punt on the case where we are resetting a
6885 // task that is not at the top but who has activities above
6886 // with an affinity to it... this is really not a normal
6887 // case, and we will need to later pull that task to the front
6888 // and usually at that point we will do the reset and pick
6889 // up those remaining activities. (This only happens if
6890 // someone starts an activity in a new task from an activity
6891 // in a task that is not currently on top.)
6892 if (forceReset || finishOnTaskLaunch) {
6893 if (replyChainEnd < 0) {
6894 replyChainEnd = targetI;
6895 }
6896 HistoryRecord p = null;
6897 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6898 p = (HistoryRecord)mHistory.get(srcPos);
6899 if (p.finishing) {
6900 continue;
6901 }
6902 if (finishActivityLocked(p, srcPos,
6903 Activity.RESULT_CANCELED, null, "reset")) {
6904 taskTopI--;
6905 lastReparentPos--;
6906 replyChainEnd--;
6907 srcPos--;
6908 }
6909 }
6910 replyChainEnd = -1;
6911 } else {
6912 if (replyChainEnd < 0) {
6913 replyChainEnd = targetI;
6914 }
6915 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6916 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6917 if (p.finishing) {
6918 continue;
6919 }
6920 if (lastReparentPos < 0) {
6921 lastReparentPos = taskTopI;
6922 taskTop = p;
6923 } else {
6924 lastReparentPos--;
6925 }
6926 mHistory.remove(srcPos);
6927 p.task.numActivities--;
6928 p.task = task;
6929 mHistory.add(lastReparentPos, p);
6930 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6931 + " in to resetting task " + task);
6932 task.numActivities++;
6933 mWindowManager.moveAppToken(lastReparentPos, p);
6934 mWindowManager.setAppGroupId(p, p.task.taskId);
6935 if (VALIDATE_TOKENS) {
6936 mWindowManager.validateAppTokens(mHistory);
6937 }
6938 }
6939 replyChainEnd = -1;
6940
6941 // Now we've moved it in to place... but what if this is
6942 // a singleTop activity and we have put it on top of another
6943 // instance of the same activity? Then we drop the instance
6944 // below so it remains singleTop.
6945 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6946 for (int j=lastReparentPos-1; j>=0; j--) {
6947 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6948 if (p.finishing) {
6949 continue;
6950 }
6951 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6952 if (finishActivityLocked(p, j,
6953 Activity.RESULT_CANCELED, null, "replace")) {
6954 taskTopI--;
6955 lastReparentPos--;
6956 }
6957 }
6958 }
6959 }
6960 }
6961 }
6962
6963 target = below;
6964 targetI = i;
6965 }
6966
6967 return taskTop;
6968 }
6969
6970 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006971 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006972 */
6973 public void moveTaskToFront(int task) {
6974 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6975 "moveTaskToFront()");
6976
6977 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006978 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6979 Binder.getCallingUid(), "Task to front")) {
6980 return;
6981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006982 final long origId = Binder.clearCallingIdentity();
6983 try {
6984 int N = mRecentTasks.size();
6985 for (int i=0; i<N; i++) {
6986 TaskRecord tr = mRecentTasks.get(i);
6987 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006988 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006989 return;
6990 }
6991 }
6992 for (int i=mHistory.size()-1; i>=0; i--) {
6993 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6994 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006995 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006996 return;
6997 }
6998 }
6999 } finally {
7000 Binder.restoreCallingIdentity(origId);
7001 }
7002 }
7003 }
7004
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007005 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007006 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7007
7008 final int task = tr.taskId;
7009 int top = mHistory.size()-1;
7010
7011 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7012 // nothing to do!
7013 return;
7014 }
7015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007016 ArrayList moved = new ArrayList();
7017
7018 // Applying the affinities may have removed entries from the history,
7019 // so get the size again.
7020 top = mHistory.size()-1;
7021 int pos = top;
7022
7023 // Shift all activities with this task up to the top
7024 // of the stack, keeping them in the same internal order.
7025 while (pos >= 0) {
7026 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7027 if (localLOGV) Log.v(
7028 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7029 boolean first = true;
7030 if (r.task.taskId == task) {
7031 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7032 mHistory.remove(pos);
7033 mHistory.add(top, r);
7034 moved.add(0, r);
7035 top--;
7036 if (first) {
7037 addRecentTask(r.task);
7038 first = false;
7039 }
7040 }
7041 pos--;
7042 }
7043
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007044 if (DEBUG_TRANSITION) Log.v(TAG,
7045 "Prepare to front transition: task=" + tr);
7046 if (reason != null &&
7047 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7048 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7049 HistoryRecord r = topRunningActivityLocked(null);
7050 if (r != null) {
7051 mNoAnimActivities.add(r);
7052 }
7053 } else {
7054 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7055 }
7056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007057 mWindowManager.moveAppTokensToTop(moved);
7058 if (VALIDATE_TOKENS) {
7059 mWindowManager.validateAppTokens(mHistory);
7060 }
7061
7062 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007063 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007064 }
7065
7066 private final void finishTaskMove(int task) {
7067 resumeTopActivityLocked(null);
7068 }
7069
7070 public void moveTaskToBack(int task) {
7071 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7072 "moveTaskToBack()");
7073
7074 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007075 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7076 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7077 Binder.getCallingUid(), "Task to back")) {
7078 return;
7079 }
7080 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007081 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007082 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007083 Binder.restoreCallingIdentity(origId);
7084 }
7085 }
7086
7087 /**
7088 * Moves an activity, and all of the other activities within the same task, to the bottom
7089 * of the history stack. The activity's order within the task is unchanged.
7090 *
7091 * @param token A reference to the activity we wish to move
7092 * @param nonRoot If false then this only works if the activity is the root
7093 * of a task; if true it will work for any activity in a task.
7094 * @return Returns true if the move completed, false if not.
7095 */
7096 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7097 synchronized(this) {
7098 final long origId = Binder.clearCallingIdentity();
7099 int taskId = getTaskForActivityLocked(token, !nonRoot);
7100 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007101 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007102 }
7103 Binder.restoreCallingIdentity(origId);
7104 }
7105 return false;
7106 }
7107
7108 /**
7109 * Worker method for rearranging history stack. Implements the function of moving all
7110 * activities for a specific task (gathering them if disjoint) into a single group at the
7111 * bottom of the stack.
7112 *
7113 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7114 * to premeptively cancel the move.
7115 *
7116 * @param task The taskId to collect and move to the bottom.
7117 * @return Returns true if the move completed, false if not.
7118 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007119 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007120 Log.i(TAG, "moveTaskToBack: " + task);
7121
7122 // If we have a watcher, preflight the move before committing to it. First check
7123 // for *other* available tasks, but if none are available, then try again allowing the
7124 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007125 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007126 HistoryRecord next = topRunningActivityLocked(null, task);
7127 if (next == null) {
7128 next = topRunningActivityLocked(null, 0);
7129 }
7130 if (next != null) {
7131 // ask watcher if this is allowed
7132 boolean moveOK = true;
7133 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007134 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007135 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007136 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007137 }
7138 if (!moveOK) {
7139 return false;
7140 }
7141 }
7142 }
7143
7144 ArrayList moved = new ArrayList();
7145
7146 if (DEBUG_TRANSITION) Log.v(TAG,
7147 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007148
7149 final int N = mHistory.size();
7150 int bottom = 0;
7151 int pos = 0;
7152
7153 // Shift all activities with this task down to the bottom
7154 // of the stack, keeping them in the same internal order.
7155 while (pos < N) {
7156 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7157 if (localLOGV) Log.v(
7158 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7159 if (r.task.taskId == task) {
7160 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7161 mHistory.remove(pos);
7162 mHistory.add(bottom, r);
7163 moved.add(r);
7164 bottom++;
7165 }
7166 pos++;
7167 }
7168
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007169 if (reason != null &&
7170 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7171 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7172 HistoryRecord r = topRunningActivityLocked(null);
7173 if (r != null) {
7174 mNoAnimActivities.add(r);
7175 }
7176 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007177 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007179 mWindowManager.moveAppTokensToBottom(moved);
7180 if (VALIDATE_TOKENS) {
7181 mWindowManager.validateAppTokens(mHistory);
7182 }
7183
7184 finishTaskMove(task);
7185 return true;
7186 }
7187
7188 public void moveTaskBackwards(int task) {
7189 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7190 "moveTaskBackwards()");
7191
7192 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007193 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7194 Binder.getCallingUid(), "Task backwards")) {
7195 return;
7196 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007197 final long origId = Binder.clearCallingIdentity();
7198 moveTaskBackwardsLocked(task);
7199 Binder.restoreCallingIdentity(origId);
7200 }
7201 }
7202
7203 private final void moveTaskBackwardsLocked(int task) {
7204 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7205 }
7206
7207 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7208 synchronized(this) {
7209 return getTaskForActivityLocked(token, onlyRoot);
7210 }
7211 }
7212
7213 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7214 final int N = mHistory.size();
7215 TaskRecord lastTask = null;
7216 for (int i=0; i<N; i++) {
7217 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7218 if (r == token) {
7219 if (!onlyRoot || lastTask != r.task) {
7220 return r.task.taskId;
7221 }
7222 return -1;
7223 }
7224 lastTask = r.task;
7225 }
7226
7227 return -1;
7228 }
7229
7230 /**
7231 * Returns the top activity in any existing task matching the given
7232 * Intent. Returns null if no such task is found.
7233 */
7234 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7235 ComponentName cls = intent.getComponent();
7236 if (info.targetActivity != null) {
7237 cls = new ComponentName(info.packageName, info.targetActivity);
7238 }
7239
7240 TaskRecord cp = null;
7241
7242 final int N = mHistory.size();
7243 for (int i=(N-1); i>=0; i--) {
7244 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7245 if (!r.finishing && r.task != cp
7246 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7247 cp = r.task;
7248 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7249 // + "/aff=" + r.task.affinity + " to new cls="
7250 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7251 if (r.task.affinity != null) {
7252 if (r.task.affinity.equals(info.taskAffinity)) {
7253 //Log.i(TAG, "Found matching affinity!");
7254 return r;
7255 }
7256 } else if (r.task.intent != null
7257 && r.task.intent.getComponent().equals(cls)) {
7258 //Log.i(TAG, "Found matching class!");
7259 //dump();
7260 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7261 return r;
7262 } else if (r.task.affinityIntent != null
7263 && r.task.affinityIntent.getComponent().equals(cls)) {
7264 //Log.i(TAG, "Found matching class!");
7265 //dump();
7266 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7267 return r;
7268 }
7269 }
7270 }
7271
7272 return null;
7273 }
7274
7275 /**
7276 * Returns the first activity (starting from the top of the stack) that
7277 * is the same as the given activity. Returns null if no such activity
7278 * is found.
7279 */
7280 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7281 ComponentName cls = intent.getComponent();
7282 if (info.targetActivity != null) {
7283 cls = new ComponentName(info.packageName, info.targetActivity);
7284 }
7285
7286 final int N = mHistory.size();
7287 for (int i=(N-1); i>=0; i--) {
7288 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7289 if (!r.finishing) {
7290 if (r.intent.getComponent().equals(cls)) {
7291 //Log.i(TAG, "Found matching class!");
7292 //dump();
7293 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7294 return r;
7295 }
7296 }
7297 }
7298
7299 return null;
7300 }
7301
7302 public void finishOtherInstances(IBinder token, ComponentName className) {
7303 synchronized(this) {
7304 final long origId = Binder.clearCallingIdentity();
7305
7306 int N = mHistory.size();
7307 TaskRecord lastTask = null;
7308 for (int i=0; i<N; i++) {
7309 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7310 if (r.realActivity.equals(className)
7311 && r != token && lastTask != r.task) {
7312 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7313 null, "others")) {
7314 i--;
7315 N--;
7316 }
7317 }
7318 lastTask = r.task;
7319 }
7320
7321 Binder.restoreCallingIdentity(origId);
7322 }
7323 }
7324
7325 // =========================================================
7326 // THUMBNAILS
7327 // =========================================================
7328
7329 public void reportThumbnail(IBinder token,
7330 Bitmap thumbnail, CharSequence description) {
7331 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7332 final long origId = Binder.clearCallingIdentity();
7333 sendPendingThumbnail(null, token, thumbnail, description, true);
7334 Binder.restoreCallingIdentity(origId);
7335 }
7336
7337 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7338 Bitmap thumbnail, CharSequence description, boolean always) {
7339 TaskRecord task = null;
7340 ArrayList receivers = null;
7341
7342 //System.out.println("Send pending thumbnail: " + r);
7343
7344 synchronized(this) {
7345 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007346 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007347 if (index < 0) {
7348 return;
7349 }
7350 r = (HistoryRecord)mHistory.get(index);
7351 }
7352 if (thumbnail == null) {
7353 thumbnail = r.thumbnail;
7354 description = r.description;
7355 }
7356 if (thumbnail == null && !always) {
7357 // If there is no thumbnail, and this entry is not actually
7358 // going away, then abort for now and pick up the next
7359 // thumbnail we get.
7360 return;
7361 }
7362 task = r.task;
7363
7364 int N = mPendingThumbnails.size();
7365 int i=0;
7366 while (i<N) {
7367 PendingThumbnailsRecord pr =
7368 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7369 //System.out.println("Looking in " + pr.pendingRecords);
7370 if (pr.pendingRecords.remove(r)) {
7371 if (receivers == null) {
7372 receivers = new ArrayList();
7373 }
7374 receivers.add(pr);
7375 if (pr.pendingRecords.size() == 0) {
7376 pr.finished = true;
7377 mPendingThumbnails.remove(i);
7378 N--;
7379 continue;
7380 }
7381 }
7382 i++;
7383 }
7384 }
7385
7386 if (receivers != null) {
7387 final int N = receivers.size();
7388 for (int i=0; i<N; i++) {
7389 try {
7390 PendingThumbnailsRecord pr =
7391 (PendingThumbnailsRecord)receivers.get(i);
7392 pr.receiver.newThumbnail(
7393 task != null ? task.taskId : -1, thumbnail, description);
7394 if (pr.finished) {
7395 pr.receiver.finished();
7396 }
7397 } catch (Exception e) {
7398 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7399 }
7400 }
7401 }
7402 }
7403
7404 // =========================================================
7405 // CONTENT PROVIDERS
7406 // =========================================================
7407
7408 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7409 List providers = null;
7410 try {
7411 providers = ActivityThread.getPackageManager().
7412 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007413 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007414 } catch (RemoteException ex) {
7415 }
7416 if (providers != null) {
7417 final int N = providers.size();
7418 for (int i=0; i<N; i++) {
7419 ProviderInfo cpi =
7420 (ProviderInfo)providers.get(i);
7421 ContentProviderRecord cpr =
7422 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7423 if (cpr == null) {
7424 cpr = new ContentProviderRecord(cpi, app.info);
7425 mProvidersByClass.put(cpi.name, cpr);
7426 }
7427 app.pubProviders.put(cpi.name, cpr);
7428 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007429 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007430 }
7431 }
7432 return providers;
7433 }
7434
7435 private final String checkContentProviderPermissionLocked(
7436 ProviderInfo cpi, ProcessRecord r, int mode) {
7437 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7438 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7439 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7440 cpi.exported ? -1 : cpi.applicationInfo.uid)
7441 == PackageManager.PERMISSION_GRANTED
7442 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7443 return null;
7444 }
7445 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7446 cpi.exported ? -1 : cpi.applicationInfo.uid)
7447 == PackageManager.PERMISSION_GRANTED) {
7448 return null;
7449 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007450
7451 PathPermission[] pps = cpi.pathPermissions;
7452 if (pps != null) {
7453 int i = pps.length;
7454 while (i > 0) {
7455 i--;
7456 PathPermission pp = pps[i];
7457 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7458 cpi.exported ? -1 : cpi.applicationInfo.uid)
7459 == PackageManager.PERMISSION_GRANTED
7460 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7461 return null;
7462 }
7463 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7464 cpi.exported ? -1 : cpi.applicationInfo.uid)
7465 == PackageManager.PERMISSION_GRANTED) {
7466 return null;
7467 }
7468 }
7469 }
7470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007471 String msg = "Permission Denial: opening provider " + cpi.name
7472 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7473 + ", uid=" + callingUid + ") requires "
7474 + cpi.readPermission + " or " + cpi.writePermission;
7475 Log.w(TAG, msg);
7476 return msg;
7477 }
7478
7479 private final ContentProviderHolder getContentProviderImpl(
7480 IApplicationThread caller, String name) {
7481 ContentProviderRecord cpr;
7482 ProviderInfo cpi = null;
7483
7484 synchronized(this) {
7485 ProcessRecord r = null;
7486 if (caller != null) {
7487 r = getRecordForAppLocked(caller);
7488 if (r == null) {
7489 throw new SecurityException(
7490 "Unable to find app for caller " + caller
7491 + " (pid=" + Binder.getCallingPid()
7492 + ") when getting content provider " + name);
7493 }
7494 }
7495
7496 // First check if this content provider has been published...
7497 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7498 if (cpr != null) {
7499 cpi = cpr.info;
7500 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7501 return new ContentProviderHolder(cpi,
7502 cpi.readPermission != null
7503 ? cpi.readPermission : cpi.writePermission);
7504 }
7505
7506 if (r != null && cpr.canRunHere(r)) {
7507 // This provider has been published or is in the process
7508 // of being published... but it is also allowed to run
7509 // in the caller's process, so don't make a connection
7510 // and just let the caller instantiate its own instance.
7511 if (cpr.provider != null) {
7512 // don't give caller the provider object, it needs
7513 // to make its own.
7514 cpr = new ContentProviderRecord(cpr);
7515 }
7516 return cpr;
7517 }
7518
7519 final long origId = Binder.clearCallingIdentity();
7520
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007521 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007522 // return it right away.
7523 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007524 if (DEBUG_PROVIDER) Log.v(TAG,
7525 "Adding provider requested by "
7526 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007527 + cpr.info.processName);
7528 Integer cnt = r.conProviders.get(cpr);
7529 if (cnt == null) {
7530 r.conProviders.put(cpr, new Integer(1));
7531 } else {
7532 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007534 cpr.clients.add(r);
7535 } else {
7536 cpr.externals++;
7537 }
7538
7539 if (cpr.app != null) {
7540 updateOomAdjLocked(cpr.app);
7541 }
7542
7543 Binder.restoreCallingIdentity(origId);
7544
7545 } else {
7546 try {
7547 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007548 resolveContentProvider(name,
7549 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007550 } catch (RemoteException ex) {
7551 }
7552 if (cpi == null) {
7553 return null;
7554 }
7555
7556 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7557 return new ContentProviderHolder(cpi,
7558 cpi.readPermission != null
7559 ? cpi.readPermission : cpi.writePermission);
7560 }
7561
7562 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7563 final boolean firstClass = cpr == null;
7564 if (firstClass) {
7565 try {
7566 ApplicationInfo ai =
7567 ActivityThread.getPackageManager().
7568 getApplicationInfo(
7569 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007570 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007571 if (ai == null) {
7572 Log.w(TAG, "No package info for content provider "
7573 + cpi.name);
7574 return null;
7575 }
7576 cpr = new ContentProviderRecord(cpi, ai);
7577 } catch (RemoteException ex) {
7578 // pm is in same process, this will never happen.
7579 }
7580 }
7581
7582 if (r != null && cpr.canRunHere(r)) {
7583 // If this is a multiprocess provider, then just return its
7584 // info and allow the caller to instantiate it. Only do
7585 // this if the provider is the same user as the caller's
7586 // process, or can run as root (so can be in any process).
7587 return cpr;
7588 }
7589
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007590 if (DEBUG_PROVIDER) {
7591 RuntimeException e = new RuntimeException("here");
7592 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7593 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007594 }
7595
7596 // This is single process, and our app is now connecting to it.
7597 // See if we are already in the process of launching this
7598 // provider.
7599 final int N = mLaunchingProviders.size();
7600 int i;
7601 for (i=0; i<N; i++) {
7602 if (mLaunchingProviders.get(i) == cpr) {
7603 break;
7604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007605 }
7606
7607 // If the provider is not already being launched, then get it
7608 // started.
7609 if (i >= N) {
7610 final long origId = Binder.clearCallingIdentity();
7611 ProcessRecord proc = startProcessLocked(cpi.processName,
7612 cpr.appInfo, false, 0, "content provider",
7613 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007614 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007615 if (proc == null) {
7616 Log.w(TAG, "Unable to launch app "
7617 + cpi.applicationInfo.packageName + "/"
7618 + cpi.applicationInfo.uid + " for provider "
7619 + name + ": process is bad");
7620 return null;
7621 }
7622 cpr.launchingApp = proc;
7623 mLaunchingProviders.add(cpr);
7624 Binder.restoreCallingIdentity(origId);
7625 }
7626
7627 // Make sure the provider is published (the same provider class
7628 // may be published under multiple names).
7629 if (firstClass) {
7630 mProvidersByClass.put(cpi.name, cpr);
7631 }
7632 mProvidersByName.put(name, cpr);
7633
7634 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007635 if (DEBUG_PROVIDER) Log.v(TAG,
7636 "Adding provider requested by "
7637 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007638 + cpr.info.processName);
7639 Integer cnt = r.conProviders.get(cpr);
7640 if (cnt == null) {
7641 r.conProviders.put(cpr, new Integer(1));
7642 } else {
7643 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7644 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007645 cpr.clients.add(r);
7646 } else {
7647 cpr.externals++;
7648 }
7649 }
7650 }
7651
7652 // Wait for the provider to be published...
7653 synchronized (cpr) {
7654 while (cpr.provider == null) {
7655 if (cpr.launchingApp == null) {
7656 Log.w(TAG, "Unable to launch app "
7657 + cpi.applicationInfo.packageName + "/"
7658 + cpi.applicationInfo.uid + " for provider "
7659 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007660 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007661 cpi.applicationInfo.packageName,
7662 cpi.applicationInfo.uid, name);
7663 return null;
7664 }
7665 try {
7666 cpr.wait();
7667 } catch (InterruptedException ex) {
7668 }
7669 }
7670 }
7671 return cpr;
7672 }
7673
7674 public final ContentProviderHolder getContentProvider(
7675 IApplicationThread caller, String name) {
7676 if (caller == null) {
7677 String msg = "null IApplicationThread when getting content provider "
7678 + name;
7679 Log.w(TAG, msg);
7680 throw new SecurityException(msg);
7681 }
7682
7683 return getContentProviderImpl(caller, name);
7684 }
7685
7686 private ContentProviderHolder getContentProviderExternal(String name) {
7687 return getContentProviderImpl(null, name);
7688 }
7689
7690 /**
7691 * Drop a content provider from a ProcessRecord's bookkeeping
7692 * @param cpr
7693 */
7694 public void removeContentProvider(IApplicationThread caller, String name) {
7695 synchronized (this) {
7696 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7697 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007698 // remove from mProvidersByClass
7699 if (DEBUG_PROVIDER) Log.v(TAG, name +
7700 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007701 return;
7702 }
7703 final ProcessRecord r = getRecordForAppLocked(caller);
7704 if (r == null) {
7705 throw new SecurityException(
7706 "Unable to find app for caller " + caller +
7707 " when removing content provider " + name);
7708 }
7709 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007710 ContentProviderRecord localCpr = (ContentProviderRecord)
7711 mProvidersByClass.get(cpr.info.name);
7712 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7713 + r.info.processName + " from process "
7714 + localCpr.appInfo.processName);
7715 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007716 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007717 Log.w(TAG, "removeContentProvider called on local provider: "
7718 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007719 return;
7720 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007721 Integer cnt = r.conProviders.get(localCpr);
7722 if (cnt == null || cnt.intValue() <= 1) {
7723 localCpr.clients.remove(r);
7724 r.conProviders.remove(localCpr);
7725 } else {
7726 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007728 }
7729 updateOomAdjLocked();
7730 }
7731 }
7732
7733 private void removeContentProviderExternal(String name) {
7734 synchronized (this) {
7735 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7736 if(cpr == null) {
7737 //remove from mProvidersByClass
7738 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7739 return;
7740 }
7741
7742 //update content provider record entry info
7743 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7744 localCpr.externals--;
7745 if (localCpr.externals < 0) {
7746 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7747 }
7748 updateOomAdjLocked();
7749 }
7750 }
7751
7752 public final void publishContentProviders(IApplicationThread caller,
7753 List<ContentProviderHolder> providers) {
7754 if (providers == null) {
7755 return;
7756 }
7757
7758 synchronized(this) {
7759 final ProcessRecord r = getRecordForAppLocked(caller);
7760 if (r == null) {
7761 throw new SecurityException(
7762 "Unable to find app for caller " + caller
7763 + " (pid=" + Binder.getCallingPid()
7764 + ") when publishing content providers");
7765 }
7766
7767 final long origId = Binder.clearCallingIdentity();
7768
7769 final int N = providers.size();
7770 for (int i=0; i<N; i++) {
7771 ContentProviderHolder src = providers.get(i);
7772 if (src == null || src.info == null || src.provider == null) {
7773 continue;
7774 }
7775 ContentProviderRecord dst =
7776 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7777 if (dst != null) {
7778 mProvidersByClass.put(dst.info.name, dst);
7779 String names[] = dst.info.authority.split(";");
7780 for (int j = 0; j < names.length; j++) {
7781 mProvidersByName.put(names[j], dst);
7782 }
7783
7784 int NL = mLaunchingProviders.size();
7785 int j;
7786 for (j=0; j<NL; j++) {
7787 if (mLaunchingProviders.get(j) == dst) {
7788 mLaunchingProviders.remove(j);
7789 j--;
7790 NL--;
7791 }
7792 }
7793 synchronized (dst) {
7794 dst.provider = src.provider;
7795 dst.app = r;
7796 dst.notifyAll();
7797 }
7798 updateOomAdjLocked(r);
7799 }
7800 }
7801
7802 Binder.restoreCallingIdentity(origId);
7803 }
7804 }
7805
7806 public static final void installSystemProviders() {
7807 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7808 List providers = mSelf.generateApplicationProvidersLocked(app);
7809 mSystemThread.installSystemProviders(providers);
7810 }
7811
7812 // =========================================================
7813 // GLOBAL MANAGEMENT
7814 // =========================================================
7815
7816 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7817 ApplicationInfo info, String customProcess) {
7818 String proc = customProcess != null ? customProcess : info.processName;
7819 BatteryStatsImpl.Uid.Proc ps = null;
7820 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7821 synchronized (stats) {
7822 ps = stats.getProcessStatsLocked(info.uid, proc);
7823 }
7824 return new ProcessRecord(ps, thread, info, proc);
7825 }
7826
7827 final ProcessRecord addAppLocked(ApplicationInfo info) {
7828 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7829
7830 if (app == null) {
7831 app = newProcessRecordLocked(null, info, null);
7832 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007833 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007834 }
7835
7836 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7837 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7838 app.persistent = true;
7839 app.maxAdj = CORE_SERVER_ADJ;
7840 }
7841 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7842 mPersistentStartingProcesses.add(app);
7843 startProcessLocked(app, "added application", app.processName);
7844 }
7845
7846 return app;
7847 }
7848
7849 public void unhandledBack() {
7850 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7851 "unhandledBack()");
7852
7853 synchronized(this) {
7854 int count = mHistory.size();
Dianne Hackborn03abb812010-01-04 18:43:19 -08007855 if (DEBUG_SWITCH) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007856 TAG, "Performing unhandledBack(): stack size = " + count);
7857 if (count > 1) {
7858 final long origId = Binder.clearCallingIdentity();
7859 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7860 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7861 Binder.restoreCallingIdentity(origId);
7862 }
7863 }
7864 }
7865
7866 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7867 String name = uri.getAuthority();
7868 ContentProviderHolder cph = getContentProviderExternal(name);
7869 ParcelFileDescriptor pfd = null;
7870 if (cph != null) {
7871 // We record the binder invoker's uid in thread-local storage before
7872 // going to the content provider to open the file. Later, in the code
7873 // that handles all permissions checks, we look for this uid and use
7874 // that rather than the Activity Manager's own uid. The effect is that
7875 // we do the check against the caller's permissions even though it looks
7876 // to the content provider like the Activity Manager itself is making
7877 // the request.
7878 sCallerIdentity.set(new Identity(
7879 Binder.getCallingPid(), Binder.getCallingUid()));
7880 try {
7881 pfd = cph.provider.openFile(uri, "r");
7882 } catch (FileNotFoundException e) {
7883 // do nothing; pfd will be returned null
7884 } finally {
7885 // Ensure that whatever happens, we clean up the identity state
7886 sCallerIdentity.remove();
7887 }
7888
7889 // We've got the fd now, so we're done with the provider.
7890 removeContentProviderExternal(name);
7891 } else {
7892 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7893 }
7894 return pfd;
7895 }
7896
7897 public void goingToSleep() {
7898 synchronized(this) {
7899 mSleeping = true;
7900 mWindowManager.setEventDispatching(false);
7901
7902 if (mResumedActivity != null) {
7903 pauseIfSleepingLocked();
7904 } else {
7905 Log.w(TAG, "goingToSleep with no resumed activity!");
7906 }
7907 }
7908 }
7909
Dianne Hackborn55280a92009-05-07 15:53:46 -07007910 public boolean shutdown(int timeout) {
7911 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7912 != PackageManager.PERMISSION_GRANTED) {
7913 throw new SecurityException("Requires permission "
7914 + android.Manifest.permission.SHUTDOWN);
7915 }
7916
7917 boolean timedout = false;
7918
7919 synchronized(this) {
7920 mShuttingDown = true;
7921 mWindowManager.setEventDispatching(false);
7922
7923 if (mResumedActivity != null) {
7924 pauseIfSleepingLocked();
7925 final long endTime = System.currentTimeMillis() + timeout;
7926 while (mResumedActivity != null || mPausingActivity != null) {
7927 long delay = endTime - System.currentTimeMillis();
7928 if (delay <= 0) {
7929 Log.w(TAG, "Activity manager shutdown timed out");
7930 timedout = true;
7931 break;
7932 }
7933 try {
7934 this.wait();
7935 } catch (InterruptedException e) {
7936 }
7937 }
7938 }
7939 }
7940
7941 mUsageStatsService.shutdown();
7942 mBatteryStatsService.shutdown();
7943
7944 return timedout;
7945 }
7946
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007947 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007948 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007949 if (!mGoingToSleep.isHeld()) {
7950 mGoingToSleep.acquire();
7951 if (mLaunchingActivity.isHeld()) {
7952 mLaunchingActivity.release();
7953 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7954 }
7955 }
7956
7957 // If we are not currently pausing an activity, get the current
7958 // one to pause. If we are pausing one, we will just let that stuff
7959 // run and release the wake lock when all done.
7960 if (mPausingActivity == null) {
7961 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7962 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7963 startPausingLocked(false, true);
7964 }
7965 }
7966 }
7967
7968 public void wakingUp() {
7969 synchronized(this) {
7970 if (mGoingToSleep.isHeld()) {
7971 mGoingToSleep.release();
7972 }
7973 mWindowManager.setEventDispatching(true);
7974 mSleeping = false;
7975 resumeTopActivityLocked(null);
7976 }
7977 }
7978
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007979 public void stopAppSwitches() {
7980 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7981 != PackageManager.PERMISSION_GRANTED) {
7982 throw new SecurityException("Requires permission "
7983 + android.Manifest.permission.STOP_APP_SWITCHES);
7984 }
7985
7986 synchronized(this) {
7987 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7988 + APP_SWITCH_DELAY_TIME;
7989 mDidAppSwitch = false;
7990 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7991 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7992 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7993 }
7994 }
7995
7996 public void resumeAppSwitches() {
7997 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7998 != PackageManager.PERMISSION_GRANTED) {
7999 throw new SecurityException("Requires permission "
8000 + android.Manifest.permission.STOP_APP_SWITCHES);
8001 }
8002
8003 synchronized(this) {
8004 // Note that we don't execute any pending app switches... we will
8005 // let those wait until either the timeout, or the next start
8006 // activity request.
8007 mAppSwitchesAllowedTime = 0;
8008 }
8009 }
8010
8011 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8012 String name) {
8013 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8014 return true;
8015 }
8016
8017 final int perm = checkComponentPermission(
8018 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8019 callingUid, -1);
8020 if (perm == PackageManager.PERMISSION_GRANTED) {
8021 return true;
8022 }
8023
8024 Log.w(TAG, name + " request from " + callingUid + " stopped");
8025 return false;
8026 }
8027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008028 public void setDebugApp(String packageName, boolean waitForDebugger,
8029 boolean persistent) {
8030 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8031 "setDebugApp()");
8032
8033 // Note that this is not really thread safe if there are multiple
8034 // callers into it at the same time, but that's not a situation we
8035 // care about.
8036 if (persistent) {
8037 final ContentResolver resolver = mContext.getContentResolver();
8038 Settings.System.putString(
8039 resolver, Settings.System.DEBUG_APP,
8040 packageName);
8041 Settings.System.putInt(
8042 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8043 waitForDebugger ? 1 : 0);
8044 }
8045
8046 synchronized (this) {
8047 if (!persistent) {
8048 mOrigDebugApp = mDebugApp;
8049 mOrigWaitForDebugger = mWaitForDebugger;
8050 }
8051 mDebugApp = packageName;
8052 mWaitForDebugger = waitForDebugger;
8053 mDebugTransient = !persistent;
8054 if (packageName != null) {
8055 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn03abb812010-01-04 18:43:19 -08008056 forceStopPackageLocked(packageName, -1, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008057 Binder.restoreCallingIdentity(origId);
8058 }
8059 }
8060 }
8061
8062 public void setAlwaysFinish(boolean enabled) {
8063 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8064 "setAlwaysFinish()");
8065
8066 Settings.System.putInt(
8067 mContext.getContentResolver(),
8068 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8069
8070 synchronized (this) {
8071 mAlwaysFinishActivities = enabled;
8072 }
8073 }
8074
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008075 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008076 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008077 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008078 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008079 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008080 }
8081 }
8082
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008083 public void registerActivityWatcher(IActivityWatcher watcher) {
8084 mWatchers.register(watcher);
8085 }
8086
8087 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8088 mWatchers.unregister(watcher);
8089 }
8090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008091 public final void enterSafeMode() {
8092 synchronized(this) {
8093 // It only makes sense to do this before the system is ready
8094 // and started launching other packages.
8095 if (!mSystemReady) {
8096 try {
8097 ActivityThread.getPackageManager().enterSafeMode();
8098 } catch (RemoteException e) {
8099 }
8100
8101 View v = LayoutInflater.from(mContext).inflate(
8102 com.android.internal.R.layout.safe_mode, null);
8103 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8104 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8105 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8106 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8107 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8108 lp.format = v.getBackground().getOpacity();
8109 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8110 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8111 ((WindowManager)mContext.getSystemService(
8112 Context.WINDOW_SERVICE)).addView(v, lp);
8113 }
8114 }
8115 }
8116
8117 public void noteWakeupAlarm(IIntentSender sender) {
8118 if (!(sender instanceof PendingIntentRecord)) {
8119 return;
8120 }
8121 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8122 synchronized (stats) {
8123 if (mBatteryStatsService.isOnBattery()) {
8124 mBatteryStatsService.enforceCallingPermission();
8125 PendingIntentRecord rec = (PendingIntentRecord)sender;
8126 int MY_UID = Binder.getCallingUid();
8127 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8128 BatteryStatsImpl.Uid.Pkg pkg =
8129 stats.getPackageStatsLocked(uid, rec.key.packageName);
8130 pkg.incWakeupsLocked();
8131 }
8132 }
8133 }
8134
8135 public boolean killPidsForMemory(int[] pids) {
8136 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8137 throw new SecurityException("killPidsForMemory only available to the system");
8138 }
8139
8140 // XXX Note: don't acquire main activity lock here, because the window
8141 // manager calls in with its locks held.
8142
8143 boolean killed = false;
8144 synchronized (mPidsSelfLocked) {
8145 int[] types = new int[pids.length];
8146 int worstType = 0;
8147 for (int i=0; i<pids.length; i++) {
8148 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8149 if (proc != null) {
8150 int type = proc.setAdj;
8151 types[i] = type;
8152 if (type > worstType) {
8153 worstType = type;
8154 }
8155 }
8156 }
8157
8158 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8159 // then constrain it so we will kill all hidden procs.
8160 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8161 worstType = HIDDEN_APP_MIN_ADJ;
8162 }
8163 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8164 for (int i=0; i<pids.length; i++) {
8165 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8166 if (proc == null) {
8167 continue;
8168 }
8169 int adj = proc.setAdj;
8170 if (adj >= worstType) {
8171 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8172 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008173 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008174 proc.processName, adj);
8175 killed = true;
8176 Process.killProcess(pids[i]);
8177 }
8178 }
8179 }
8180 return killed;
8181 }
8182
8183 public void reportPss(IApplicationThread caller, int pss) {
8184 Watchdog.PssRequestor req;
8185 String name;
8186 ProcessRecord callerApp;
8187 synchronized (this) {
8188 if (caller == null) {
8189 return;
8190 }
8191 callerApp = getRecordForAppLocked(caller);
8192 if (callerApp == null) {
8193 return;
8194 }
8195 callerApp.lastPss = pss;
8196 req = callerApp;
8197 name = callerApp.processName;
8198 }
8199 Watchdog.getInstance().reportPss(req, name, pss);
8200 if (!callerApp.persistent) {
8201 removeRequestedPss(callerApp);
8202 }
8203 }
8204
8205 public void requestPss(Runnable completeCallback) {
8206 ArrayList<ProcessRecord> procs;
8207 synchronized (this) {
8208 mRequestPssCallback = completeCallback;
8209 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008210 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8211 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008212 if (!proc.persistent) {
8213 mRequestPssList.add(proc);
8214 }
8215 }
8216 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8217 }
8218
8219 int oldPri = Process.getThreadPriority(Process.myTid());
8220 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8221 for (int i=procs.size()-1; i>=0; i--) {
8222 ProcessRecord proc = procs.get(i);
8223 proc.lastPss = 0;
8224 proc.requestPss();
8225 }
8226 Process.setThreadPriority(oldPri);
8227 }
8228
8229 void removeRequestedPss(ProcessRecord proc) {
8230 Runnable callback = null;
8231 synchronized (this) {
8232 if (mRequestPssList.remove(proc)) {
8233 if (mRequestPssList.size() == 0) {
8234 callback = mRequestPssCallback;
8235 mRequestPssCallback = null;
8236 }
8237 }
8238 }
8239
8240 if (callback != null) {
8241 callback.run();
8242 }
8243 }
8244
8245 public void collectPss(Watchdog.PssStats stats) {
8246 stats.mEmptyPss = 0;
8247 stats.mEmptyCount = 0;
8248 stats.mBackgroundPss = 0;
8249 stats.mBackgroundCount = 0;
8250 stats.mServicePss = 0;
8251 stats.mServiceCount = 0;
8252 stats.mVisiblePss = 0;
8253 stats.mVisibleCount = 0;
8254 stats.mForegroundPss = 0;
8255 stats.mForegroundCount = 0;
8256 stats.mNoPssCount = 0;
8257 synchronized (this) {
8258 int i;
8259 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8260 ? mProcDeaths.length : stats.mProcDeaths.length;
8261 int aggr = 0;
8262 for (i=0; i<NPD; i++) {
8263 aggr += mProcDeaths[i];
8264 stats.mProcDeaths[i] = aggr;
8265 }
8266 while (i<stats.mProcDeaths.length) {
8267 stats.mProcDeaths[i] = 0;
8268 i++;
8269 }
8270
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008271 for (i=mLruProcesses.size()-1; i>=0; i--) {
8272 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008273 if (proc.persistent) {
8274 continue;
8275 }
8276 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8277 if (proc.lastPss == 0) {
8278 stats.mNoPssCount++;
8279 continue;
8280 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008281 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8282 if (proc.empty) {
8283 stats.mEmptyPss += proc.lastPss;
8284 stats.mEmptyCount++;
8285 } else {
8286 stats.mBackgroundPss += proc.lastPss;
8287 stats.mBackgroundCount++;
8288 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008289 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8290 stats.mVisiblePss += proc.lastPss;
8291 stats.mVisibleCount++;
8292 } else {
8293 stats.mForegroundPss += proc.lastPss;
8294 stats.mForegroundCount++;
8295 }
8296 }
8297 }
8298 }
8299
8300 public final void startRunning(String pkg, String cls, String action,
8301 String data) {
8302 synchronized(this) {
8303 if (mStartRunning) {
8304 return;
8305 }
8306 mStartRunning = true;
8307 mTopComponent = pkg != null && cls != null
8308 ? new ComponentName(pkg, cls) : null;
8309 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8310 mTopData = data;
8311 if (!mSystemReady) {
8312 return;
8313 }
8314 }
8315
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008316 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008317 }
8318
8319 private void retrieveSettings() {
8320 final ContentResolver resolver = mContext.getContentResolver();
8321 String debugApp = Settings.System.getString(
8322 resolver, Settings.System.DEBUG_APP);
8323 boolean waitForDebugger = Settings.System.getInt(
8324 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8325 boolean alwaysFinishActivities = Settings.System.getInt(
8326 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8327
8328 Configuration configuration = new Configuration();
8329 Settings.System.getConfiguration(resolver, configuration);
8330
8331 synchronized (this) {
8332 mDebugApp = mOrigDebugApp = debugApp;
8333 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8334 mAlwaysFinishActivities = alwaysFinishActivities;
8335 // This happens before any activities are started, so we can
8336 // change mConfiguration in-place.
8337 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008338 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008339 }
8340 }
8341
8342 public boolean testIsSystemReady() {
8343 // no need to synchronize(this) just to read & return the value
8344 return mSystemReady;
8345 }
8346
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008347 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008348 // In the simulator, startRunning will never have been called, which
8349 // normally sets a few crucial variables. Do it here instead.
8350 if (!Process.supportsProcesses()) {
8351 mStartRunning = true;
8352 mTopAction = Intent.ACTION_MAIN;
8353 }
8354
8355 synchronized(this) {
8356 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008357 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008358 return;
8359 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008360
8361 // Check to see if there are any update receivers to run.
8362 if (!mDidUpdate) {
8363 if (mWaitingUpdate) {
8364 return;
8365 }
8366 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8367 List<ResolveInfo> ris = null;
8368 try {
8369 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8370 intent, null, 0);
8371 } catch (RemoteException e) {
8372 }
8373 if (ris != null) {
8374 for (int i=ris.size()-1; i>=0; i--) {
8375 if ((ris.get(i).activityInfo.applicationInfo.flags
8376 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8377 ris.remove(i);
8378 }
8379 }
8380 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8381 for (int i=0; i<ris.size(); i++) {
8382 ActivityInfo ai = ris.get(i).activityInfo;
8383 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8384 IIntentReceiver finisher = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -08008385 if (i == ris.size()-1) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008386 finisher = new IIntentReceiver.Stub() {
8387 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008388 String data, Bundle extras, boolean ordered,
8389 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008390 throws RemoteException {
8391 synchronized (ActivityManagerService.this) {
8392 mDidUpdate = true;
8393 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008394 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008395 }
8396 };
8397 }
8398 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8399 broadcastIntentLocked(null, null, intent, null, finisher,
8400 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornd6847842010-01-12 18:14:19 -08008401 if (finisher != null) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008402 mWaitingUpdate = true;
8403 }
8404 }
8405 }
8406 if (mWaitingUpdate) {
8407 return;
8408 }
8409 mDidUpdate = true;
8410 }
8411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008412 mSystemReady = true;
8413 if (!mStartRunning) {
8414 return;
8415 }
8416 }
8417
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008418 ArrayList<ProcessRecord> procsToKill = null;
8419 synchronized(mPidsSelfLocked) {
8420 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8421 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8422 if (!isAllowedWhileBooting(proc.info)){
8423 if (procsToKill == null) {
8424 procsToKill = new ArrayList<ProcessRecord>();
8425 }
8426 procsToKill.add(proc);
8427 }
8428 }
8429 }
8430
8431 if (procsToKill != null) {
8432 synchronized(this) {
8433 for (int i=procsToKill.size()-1; i>=0; i--) {
8434 ProcessRecord proc = procsToKill.get(i);
8435 Log.i(TAG, "Removing system update proc: " + proc);
8436 removeProcessLocked(proc, true);
8437 }
8438 }
8439 }
8440
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008441 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008442 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008443 SystemClock.uptimeMillis());
8444
8445 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008446 // Make sure we have no pre-ready processes sitting around.
8447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008448 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8449 ResolveInfo ri = mContext.getPackageManager()
8450 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008451 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008452 CharSequence errorMsg = null;
8453 if (ri != null) {
8454 ActivityInfo ai = ri.activityInfo;
8455 ApplicationInfo app = ai.applicationInfo;
8456 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8457 mTopAction = Intent.ACTION_FACTORY_TEST;
8458 mTopData = null;
8459 mTopComponent = new ComponentName(app.packageName,
8460 ai.name);
8461 } else {
8462 errorMsg = mContext.getResources().getText(
8463 com.android.internal.R.string.factorytest_not_system);
8464 }
8465 } else {
8466 errorMsg = mContext.getResources().getText(
8467 com.android.internal.R.string.factorytest_no_action);
8468 }
8469 if (errorMsg != null) {
8470 mTopAction = null;
8471 mTopData = null;
8472 mTopComponent = null;
8473 Message msg = Message.obtain();
8474 msg.what = SHOW_FACTORY_ERROR_MSG;
8475 msg.getData().putCharSequence("msg", errorMsg);
8476 mHandler.sendMessage(msg);
8477 }
8478 }
8479 }
8480
8481 retrieveSettings();
8482
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008483 if (goingCallback != null) goingCallback.run();
8484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008485 synchronized (this) {
8486 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8487 try {
8488 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008489 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008490 if (apps != null) {
8491 int N = apps.size();
8492 int i;
8493 for (i=0; i<N; i++) {
8494 ApplicationInfo info
8495 = (ApplicationInfo)apps.get(i);
8496 if (info != null &&
8497 !info.packageName.equals("android")) {
8498 addAppLocked(info);
8499 }
8500 }
8501 }
8502 } catch (RemoteException ex) {
8503 // pm is in same process, this will never happen.
8504 }
8505 }
8506
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008507 // Start up initial activity.
8508 mBooting = true;
8509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008510 try {
8511 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8512 Message msg = Message.obtain();
8513 msg.what = SHOW_UID_ERROR_MSG;
8514 mHandler.sendMessage(msg);
8515 }
8516 } catch (RemoteException e) {
8517 }
8518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008519 resumeTopActivityLocked(null);
8520 }
8521 }
8522
Dan Egnorb7f03672009-12-09 16:22:32 -08008523 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008524 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008525 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008526 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008527 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008528 startAppProblemLocked(app);
8529 app.stopFreezingAllLocked();
8530 return handleAppCrashLocked(app);
8531 }
8532
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008533 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Doug Zongker43866e02010-01-07 12:09:54 -08008534 // check if error reporting is enabled in secure settings
8535 int enabled = Settings.Secure.getInt(mContext.getContentResolver(),
8536 Settings.Secure.SEND_ACTION_APP_ERROR, 0);
Jacek Surazskia2339432009-09-18 15:01:26 +02008537 if (enabled == 0) {
8538 return null;
8539 }
8540
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008541 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008542
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008543 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008544 // look for receiver in the installer package
8545 String candidate = pm.getInstallerPackageName(app.info.packageName);
8546 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8547 if (result != null) {
8548 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008549 }
8550
Jacek Surazski82a73df2009-06-17 14:33:18 +02008551 // if the error app is on the system image, look for system apps
8552 // error receiver
8553 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8554 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8555 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8556 if (result != null) {
8557 return result;
8558 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008559 }
8560
Jacek Surazski82a73df2009-06-17 14:33:18 +02008561 // if there is a default receiver, try that
8562 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8563 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008564 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008565 // should not happen
8566 Log.e(TAG, "error talking to PackageManager", e);
8567 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008568 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008569 }
8570
8571 /**
8572 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8573 *
8574 * @param pm PackageManager isntance
8575 * @param errorPackage package which caused the error
8576 * @param receiverPackage candidate package to receive the error
8577 * @return activity component within receiverPackage which handles
8578 * ACTION_APP_ERROR, or null if not found
8579 */
8580 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8581 String receiverPackage) throws RemoteException {
8582 if (receiverPackage == null || receiverPackage.length() == 0) {
8583 return null;
8584 }
8585
8586 // break the loop if it's the error report receiver package that crashed
8587 if (receiverPackage.equals(errorPackage)) {
8588 return null;
8589 }
8590
8591 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8592 intent.setPackage(receiverPackage);
8593 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8594 if (info == null || info.activityInfo == null) {
8595 return null;
8596 }
8597 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008598 }
8599
Dan Egnorb7f03672009-12-09 16:22:32 -08008600 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008601 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008602 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008603 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008604 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8605 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008606 startAppProblemLocked(app);
8607 app.stopFreezingAllLocked();
8608 }
8609
8610 /**
8611 * Generate a process error record, suitable for attachment to a ProcessRecord.
8612 *
8613 * @param app The ProcessRecord in which the error occurred.
8614 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8615 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008616 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008617 * @param shortMsg Short message describing the crash.
8618 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008619 * @param stackTrace Full crash stack trace, may be null.
8620 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008621 * @return Returns a fully-formed AppErrorStateInfo record.
8622 */
8623 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008624 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008625 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008627 report.condition = condition;
8628 report.processName = app.processName;
8629 report.pid = app.pid;
8630 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008631 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008632 report.shortMsg = shortMsg;
8633 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008634 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008635
8636 return report;
8637 }
8638
Dan Egnor42471dd2010-01-07 17:25:22 -08008639 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008640 synchronized (this) {
8641 app.crashing = false;
8642 app.crashingReport = null;
8643 app.notResponding = false;
8644 app.notRespondingReport = null;
8645 if (app.anrDialog == fromDialog) {
8646 app.anrDialog = null;
8647 }
8648 if (app.waitDialog == fromDialog) {
8649 app.waitDialog = null;
8650 }
8651 if (app.pid > 0 && app.pid != MY_PID) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008652 handleAppCrashLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008653 Log.i(ActivityManagerService.TAG, "Killing process "
8654 + app.processName
8655 + " (pid=" + app.pid + ") at user's request");
8656 Process.killProcess(app.pid);
8657 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008658 }
8659 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008660
Dan Egnorb7f03672009-12-09 16:22:32 -08008661 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008662 long now = SystemClock.uptimeMillis();
8663
8664 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8665 app.info.uid);
8666 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8667 // This process loses!
8668 Log.w(TAG, "Process " + app.info.processName
8669 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008670 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008671 app.info.processName, app.info.uid);
8672 killServicesLocked(app, false);
8673 for (int i=mHistory.size()-1; i>=0; i--) {
8674 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8675 if (r.app == app) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08008676 Log.w(TAG, " Force finishing activity "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008677 + r.intent.getComponent().flattenToShortString());
8678 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8679 }
8680 }
8681 if (!app.persistent) {
8682 // We don't want to start this process again until the user
8683 // explicitly does so... but for persistent process, we really
8684 // need to keep it running. If a persistent process is actually
8685 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008686 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008687 app.info.processName);
8688 mBadProcesses.put(app.info.processName, app.info.uid, now);
8689 app.bad = true;
8690 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8691 app.removed = true;
8692 removeProcessLocked(app, false);
8693 return false;
8694 }
8695 }
8696
8697 // Bump up the crash count of any services currently running in the proc.
8698 if (app.services.size() != 0) {
8699 // Any services running in the application need to be placed
8700 // back in the pending list.
8701 Iterator it = app.services.iterator();
8702 while (it.hasNext()) {
8703 ServiceRecord sr = (ServiceRecord)it.next();
8704 sr.crashCount++;
8705 }
8706 }
8707
8708 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8709 return true;
8710 }
8711
8712 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008713 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008714 skipCurrentReceiverLocked(app);
8715 }
8716
8717 void skipCurrentReceiverLocked(ProcessRecord app) {
8718 boolean reschedule = false;
8719 BroadcastRecord r = app.curReceiver;
8720 if (r != null) {
8721 // The current broadcast is waiting for this app's receiver
8722 // to be finished. Looks like that's not going to happen, so
8723 // let the broadcast continue.
8724 logBroadcastReceiverDiscard(r);
8725 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8726 r.resultExtras, r.resultAbort, true);
8727 reschedule = true;
8728 }
8729 r = mPendingBroadcast;
8730 if (r != null && r.curApp == app) {
8731 if (DEBUG_BROADCAST) Log.v(TAG,
8732 "skip & discard pending app " + r);
8733 logBroadcastReceiverDiscard(r);
8734 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8735 r.resultExtras, r.resultAbort, true);
8736 reschedule = true;
8737 }
8738 if (reschedule) {
8739 scheduleBroadcastsLocked();
8740 }
8741 }
8742
Dan Egnor60d87622009-12-16 16:32:58 -08008743 /**
8744 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8745 * The application process will exit immediately after this call returns.
8746 * @param app object of the crashing app, null for the system server
8747 * @param crashInfo describing the exception
8748 */
8749 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8750 ProcessRecord r = findAppProcess(app);
8751
8752 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8753 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008754 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008755 crashInfo.exceptionClassName,
8756 crashInfo.exceptionMessage,
8757 crashInfo.throwFileName,
8758 crashInfo.throwLineNumber);
8759
Dan Egnor42471dd2010-01-07 17:25:22 -08008760 addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008761
8762 crashApplication(r, crashInfo);
8763 }
8764
8765 /**
8766 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8767 * @param app object of the crashing app, null for the system server
8768 * @param tag reported by the caller
8769 * @param crashInfo describing the context of the error
8770 * @return true if the process should exit immediately (WTF is fatal)
8771 */
8772 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008773 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008774 ProcessRecord r = findAppProcess(app);
8775
8776 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8777 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008778 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008779 tag, crashInfo.exceptionMessage);
8780
Dan Egnor42471dd2010-01-07 17:25:22 -08008781 addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008782
Doug Zongker43866e02010-01-07 12:09:54 -08008783 if (Settings.Secure.getInt(mContext.getContentResolver(),
8784 Settings.Secure.WTF_IS_FATAL, 0) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008785 crashApplication(r, crashInfo);
8786 return true;
8787 } else {
8788 return false;
8789 }
8790 }
8791
8792 /**
8793 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8794 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8795 */
8796 private ProcessRecord findAppProcess(IBinder app) {
8797 if (app == null) {
8798 return null;
8799 }
8800
8801 synchronized (this) {
8802 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8803 final int NA = apps.size();
8804 for (int ia=0; ia<NA; ia++) {
8805 ProcessRecord p = apps.valueAt(ia);
8806 if (p.thread != null && p.thread.asBinder() == app) {
8807 return p;
8808 }
8809 }
8810 }
8811
8812 Log.w(TAG, "Can't find mystery application: " + app);
8813 return null;
8814 }
8815 }
8816
8817 /**
Dan Egnor42471dd2010-01-07 17:25:22 -08008818 * Write a description of an error (crash, WTF, ANR) to the drop box.
Dan Egnor60d87622009-12-16 16:32:58 -08008819 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
Dan Egnor42471dd2010-01-07 17:25:22 -08008820 * @param process which caused the error, null means the system server
8821 * @param activity which triggered the error, null if unknown
8822 * @param parent activity related to the error, null if unknown
8823 * @param subject line related to the error, null if absent
8824 * @param report in long form describing the error, null if absent
8825 * @param logFile to include in the report, null if none
8826 * @param crashInfo giving an application stack trace, null if absent
Dan Egnor60d87622009-12-16 16:32:58 -08008827 */
Dan Egnor42471dd2010-01-07 17:25:22 -08008828 private void addErrorToDropBox(String eventType,
8829 ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
8830 String subject, String report, File logFile,
Dan Egnor60d87622009-12-16 16:32:58 -08008831 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008832 String dropboxTag;
8833 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008834 dropboxTag = "system_server_" + eventType;
Dan Egnor42471dd2010-01-07 17:25:22 -08008835 } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008836 dropboxTag = "system_app_" + eventType;
8837 } else {
8838 dropboxTag = "data_app_" + eventType;
8839 }
8840
8841 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8842 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8843 StringBuilder sb = new StringBuilder(1024);
Dan Egnor42471dd2010-01-07 17:25:22 -08008844 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008845 sb.append("Process: system_server\n");
8846 } else {
Dan Egnor42471dd2010-01-07 17:25:22 -08008847 sb.append("Process: ").append(process.processName).append("\n");
Dan Egnor2780e732010-01-22 14:47:35 -08008848 sb.append("Flags: 0x").append(Integer.toString(process.info.flags, 16)).append("\n");
Dan Egnor42471dd2010-01-07 17:25:22 -08008849 }
8850 if (activity != null) {
8851 sb.append("Activity: ").append(activity.shortComponentName).append("\n");
8852 }
8853 if (parent != null && parent.app != null && parent.app.pid != process.pid) {
8854 sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
8855 }
8856 if (parent != null && parent != activity) {
8857 sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
8858 }
8859 if (subject != null) {
8860 sb.append("Subject: ").append(subject).append("\n");
8861 }
8862 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8863 sb.append("\n");
8864 if (report != null) {
8865 sb.append(report);
8866 }
8867 if (logFile != null) {
8868 try {
8869 sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
8870 } catch (IOException e) {
8871 Log.e(TAG, "Error reading " + logFile, e);
Dan Egnor60d87622009-12-16 16:32:58 -08008872 }
8873 }
Dan Egnor60d87622009-12-16 16:32:58 -08008874 if (crashInfo != null && crashInfo.stackTrace != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008875 sb.append(crashInfo.stackTrace);
Dan Egnor60d87622009-12-16 16:32:58 -08008876 }
8877 dbox.addText(dropboxTag, sb.toString());
8878 }
8879 }
8880
8881 /**
8882 * Bring up the "unexpected error" dialog box for a crashing app.
8883 * Deal with edge cases (intercepts from instrumented applications,
8884 * ActivityController, error intent receivers, that sort of thing).
8885 * @param r the application crashing
8886 * @param crashInfo describing the failure
8887 */
8888 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008889 long timeMillis = System.currentTimeMillis();
8890 String shortMsg = crashInfo.exceptionClassName;
8891 String longMsg = crashInfo.exceptionMessage;
8892 String stackTrace = crashInfo.stackTrace;
8893 if (shortMsg != null && longMsg != null) {
8894 longMsg = shortMsg + ": " + longMsg;
8895 } else if (shortMsg != null) {
8896 longMsg = shortMsg;
8897 }
8898
Dan Egnor60d87622009-12-16 16:32:58 -08008899 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008900 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008901 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008902 try {
8903 String name = r != null ? r.processName : null;
8904 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008905 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008906 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008907 Log.w(TAG, "Force-killing crashed app " + name
8908 + " at watcher's request");
8909 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008910 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008911 }
8912 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008913 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008914 }
8915 }
8916
8917 final long origId = Binder.clearCallingIdentity();
8918
8919 // If this process is running instrumentation, finish it.
8920 if (r != null && r.instrumentationClass != null) {
8921 Log.w(TAG, "Error in app " + r.processName
8922 + " running instrumentation " + r.instrumentationClass + ":");
8923 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8924 if (longMsg != null) Log.w(TAG, " " + longMsg);
8925 Bundle info = new Bundle();
8926 info.putString("shortMsg", shortMsg);
8927 info.putString("longMsg", longMsg);
8928 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8929 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008930 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008931 }
8932
Dan Egnor60d87622009-12-16 16:32:58 -08008933 // If we can't identify the process or it's already exceeded its crash quota,
8934 // quit right away without showing a crash dialog.
8935 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008936 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008937 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008938 }
8939
8940 Message msg = Message.obtain();
8941 msg.what = SHOW_ERROR_MSG;
8942 HashMap data = new HashMap();
8943 data.put("result", result);
8944 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008945 msg.obj = data;
8946 mHandler.sendMessage(msg);
8947
8948 Binder.restoreCallingIdentity(origId);
8949 }
8950
8951 int res = result.get();
8952
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008953 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008954 synchronized (this) {
8955 if (r != null) {
8956 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8957 SystemClock.uptimeMillis());
8958 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008959 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008960 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008961 }
8962 }
8963
8964 if (appErrorIntent != null) {
8965 try {
8966 mContext.startActivity(appErrorIntent);
8967 } catch (ActivityNotFoundException e) {
8968 Log.w(TAG, "bug report receiver dissappeared", e);
8969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008971 }
Dan Egnorb7f03672009-12-09 16:22:32 -08008972
8973 Intent createAppErrorIntentLocked(ProcessRecord r,
8974 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
8975 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008976 if (report == null) {
8977 return null;
8978 }
8979 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8980 result.setComponent(r.errorReportReceiver);
8981 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8982 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8983 return result;
8984 }
8985
Dan Egnorb7f03672009-12-09 16:22:32 -08008986 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
8987 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008988 if (r.errorReportReceiver == null) {
8989 return null;
8990 }
8991
8992 if (!r.crashing && !r.notResponding) {
8993 return null;
8994 }
8995
Dan Egnorb7f03672009-12-09 16:22:32 -08008996 ApplicationErrorReport report = new ApplicationErrorReport();
8997 report.packageName = r.info.packageName;
8998 report.installerPackageName = r.errorReportReceiver.getPackageName();
8999 report.processName = r.processName;
9000 report.time = timeMillis;
Jacek Surazskie0ee6ef2010-01-07 16:23:03 +01009001 report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009002
Dan Egnorb7f03672009-12-09 16:22:32 -08009003 if (r.crashing) {
9004 report.type = ApplicationErrorReport.TYPE_CRASH;
9005 report.crashInfo = crashInfo;
9006 } else if (r.notResponding) {
9007 report.type = ApplicationErrorReport.TYPE_ANR;
9008 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009009
Dan Egnorb7f03672009-12-09 16:22:32 -08009010 report.anrInfo.activity = r.notRespondingReport.tag;
9011 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9012 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009013 }
9014
Dan Egnorb7f03672009-12-09 16:22:32 -08009015 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009016 }
9017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009018 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9019 // assume our apps are happy - lazy create the list
9020 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9021
9022 synchronized (this) {
9023
9024 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009025 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9026 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009027 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9028 // This one's in trouble, so we'll generate a report for it
9029 // crashes are higher priority (in case there's a crash *and* an anr)
9030 ActivityManager.ProcessErrorStateInfo report = null;
9031 if (app.crashing) {
9032 report = app.crashingReport;
9033 } else if (app.notResponding) {
9034 report = app.notRespondingReport;
9035 }
9036
9037 if (report != null) {
9038 if (errList == null) {
9039 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9040 }
9041 errList.add(report);
9042 } else {
9043 Log.w(TAG, "Missing app error report, app = " + app.processName +
9044 " crashing = " + app.crashing +
9045 " notResponding = " + app.notResponding);
9046 }
9047 }
9048 }
9049 }
9050
9051 return errList;
9052 }
9053
9054 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9055 // Lazy instantiation of list
9056 List<ActivityManager.RunningAppProcessInfo> runList = null;
9057 synchronized (this) {
9058 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009059 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9060 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009061 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9062 // Generate process state info for running application
9063 ActivityManager.RunningAppProcessInfo currApp =
9064 new ActivityManager.RunningAppProcessInfo(app.processName,
9065 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009066 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009067 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009068 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009069 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9070 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9071 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009072 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9073 } else if (adj >= HOME_APP_ADJ) {
9074 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9075 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009076 } else if (adj >= SECONDARY_SERVER_ADJ) {
9077 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9078 } else if (adj >= VISIBLE_APP_ADJ) {
9079 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9080 } else {
9081 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9082 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009083 currApp.importanceReasonCode = app.adjTypeCode;
9084 if (app.adjSource instanceof ProcessRecord) {
9085 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9086 } else if (app.adjSource instanceof HistoryRecord) {
9087 HistoryRecord r = (HistoryRecord)app.adjSource;
9088 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9089 }
9090 if (app.adjTarget instanceof ComponentName) {
9091 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9092 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009093 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9094 // + " lru=" + currApp.lru);
9095 if (runList == null) {
9096 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9097 }
9098 runList.add(currApp);
9099 }
9100 }
9101 }
9102 return runList;
9103 }
9104
9105 @Override
9106 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009107 if (checkCallingPermission(android.Manifest.permission.DUMP)
9108 != PackageManager.PERMISSION_GRANTED) {
9109 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9110 + Binder.getCallingPid()
9111 + ", uid=" + Binder.getCallingUid()
9112 + " without permission "
9113 + android.Manifest.permission.DUMP);
9114 return;
9115 }
9116
9117 boolean dumpAll = false;
9118
9119 int opti = 0;
9120 while (opti < args.length) {
9121 String opt = args[opti];
9122 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9123 break;
9124 }
9125 opti++;
9126 if ("-a".equals(opt)) {
9127 dumpAll = true;
9128 } else if ("-h".equals(opt)) {
9129 pw.println("Activity manager dump options:");
9130 pw.println(" [-a] [h- [cmd] ...");
9131 pw.println(" cmd may be one of:");
9132 pw.println(" activities: activity stack state");
9133 pw.println(" broadcasts: broadcast state");
9134 pw.println(" intents: pending intent state");
9135 pw.println(" processes: process state");
9136 pw.println(" providers: content provider state");
9137 pw.println(" services: service state");
9138 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009139 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009140 } else {
9141 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009142 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009143 }
9144
9145 // Is the caller requesting to dump a particular piece of data?
9146 if (opti < args.length) {
9147 String cmd = args[opti];
9148 opti++;
9149 if ("activities".equals(cmd) || "a".equals(cmd)) {
9150 synchronized (this) {
9151 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009152 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009153 return;
9154 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9155 synchronized (this) {
9156 dumpBroadcastsLocked(fd, pw, args, opti, true);
9157 }
9158 return;
9159 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9160 synchronized (this) {
9161 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9162 }
9163 return;
9164 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9165 synchronized (this) {
9166 dumpProcessesLocked(fd, pw, args, opti, true);
9167 }
9168 return;
9169 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9170 synchronized (this) {
9171 dumpProvidersLocked(fd, pw, args, opti, true);
9172 }
9173 return;
9174 } else if ("service".equals(cmd)) {
9175 dumpService(fd, pw, args, opti, true);
9176 return;
9177 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9178 synchronized (this) {
9179 dumpServicesLocked(fd, pw, args, opti, true);
9180 }
9181 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009182 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009183 }
9184
9185 // No piece of data specified, dump everything.
9186 synchronized (this) {
9187 boolean needSep;
9188 if (dumpAll) {
9189 pw.println("Providers in Current Activity Manager State:");
9190 }
9191 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9192 if (needSep) {
9193 pw.println(" ");
9194 }
9195 if (dumpAll) {
9196 pw.println("-------------------------------------------------------------------------------");
9197 pw.println("Broadcasts in Current Activity Manager State:");
9198 }
9199 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9200 if (needSep) {
9201 pw.println(" ");
9202 }
9203 if (dumpAll) {
9204 pw.println("-------------------------------------------------------------------------------");
9205 pw.println("Services in Current Activity Manager State:");
9206 }
9207 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9208 if (needSep) {
9209 pw.println(" ");
9210 }
9211 if (dumpAll) {
9212 pw.println("-------------------------------------------------------------------------------");
9213 pw.println("PendingIntents in Current Activity Manager State:");
9214 }
9215 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9216 if (needSep) {
9217 pw.println(" ");
9218 }
9219 if (dumpAll) {
9220 pw.println("-------------------------------------------------------------------------------");
9221 pw.println("Activities in Current Activity Manager State:");
9222 }
9223 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9224 if (needSep) {
9225 pw.println(" ");
9226 }
9227 if (dumpAll) {
9228 pw.println("-------------------------------------------------------------------------------");
9229 pw.println("Processes in Current Activity Manager State:");
9230 }
9231 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9232 }
9233 }
9234
9235 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9236 int opti, boolean dumpAll, boolean needHeader) {
9237 if (needHeader) {
9238 pw.println(" Activity stack:");
9239 }
9240 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9241 pw.println(" ");
9242 pw.println(" Running activities (most recent first):");
9243 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9244 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009245 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009246 pw.println(" Activities waiting for another to become visible:");
9247 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9248 }
9249 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009250 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009251 pw.println(" Activities waiting to stop:");
9252 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9253 }
9254 if (mFinishingActivities.size() > 0) {
9255 pw.println(" ");
9256 pw.println(" Activities waiting to finish:");
9257 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009259
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009260 pw.println(" ");
9261 pw.println(" mPausingActivity: " + mPausingActivity);
9262 pw.println(" mResumedActivity: " + mResumedActivity);
9263 pw.println(" mFocusedActivity: " + mFocusedActivity);
9264 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009265
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009266 if (dumpAll && mRecentTasks.size() > 0) {
9267 pw.println(" ");
9268 pw.println("Recent tasks in Current Activity Manager State:");
9269
9270 final int N = mRecentTasks.size();
9271 for (int i=0; i<N; i++) {
9272 TaskRecord tr = mRecentTasks.get(i);
9273 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9274 pw.println(tr);
9275 mRecentTasks.get(i).dump(pw, " ");
9276 }
9277 }
9278
9279 pw.println(" ");
9280 pw.println(" mCurTask: " + mCurTask);
9281
9282 return true;
9283 }
9284
9285 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9286 int opti, boolean dumpAll) {
9287 boolean needSep = false;
9288 int numPers = 0;
9289
9290 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009291 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9292 final int NA = procs.size();
9293 for (int ia=0; ia<NA; ia++) {
9294 if (!needSep) {
9295 pw.println(" All known processes:");
9296 needSep = true;
9297 }
9298 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009299 pw.print(r.persistent ? " *PERS*" : " *APP*");
9300 pw.print(" UID "); pw.print(procs.keyAt(ia));
9301 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009302 r.dump(pw, " ");
9303 if (r.persistent) {
9304 numPers++;
9305 }
9306 }
9307 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009308 }
9309
9310 if (mLruProcesses.size() > 0) {
9311 if (needSep) pw.println(" ");
9312 needSep = true;
9313 pw.println(" Running processes (most recent first):");
9314 dumpProcessList(pw, this, mLruProcesses, " ",
9315 "App ", "PERS", true);
9316 needSep = true;
9317 }
9318
9319 synchronized (mPidsSelfLocked) {
9320 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009321 if (needSep) pw.println(" ");
9322 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009323 pw.println(" PID mappings:");
9324 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9325 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9326 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009327 }
9328 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009329 }
9330
9331 if (mForegroundProcesses.size() > 0) {
9332 if (needSep) pw.println(" ");
9333 needSep = true;
9334 pw.println(" Foreground Processes:");
9335 for (int i=0; i<mForegroundProcesses.size(); i++) {
9336 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9337 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009338 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009339 }
9340
9341 if (mPersistentStartingProcesses.size() > 0) {
9342 if (needSep) pw.println(" ");
9343 needSep = true;
9344 pw.println(" Persisent processes that are starting:");
9345 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9346 "Starting Norm", "Restarting PERS", false);
9347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009348
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009349 if (mStartingProcesses.size() > 0) {
9350 if (needSep) pw.println(" ");
9351 needSep = true;
9352 pw.println(" Processes that are starting:");
9353 dumpProcessList(pw, this, mStartingProcesses, " ",
9354 "Starting Norm", "Starting PERS", false);
9355 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009356
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009357 if (mRemovedProcesses.size() > 0) {
9358 if (needSep) pw.println(" ");
9359 needSep = true;
9360 pw.println(" Processes that are being removed:");
9361 dumpProcessList(pw, this, mRemovedProcesses, " ",
9362 "Removed Norm", "Removed PERS", false);
9363 }
9364
9365 if (mProcessesOnHold.size() > 0) {
9366 if (needSep) pw.println(" ");
9367 needSep = true;
9368 pw.println(" Processes that are on old until the system is ready:");
9369 dumpProcessList(pw, this, mProcessesOnHold, " ",
9370 "OnHold Norm", "OnHold PERS", false);
9371 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009372
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009373 if (mProcessesToGc.size() > 0) {
9374 if (needSep) pw.println(" ");
9375 needSep = true;
9376 pw.println(" Processes that are waiting to GC:");
9377 long now = SystemClock.uptimeMillis();
9378 for (int i=0; i<mProcessesToGc.size(); i++) {
9379 ProcessRecord proc = mProcessesToGc.get(i);
9380 pw.print(" Process "); pw.println(proc);
9381 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9382 pw.print(", last gced=");
9383 pw.print(now-proc.lastRequestedGc);
9384 pw.print(" ms ago, last lowMem=");
9385 pw.print(now-proc.lastLowMemory);
9386 pw.println(" ms ago");
9387
9388 }
9389 }
9390
9391 if (mProcessCrashTimes.getMap().size() > 0) {
9392 if (needSep) pw.println(" ");
9393 needSep = true;
9394 pw.println(" Time since processes crashed:");
9395 long now = SystemClock.uptimeMillis();
9396 for (Map.Entry<String, SparseArray<Long>> procs
9397 : mProcessCrashTimes.getMap().entrySet()) {
9398 SparseArray<Long> uids = procs.getValue();
9399 final int N = uids.size();
9400 for (int i=0; i<N; i++) {
9401 pw.print(" Process "); pw.print(procs.getKey());
9402 pw.print(" uid "); pw.print(uids.keyAt(i));
9403 pw.print(": last crashed ");
9404 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009405 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009406 }
9407 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009409
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009410 if (mBadProcesses.getMap().size() > 0) {
9411 if (needSep) pw.println(" ");
9412 needSep = true;
9413 pw.println(" Bad processes:");
9414 for (Map.Entry<String, SparseArray<Long>> procs
9415 : mBadProcesses.getMap().entrySet()) {
9416 SparseArray<Long> uids = procs.getValue();
9417 final int N = uids.size();
9418 for (int i=0; i<N; i++) {
9419 pw.print(" Bad process "); pw.print(procs.getKey());
9420 pw.print(" uid "); pw.print(uids.keyAt(i));
9421 pw.print(": crashed at time ");
9422 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009423 }
9424 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009425 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009426
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009427 pw.println(" ");
9428 pw.println(" mHomeProcess: " + mHomeProcess);
9429 pw.println(" mConfiguration: " + mConfiguration);
9430 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9431 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9432 || mOrigWaitForDebugger) {
9433 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9434 + " mDebugTransient=" + mDebugTransient
9435 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9436 }
9437 if (mAlwaysFinishActivities || mController != null) {
9438 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9439 + " mController=" + mController);
9440 }
9441 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009442 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009443 pw.println(" mStartRunning=" + mStartRunning
9444 + " mSystemReady=" + mSystemReady
9445 + " mBooting=" + mBooting
9446 + " mBooted=" + mBooted
9447 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009448 pw.println(" mGoingToSleep=" + mGoingToSleep);
9449 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009450 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009451
9452 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009453 }
9454
9455 /**
9456 * There are three ways to call this:
9457 * - no service specified: dump all the services
9458 * - a flattened component name that matched an existing service was specified as the
9459 * first arg: dump that one service
9460 * - the first arg isn't the flattened component name of an existing service:
9461 * dump all services whose component contains the first arg as a substring
9462 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009463 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9464 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009465 String[] newArgs;
9466 String componentNameString;
9467 ServiceRecord r;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009468 if (opti <= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009469 componentNameString = null;
9470 newArgs = EMPTY_STRING_ARRAY;
9471 r = null;
9472 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009473 componentNameString = args[opti];
9474 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009475 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9476 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009477 newArgs = new String[args.length - opti];
9478 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009479 }
9480
9481 if (r != null) {
9482 dumpService(fd, pw, r, newArgs);
9483 } else {
9484 for (ServiceRecord r1 : mServices.values()) {
9485 if (componentNameString == null
9486 || r1.name.flattenToString().contains(componentNameString)) {
9487 dumpService(fd, pw, r1, newArgs);
9488 }
9489 }
9490 }
9491 }
9492
9493 /**
9494 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9495 * there is a thread associated with the service.
9496 */
9497 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9498 pw.println(" Service " + r.name.flattenToString());
9499 if (r.app != null && r.app.thread != null) {
9500 try {
9501 // flush anything that is already in the PrintWriter since the thread is going
9502 // to write to the file descriptor directly
9503 pw.flush();
9504 r.app.thread.dumpService(fd, r, args);
9505 pw.print("\n");
9506 } catch (RemoteException e) {
9507 pw.println("got a RemoteException while dumping the service");
9508 }
9509 }
9510 }
9511
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009512 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9513 int opti, boolean dumpAll) {
9514 boolean needSep = false;
9515
9516 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009517 if (mRegisteredReceivers.size() > 0) {
9518 pw.println(" ");
9519 pw.println(" Registered Receivers:");
9520 Iterator it = mRegisteredReceivers.values().iterator();
9521 while (it.hasNext()) {
9522 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009523 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009524 r.dump(pw, " ");
9525 }
9526 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009528 pw.println(" ");
9529 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009530 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009531 needSep = true;
9532 }
9533
9534 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9535 || mPendingBroadcast != null) {
9536 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009537 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009538 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009539 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009540 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9541 pw.println(" Broadcast #" + i + ":");
9542 mParallelBroadcasts.get(i).dump(pw, " ");
9543 }
9544 if (mOrderedBroadcasts.size() > 0) {
9545 pw.println(" ");
9546 pw.println(" Active serialized broadcasts:");
9547 }
9548 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9549 pw.println(" Serialized Broadcast #" + i + ":");
9550 mOrderedBroadcasts.get(i).dump(pw, " ");
9551 }
9552 pw.println(" ");
9553 pw.println(" Pending broadcast:");
9554 if (mPendingBroadcast != null) {
9555 mPendingBroadcast.dump(pw, " ");
9556 } else {
9557 pw.println(" (null)");
9558 }
9559 needSep = true;
9560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009561
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009562 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009563 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009564 pw.println(" Historical broadcasts:");
9565 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9566 BroadcastRecord r = mBroadcastHistory[i];
9567 if (r == null) {
9568 break;
9569 }
9570 pw.println(" Historical Broadcast #" + i + ":");
9571 r.dump(pw, " ");
9572 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009573 needSep = true;
9574 }
9575
9576 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009577 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009578 pw.println(" Sticky broadcasts:");
9579 StringBuilder sb = new StringBuilder(128);
9580 for (Map.Entry<String, ArrayList<Intent>> ent
9581 : mStickyBroadcasts.entrySet()) {
9582 pw.print(" * Sticky action "); pw.print(ent.getKey());
9583 pw.println(":");
9584 ArrayList<Intent> intents = ent.getValue();
9585 final int N = intents.size();
9586 for (int i=0; i<N; i++) {
9587 sb.setLength(0);
9588 sb.append(" Intent: ");
9589 intents.get(i).toShortString(sb, true, false);
9590 pw.println(sb.toString());
9591 Bundle bundle = intents.get(i).getExtras();
9592 if (bundle != null) {
9593 pw.print(" ");
9594 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009595 }
9596 }
9597 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009598 needSep = true;
9599 }
9600
9601 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009602 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009603 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009604 pw.println(" mHandler:");
9605 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009606 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009607 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009608
9609 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009610 }
9611
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009612 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9613 int opti, boolean dumpAll) {
9614 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009615
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009616 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009617 if (mServices.size() > 0) {
9618 pw.println(" Active services:");
9619 Iterator<ServiceRecord> it = mServices.values().iterator();
9620 while (it.hasNext()) {
9621 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009622 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009623 r.dump(pw, " ");
9624 }
9625 needSep = true;
9626 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009628
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009629 if (mPendingServices.size() > 0) {
9630 if (needSep) pw.println(" ");
9631 pw.println(" Pending services:");
9632 for (int i=0; i<mPendingServices.size(); i++) {
9633 ServiceRecord r = mPendingServices.get(i);
9634 pw.print(" * Pending "); pw.println(r);
9635 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009636 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009637 needSep = true;
9638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009639
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009640 if (mRestartingServices.size() > 0) {
9641 if (needSep) pw.println(" ");
9642 pw.println(" Restarting services:");
9643 for (int i=0; i<mRestartingServices.size(); i++) {
9644 ServiceRecord r = mRestartingServices.get(i);
9645 pw.print(" * Restarting "); pw.println(r);
9646 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009647 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009648 needSep = true;
9649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009650
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009651 if (mStoppingServices.size() > 0) {
9652 if (needSep) pw.println(" ");
9653 pw.println(" Stopping services:");
9654 for (int i=0; i<mStoppingServices.size(); i++) {
9655 ServiceRecord r = mStoppingServices.get(i);
9656 pw.print(" * Stopping "); pw.println(r);
9657 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009658 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009659 needSep = true;
9660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009661
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009662 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009663 if (mServiceConnections.size() > 0) {
9664 if (needSep) pw.println(" ");
9665 pw.println(" Connection bindings to services:");
9666 Iterator<ConnectionRecord> it
9667 = mServiceConnections.values().iterator();
9668 while (it.hasNext()) {
9669 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009670 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009671 r.dump(pw, " ");
9672 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009673 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009674 }
9675 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009676
9677 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009678 }
9679
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009680 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9681 int opti, boolean dumpAll) {
9682 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009683
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009684 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009685 if (mProvidersByClass.size() > 0) {
9686 if (needSep) pw.println(" ");
9687 pw.println(" Published content providers (by class):");
9688 Iterator it = mProvidersByClass.entrySet().iterator();
9689 while (it.hasNext()) {
9690 Map.Entry e = (Map.Entry)it.next();
9691 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009692 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009693 r.dump(pw, " ");
9694 }
9695 needSep = true;
9696 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009697
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009698 if (mProvidersByName.size() > 0) {
9699 pw.println(" ");
9700 pw.println(" Authority to provider mappings:");
9701 Iterator it = mProvidersByName.entrySet().iterator();
9702 while (it.hasNext()) {
9703 Map.Entry e = (Map.Entry)it.next();
9704 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9705 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9706 pw.println(r);
9707 }
9708 needSep = true;
9709 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009710 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009711
9712 if (mLaunchingProviders.size() > 0) {
9713 if (needSep) pw.println(" ");
9714 pw.println(" Launching content providers:");
9715 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9716 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9717 pw.println(mLaunchingProviders.get(i));
9718 }
9719 needSep = true;
9720 }
9721
9722 if (mGrantedUriPermissions.size() > 0) {
9723 pw.println();
9724 pw.println("Granted Uri Permissions:");
9725 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9726 int uid = mGrantedUriPermissions.keyAt(i);
9727 HashMap<Uri, UriPermission> perms
9728 = mGrantedUriPermissions.valueAt(i);
9729 pw.print(" * UID "); pw.print(uid);
9730 pw.println(" holds:");
9731 for (UriPermission perm : perms.values()) {
9732 pw.print(" "); pw.println(perm);
9733 perm.dump(pw, " ");
9734 }
9735 }
9736 needSep = true;
9737 }
9738
9739 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009740 }
9741
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009742 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9743 int opti, boolean dumpAll) {
9744 boolean needSep = false;
9745
9746 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009747 if (this.mIntentSenderRecords.size() > 0) {
9748 Iterator<WeakReference<PendingIntentRecord>> it
9749 = mIntentSenderRecords.values().iterator();
9750 while (it.hasNext()) {
9751 WeakReference<PendingIntentRecord> ref = it.next();
9752 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009753 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009754 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009755 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009756 rec.dump(pw, " ");
9757 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009758 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009759 }
9760 }
9761 }
9762 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009763
9764 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009765 }
9766
9767 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009768 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009769 TaskRecord lastTask = null;
9770 for (int i=list.size()-1; i>=0; i--) {
9771 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009772 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009773 if (lastTask != r.task) {
9774 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009775 pw.print(prefix);
9776 pw.print(full ? "* " : " ");
9777 pw.println(lastTask);
9778 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009779 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009780 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009781 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009782 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9783 pw.print(" #"); pw.print(i); pw.print(": ");
9784 pw.println(r);
9785 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009786 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009787 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009788 }
9789 }
9790
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009791 private static String buildOomTag(String prefix, String space, int val, int base) {
9792 if (val == base) {
9793 if (space == null) return prefix;
9794 return prefix + " ";
9795 }
9796 return prefix + "+" + Integer.toString(val-base);
9797 }
9798
9799 private static final int dumpProcessList(PrintWriter pw,
9800 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009801 String prefix, String normalLabel, String persistentLabel,
9802 boolean inclOomAdj) {
9803 int numPers = 0;
9804 for (int i=list.size()-1; i>=0; i--) {
9805 ProcessRecord r = (ProcessRecord)list.get(i);
9806 if (false) {
9807 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9808 + " #" + i + ":");
9809 r.dump(pw, prefix + " ");
9810 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009811 String oomAdj;
9812 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009813 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009814 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009815 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9816 } else if (r.setAdj >= HOME_APP_ADJ) {
9817 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9818 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9819 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9820 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9821 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9822 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9823 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9824 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9825 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009826 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009827 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009828 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009829 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009830 } else {
9831 oomAdj = Integer.toString(r.setAdj);
9832 }
9833 String schedGroup;
9834 switch (r.setSchedGroup) {
9835 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9836 schedGroup = "B";
9837 break;
9838 case Process.THREAD_GROUP_DEFAULT:
9839 schedGroup = "F";
9840 break;
9841 default:
9842 schedGroup = Integer.toString(r.setSchedGroup);
9843 break;
9844 }
9845 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009846 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009847 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009848 if (r.adjSource != null || r.adjTarget != null) {
9849 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009850 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009851 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009852 } else {
9853 pw.println(String.format("%s%s #%2d: %s",
9854 prefix, (r.persistent ? persistentLabel : normalLabel),
9855 i, r.toString()));
9856 }
9857 if (r.persistent) {
9858 numPers++;
9859 }
9860 }
9861 return numPers;
9862 }
9863
9864 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9865 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009866 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009867 long uptime = SystemClock.uptimeMillis();
9868 long realtime = SystemClock.elapsedRealtime();
9869
9870 if (isCheckinRequest) {
9871 // short checkin version
9872 pw.println(uptime + "," + realtime);
9873 pw.flush();
9874 } else {
9875 pw.println("Applications Memory Usage (kB):");
9876 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9877 }
9878 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9879 ProcessRecord r = (ProcessRecord)list.get(i);
9880 if (r.thread != null) {
9881 if (!isCheckinRequest) {
9882 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9883 pw.flush();
9884 }
9885 try {
9886 r.thread.asBinder().dump(fd, args);
9887 } catch (RemoteException e) {
9888 if (!isCheckinRequest) {
9889 pw.println("Got RemoteException!");
9890 pw.flush();
9891 }
9892 }
9893 }
9894 }
9895 }
9896
9897 /**
9898 * Searches array of arguments for the specified string
9899 * @param args array of argument strings
9900 * @param value value to search for
9901 * @return true if the value is contained in the array
9902 */
9903 private static boolean scanArgs(String[] args, String value) {
9904 if (args != null) {
9905 for (String arg : args) {
9906 if (value.equals(arg)) {
9907 return true;
9908 }
9909 }
9910 }
9911 return false;
9912 }
9913
Dianne Hackborn75b03852009-06-12 15:43:26 -07009914 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009915 int count = mHistory.size();
9916
9917 // convert the token to an entry in the history.
9918 HistoryRecord r = null;
9919 int index = -1;
9920 for (int i=count-1; i>=0; i--) {
9921 Object o = mHistory.get(i);
9922 if (o == token) {
9923 r = (HistoryRecord)o;
9924 index = i;
9925 break;
9926 }
9927 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009928
9929 return index;
9930 }
9931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009932 private final void killServicesLocked(ProcessRecord app,
9933 boolean allowRestart) {
9934 // Report disconnected services.
9935 if (false) {
9936 // XXX we are letting the client link to the service for
9937 // death notifications.
9938 if (app.services.size() > 0) {
9939 Iterator it = app.services.iterator();
9940 while (it.hasNext()) {
9941 ServiceRecord r = (ServiceRecord)it.next();
9942 if (r.connections.size() > 0) {
9943 Iterator<ConnectionRecord> jt
9944 = r.connections.values().iterator();
9945 while (jt.hasNext()) {
9946 ConnectionRecord c = jt.next();
9947 if (c.binding.client != app) {
9948 try {
9949 //c.conn.connected(r.className, null);
9950 } catch (Exception e) {
9951 // todo: this should be asynchronous!
9952 Log.w(TAG, "Exception thrown disconnected servce "
9953 + r.shortName
9954 + " from app " + app.processName, e);
9955 }
9956 }
9957 }
9958 }
9959 }
9960 }
9961 }
9962
9963 // Clean up any connections this application has to other services.
9964 if (app.connections.size() > 0) {
9965 Iterator<ConnectionRecord> it = app.connections.iterator();
9966 while (it.hasNext()) {
9967 ConnectionRecord r = it.next();
9968 removeConnectionLocked(r, app, null);
9969 }
9970 }
9971 app.connections.clear();
9972
9973 if (app.services.size() != 0) {
9974 // Any services running in the application need to be placed
9975 // back in the pending list.
9976 Iterator it = app.services.iterator();
9977 while (it.hasNext()) {
9978 ServiceRecord sr = (ServiceRecord)it.next();
9979 synchronized (sr.stats.getBatteryStats()) {
9980 sr.stats.stopLaunchedLocked();
9981 }
9982 sr.app = null;
9983 sr.executeNesting = 0;
9984 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009985
9986 boolean hasClients = sr.bindings.size() > 0;
9987 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009988 Iterator<IntentBindRecord> bindings
9989 = sr.bindings.values().iterator();
9990 while (bindings.hasNext()) {
9991 IntentBindRecord b = bindings.next();
9992 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9993 + ": shouldUnbind=" + b.hasBound);
9994 b.binder = null;
9995 b.requested = b.received = b.hasBound = false;
9996 }
9997 }
9998
9999 if (sr.crashCount >= 2) {
10000 Log.w(TAG, "Service crashed " + sr.crashCount
10001 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010002 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010003 sr.crashCount, sr.shortName, app.pid);
10004 bringDownServiceLocked(sr, true);
10005 } else if (!allowRestart) {
10006 bringDownServiceLocked(sr, true);
10007 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010008 boolean canceled = scheduleServiceRestartLocked(sr, true);
10009
10010 // Should the service remain running? Note that in the
10011 // extreme case of so many attempts to deliver a command
10012 // that it failed, that we also will stop it here.
10013 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10014 if (sr.pendingStarts.size() == 0) {
10015 sr.startRequested = false;
10016 if (!hasClients) {
10017 // Whoops, no reason to restart!
10018 bringDownServiceLocked(sr, true);
10019 }
10020 }
10021 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010022 }
10023 }
10024
10025 if (!allowRestart) {
10026 app.services.clear();
10027 }
10028 }
10029
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010030 // Make sure we have no more records on the stopping list.
10031 int i = mStoppingServices.size();
10032 while (i > 0) {
10033 i--;
10034 ServiceRecord sr = mStoppingServices.get(i);
10035 if (sr.app == app) {
10036 mStoppingServices.remove(i);
10037 }
10038 }
10039
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010040 app.executingServices.clear();
10041 }
10042
10043 private final void removeDyingProviderLocked(ProcessRecord proc,
10044 ContentProviderRecord cpr) {
10045 synchronized (cpr) {
10046 cpr.launchingApp = null;
10047 cpr.notifyAll();
10048 }
10049
10050 mProvidersByClass.remove(cpr.info.name);
10051 String names[] = cpr.info.authority.split(";");
10052 for (int j = 0; j < names.length; j++) {
10053 mProvidersByName.remove(names[j]);
10054 }
10055
10056 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10057 while (cit.hasNext()) {
10058 ProcessRecord capp = cit.next();
10059 if (!capp.persistent && capp.thread != null
10060 && capp.pid != 0
10061 && capp.pid != MY_PID) {
10062 Log.i(TAG, "Killing app " + capp.processName
10063 + " (pid " + capp.pid
10064 + ") because provider " + cpr.info.name
10065 + " is in dying process " + proc.processName);
10066 Process.killProcess(capp.pid);
10067 }
10068 }
10069
10070 mLaunchingProviders.remove(cpr);
10071 }
10072
10073 /**
10074 * Main code for cleaning up a process when it has gone away. This is
10075 * called both as a result of the process dying, or directly when stopping
10076 * a process when running in single process mode.
10077 */
10078 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10079 boolean restarting, int index) {
10080 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010081 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010082 }
10083
Dianne Hackborn36124872009-10-08 16:22:03 -070010084 mProcessesToGc.remove(app);
10085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010086 // Dismiss any open dialogs.
10087 if (app.crashDialog != null) {
10088 app.crashDialog.dismiss();
10089 app.crashDialog = null;
10090 }
10091 if (app.anrDialog != null) {
10092 app.anrDialog.dismiss();
10093 app.anrDialog = null;
10094 }
10095 if (app.waitDialog != null) {
10096 app.waitDialog.dismiss();
10097 app.waitDialog = null;
10098 }
10099
10100 app.crashing = false;
10101 app.notResponding = false;
10102
10103 app.resetPackageList();
10104 app.thread = null;
10105 app.forcingToForeground = null;
10106 app.foregroundServices = false;
10107
10108 killServicesLocked(app, true);
10109
10110 boolean restart = false;
10111
10112 int NL = mLaunchingProviders.size();
10113
10114 // Remove published content providers.
10115 if (!app.pubProviders.isEmpty()) {
10116 Iterator it = app.pubProviders.values().iterator();
10117 while (it.hasNext()) {
10118 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10119 cpr.provider = null;
10120 cpr.app = null;
10121
10122 // See if someone is waiting for this provider... in which
10123 // case we don't remove it, but just let it restart.
10124 int i = 0;
10125 if (!app.bad) {
10126 for (; i<NL; i++) {
10127 if (mLaunchingProviders.get(i) == cpr) {
10128 restart = true;
10129 break;
10130 }
10131 }
10132 } else {
10133 i = NL;
10134 }
10135
10136 if (i >= NL) {
10137 removeDyingProviderLocked(app, cpr);
10138 NL = mLaunchingProviders.size();
10139 }
10140 }
10141 app.pubProviders.clear();
10142 }
10143
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010144 // Take care of any launching providers waiting for this process.
10145 if (checkAppInLaunchingProvidersLocked(app, false)) {
10146 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010147 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010149 // Unregister from connected content providers.
10150 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010151 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010152 while (it.hasNext()) {
10153 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10154 cpr.clients.remove(app);
10155 }
10156 app.conProviders.clear();
10157 }
10158
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010159 // At this point there may be remaining entries in mLaunchingProviders
10160 // where we were the only one waiting, so they are no longer of use.
10161 // Look for these and clean up if found.
10162 // XXX Commented out for now. Trying to figure out a way to reproduce
10163 // the actual situation to identify what is actually going on.
10164 if (false) {
10165 for (int i=0; i<NL; i++) {
10166 ContentProviderRecord cpr = (ContentProviderRecord)
10167 mLaunchingProviders.get(i);
10168 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10169 synchronized (cpr) {
10170 cpr.launchingApp = null;
10171 cpr.notifyAll();
10172 }
10173 }
10174 }
10175 }
10176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010177 skipCurrentReceiverLocked(app);
10178
10179 // Unregister any receivers.
10180 if (app.receivers.size() > 0) {
10181 Iterator<ReceiverList> it = app.receivers.iterator();
10182 while (it.hasNext()) {
10183 removeReceiverLocked(it.next());
10184 }
10185 app.receivers.clear();
10186 }
10187
Christopher Tate181fafa2009-05-14 11:12:14 -070010188 // If the app is undergoing backup, tell the backup manager about it
10189 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10190 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10191 try {
10192 IBackupManager bm = IBackupManager.Stub.asInterface(
10193 ServiceManager.getService(Context.BACKUP_SERVICE));
10194 bm.agentDisconnected(app.info.packageName);
10195 } catch (RemoteException e) {
10196 // can't happen; backup manager is local
10197 }
10198 }
10199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010200 // If the caller is restarting this app, then leave it in its
10201 // current lists and let the caller take care of it.
10202 if (restarting) {
10203 return;
10204 }
10205
10206 if (!app.persistent) {
10207 if (DEBUG_PROCESSES) Log.v(TAG,
10208 "Removing non-persistent process during cleanup: " + app);
10209 mProcessNames.remove(app.processName, app.info.uid);
10210 } else if (!app.removed) {
10211 // This app is persistent, so we need to keep its record around.
10212 // If it is not already on the pending app list, add it there
10213 // and start a new process for it.
10214 app.thread = null;
10215 app.forcingToForeground = null;
10216 app.foregroundServices = false;
10217 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10218 mPersistentStartingProcesses.add(app);
10219 restart = true;
10220 }
10221 }
10222 mProcessesOnHold.remove(app);
10223
The Android Open Source Project4df24232009-03-05 14:34:35 -080010224 if (app == mHomeProcess) {
10225 mHomeProcess = null;
10226 }
10227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010228 if (restart) {
10229 // We have components that still need to be running in the
10230 // process, so re-launch it.
10231 mProcessNames.put(app.processName, app.info.uid, app);
10232 startProcessLocked(app, "restart", app.processName);
10233 } else if (app.pid > 0 && app.pid != MY_PID) {
10234 // Goodbye!
10235 synchronized (mPidsSelfLocked) {
10236 mPidsSelfLocked.remove(app.pid);
10237 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10238 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010239 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010240 }
10241 }
10242
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010243 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10244 // Look through the content providers we are waiting to have launched,
10245 // and if any run in this process then either schedule a restart of
10246 // the process or kill the client waiting for it if this process has
10247 // gone bad.
10248 int NL = mLaunchingProviders.size();
10249 boolean restart = false;
10250 for (int i=0; i<NL; i++) {
10251 ContentProviderRecord cpr = (ContentProviderRecord)
10252 mLaunchingProviders.get(i);
10253 if (cpr.launchingApp == app) {
10254 if (!alwaysBad && !app.bad) {
10255 restart = true;
10256 } else {
10257 removeDyingProviderLocked(app, cpr);
10258 NL = mLaunchingProviders.size();
10259 }
10260 }
10261 }
10262 return restart;
10263 }
10264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010265 // =========================================================
10266 // SERVICES
10267 // =========================================================
10268
10269 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10270 ActivityManager.RunningServiceInfo info =
10271 new ActivityManager.RunningServiceInfo();
10272 info.service = r.name;
10273 if (r.app != null) {
10274 info.pid = r.app.pid;
10275 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010276 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010277 info.process = r.processName;
10278 info.foreground = r.isForeground;
10279 info.activeSince = r.createTime;
10280 info.started = r.startRequested;
10281 info.clientCount = r.connections.size();
10282 info.crashCount = r.crashCount;
10283 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010284 if (r.isForeground) {
10285 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10286 }
10287 if (r.startRequested) {
10288 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10289 }
Dan Egnor42471dd2010-01-07 17:25:22 -080010290 if (r.app != null && r.app.pid == MY_PID) {
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010291 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10292 }
10293 if (r.app != null && r.app.persistent) {
10294 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10295 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010296 for (ConnectionRecord conn : r.connections.values()) {
10297 if (conn.clientLabel != 0) {
10298 info.clientPackage = conn.binding.client.info.packageName;
10299 info.clientLabel = conn.clientLabel;
10300 break;
10301 }
10302 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010303 return info;
10304 }
10305
10306 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10307 int flags) {
10308 synchronized (this) {
10309 ArrayList<ActivityManager.RunningServiceInfo> res
10310 = new ArrayList<ActivityManager.RunningServiceInfo>();
10311
10312 if (mServices.size() > 0) {
10313 Iterator<ServiceRecord> it = mServices.values().iterator();
10314 while (it.hasNext() && res.size() < maxNum) {
10315 res.add(makeRunningServiceInfoLocked(it.next()));
10316 }
10317 }
10318
10319 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10320 ServiceRecord r = mRestartingServices.get(i);
10321 ActivityManager.RunningServiceInfo info =
10322 makeRunningServiceInfoLocked(r);
10323 info.restarting = r.nextRestartTime;
10324 res.add(info);
10325 }
10326
10327 return res;
10328 }
10329 }
10330
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010331 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10332 synchronized (this) {
10333 ServiceRecord r = mServices.get(name);
10334 if (r != null) {
10335 for (ConnectionRecord conn : r.connections.values()) {
10336 if (conn.clientIntent != null) {
10337 return conn.clientIntent;
10338 }
10339 }
10340 }
10341 }
10342 return null;
10343 }
10344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010345 private final ServiceRecord findServiceLocked(ComponentName name,
10346 IBinder token) {
10347 ServiceRecord r = mServices.get(name);
10348 return r == token ? r : null;
10349 }
10350
10351 private final class ServiceLookupResult {
10352 final ServiceRecord record;
10353 final String permission;
10354
10355 ServiceLookupResult(ServiceRecord _record, String _permission) {
10356 record = _record;
10357 permission = _permission;
10358 }
10359 };
10360
10361 private ServiceLookupResult findServiceLocked(Intent service,
10362 String resolvedType) {
10363 ServiceRecord r = null;
10364 if (service.getComponent() != null) {
10365 r = mServices.get(service.getComponent());
10366 }
10367 if (r == null) {
10368 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10369 r = mServicesByIntent.get(filter);
10370 }
10371
10372 if (r == null) {
10373 try {
10374 ResolveInfo rInfo =
10375 ActivityThread.getPackageManager().resolveService(
10376 service, resolvedType, 0);
10377 ServiceInfo sInfo =
10378 rInfo != null ? rInfo.serviceInfo : null;
10379 if (sInfo == null) {
10380 return null;
10381 }
10382
10383 ComponentName name = new ComponentName(
10384 sInfo.applicationInfo.packageName, sInfo.name);
10385 r = mServices.get(name);
10386 } catch (RemoteException ex) {
10387 // pm is in same process, this will never happen.
10388 }
10389 }
10390 if (r != null) {
10391 int callingPid = Binder.getCallingPid();
10392 int callingUid = Binder.getCallingUid();
10393 if (checkComponentPermission(r.permission,
10394 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10395 != PackageManager.PERMISSION_GRANTED) {
10396 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10397 + " from pid=" + callingPid
10398 + ", uid=" + callingUid
10399 + " requires " + r.permission);
10400 return new ServiceLookupResult(null, r.permission);
10401 }
10402 return new ServiceLookupResult(r, null);
10403 }
10404 return null;
10405 }
10406
10407 private class ServiceRestarter implements Runnable {
10408 private ServiceRecord mService;
10409
10410 void setService(ServiceRecord service) {
10411 mService = service;
10412 }
10413
10414 public void run() {
10415 synchronized(ActivityManagerService.this) {
10416 performServiceRestartLocked(mService);
10417 }
10418 }
10419 }
10420
10421 private ServiceLookupResult retrieveServiceLocked(Intent service,
10422 String resolvedType, int callingPid, int callingUid) {
10423 ServiceRecord r = null;
10424 if (service.getComponent() != null) {
10425 r = mServices.get(service.getComponent());
10426 }
10427 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10428 r = mServicesByIntent.get(filter);
10429 if (r == null) {
10430 try {
10431 ResolveInfo rInfo =
10432 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010433 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010434 ServiceInfo sInfo =
10435 rInfo != null ? rInfo.serviceInfo : null;
10436 if (sInfo == null) {
10437 Log.w(TAG, "Unable to start service " + service +
10438 ": not found");
10439 return null;
10440 }
10441
10442 ComponentName name = new ComponentName(
10443 sInfo.applicationInfo.packageName, sInfo.name);
10444 r = mServices.get(name);
10445 if (r == null) {
10446 filter = new Intent.FilterComparison(service.cloneFilter());
10447 ServiceRestarter res = new ServiceRestarter();
10448 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10449 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10450 synchronized (stats) {
10451 ss = stats.getServiceStatsLocked(
10452 sInfo.applicationInfo.uid, sInfo.packageName,
10453 sInfo.name);
10454 }
Dianne Hackbornb1c4a2a2010-01-19 15:36:42 -080010455 r = new ServiceRecord(this, ss, name, filter, sInfo, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010456 res.setService(r);
10457 mServices.put(name, r);
10458 mServicesByIntent.put(filter, r);
10459
10460 // Make sure this component isn't in the pending list.
10461 int N = mPendingServices.size();
10462 for (int i=0; i<N; i++) {
10463 ServiceRecord pr = mPendingServices.get(i);
10464 if (pr.name.equals(name)) {
10465 mPendingServices.remove(i);
10466 i--;
10467 N--;
10468 }
10469 }
10470 }
10471 } catch (RemoteException ex) {
10472 // pm is in same process, this will never happen.
10473 }
10474 }
10475 if (r != null) {
10476 if (checkComponentPermission(r.permission,
10477 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10478 != PackageManager.PERMISSION_GRANTED) {
10479 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10480 + " from pid=" + Binder.getCallingPid()
10481 + ", uid=" + Binder.getCallingUid()
10482 + " requires " + r.permission);
10483 return new ServiceLookupResult(null, r.permission);
10484 }
10485 return new ServiceLookupResult(r, null);
10486 }
10487 return null;
10488 }
10489
10490 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10491 long now = SystemClock.uptimeMillis();
10492 if (r.executeNesting == 0 && r.app != null) {
10493 if (r.app.executingServices.size() == 0) {
10494 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10495 msg.obj = r.app;
10496 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10497 }
10498 r.app.executingServices.add(r);
10499 }
10500 r.executeNesting++;
10501 r.executingStart = now;
10502 }
10503
10504 private final void sendServiceArgsLocked(ServiceRecord r,
10505 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010506 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010507 if (N == 0) {
10508 return;
10509 }
10510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010511 int i = 0;
10512 while (i < N) {
10513 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010514 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010515 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010516 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010517 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010518 // If somehow we got a dummy start at the front, then
10519 // just drop it here.
10520 i++;
10521 continue;
10522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010523 bumpServiceExecutingLocked(r);
10524 if (!oomAdjusted) {
10525 oomAdjusted = true;
10526 updateOomAdjLocked(r.app);
10527 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010528 int flags = 0;
10529 if (si.deliveryCount > 0) {
10530 flags |= Service.START_FLAG_RETRY;
10531 }
10532 if (si.doneExecutingCount > 0) {
10533 flags |= Service.START_FLAG_REDELIVERY;
10534 }
10535 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10536 si.deliveredTime = SystemClock.uptimeMillis();
10537 r.deliveredStarts.add(si);
10538 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010539 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010540 } catch (RemoteException e) {
10541 // Remote process gone... we'll let the normal cleanup take
10542 // care of this.
10543 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010544 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010545 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010546 break;
10547 }
10548 }
10549 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010550 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010551 } else {
10552 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010553 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010554 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010555 }
10556 }
10557 }
10558
10559 private final boolean requestServiceBindingLocked(ServiceRecord r,
10560 IntentBindRecord i, boolean rebind) {
10561 if (r.app == null || r.app.thread == null) {
10562 // If service is not currently running, can't yet bind.
10563 return false;
10564 }
10565 if ((!i.requested || rebind) && i.apps.size() > 0) {
10566 try {
10567 bumpServiceExecutingLocked(r);
10568 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10569 + ": shouldUnbind=" + i.hasBound);
10570 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10571 if (!rebind) {
10572 i.requested = true;
10573 }
10574 i.hasBound = true;
10575 i.doRebind = false;
10576 } catch (RemoteException e) {
10577 return false;
10578 }
10579 }
10580 return true;
10581 }
10582
10583 private final void requestServiceBindingsLocked(ServiceRecord r) {
10584 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10585 while (bindings.hasNext()) {
10586 IntentBindRecord i = bindings.next();
10587 if (!requestServiceBindingLocked(r, i, false)) {
10588 break;
10589 }
10590 }
10591 }
10592
10593 private final void realStartServiceLocked(ServiceRecord r,
10594 ProcessRecord app) throws RemoteException {
10595 if (app.thread == null) {
10596 throw new RemoteException();
10597 }
10598
10599 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010600 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010601
10602 app.services.add(r);
10603 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010604 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010605
10606 boolean created = false;
10607 try {
10608 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10609 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010610 mStringBuilder.setLength(0);
10611 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010612 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010613 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010614 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010615 synchronized (r.stats.getBatteryStats()) {
10616 r.stats.startLaunchedLocked();
10617 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010618 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010619 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010620 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010621 created = true;
10622 } finally {
10623 if (!created) {
10624 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010625 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010626 }
10627 }
10628
10629 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010630
10631 // If the service is in the started state, and there are no
10632 // pending arguments, then fake up one so its onStartCommand() will
10633 // be called.
10634 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10635 r.lastStartId++;
10636 if (r.lastStartId < 1) {
10637 r.lastStartId = 1;
10638 }
10639 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10640 }
10641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010642 sendServiceArgsLocked(r, true);
10643 }
10644
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010645 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10646 boolean allowCancel) {
10647 boolean canceled = false;
10648
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010649 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010650 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010651 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010652
10653 // Any delivered but not yet finished starts should be put back
10654 // on the pending list.
10655 final int N = r.deliveredStarts.size();
10656 if (N > 0) {
10657 for (int i=N-1; i>=0; i--) {
10658 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10659 if (si.intent == null) {
10660 // We'll generate this again if needed.
10661 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10662 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10663 r.pendingStarts.add(0, si);
10664 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10665 dur *= 2;
10666 if (minDuration < dur) minDuration = dur;
10667 if (resetTime < dur) resetTime = dur;
10668 } else {
10669 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10670 + r.name);
10671 canceled = true;
10672 }
10673 }
10674 r.deliveredStarts.clear();
10675 }
10676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010677 r.totalRestartCount++;
10678 if (r.restartDelay == 0) {
10679 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010680 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010681 } else {
10682 // If it has been a "reasonably long time" since the service
10683 // was started, then reset our restart duration back to
10684 // the beginning, so we don't infinitely increase the duration
10685 // on a service that just occasionally gets killed (which is
10686 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010687 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010688 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010689 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010690 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010691 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010692 if (r.restartDelay < minDuration) {
10693 r.restartDelay = minDuration;
10694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010695 }
10696 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010697
10698 r.nextRestartTime = now + r.restartDelay;
10699
10700 // Make sure that we don't end up restarting a bunch of services
10701 // all at the same time.
10702 boolean repeat;
10703 do {
10704 repeat = false;
10705 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10706 ServiceRecord r2 = mRestartingServices.get(i);
10707 if (r2 != r && r.nextRestartTime
10708 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10709 && r.nextRestartTime
10710 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10711 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10712 r.restartDelay = r.nextRestartTime - now;
10713 repeat = true;
10714 break;
10715 }
10716 }
10717 } while (repeat);
10718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010719 if (!mRestartingServices.contains(r)) {
10720 mRestartingServices.add(r);
10721 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010722
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010723 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010725 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010726 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010727 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10728 Log.w(TAG, "Scheduling restart of crashed service "
10729 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010730 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010731 r.shortName, r.restartDelay);
10732
10733 Message msg = Message.obtain();
10734 msg.what = SERVICE_ERROR_MSG;
10735 msg.obj = r;
10736 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010737
10738 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010739 }
10740
10741 final void performServiceRestartLocked(ServiceRecord r) {
10742 if (!mRestartingServices.contains(r)) {
10743 return;
10744 }
10745 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10746 }
10747
10748 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10749 if (r.restartDelay == 0) {
10750 return false;
10751 }
10752 r.resetRestartCounter();
10753 mRestartingServices.remove(r);
10754 mHandler.removeCallbacks(r.restarter);
10755 return true;
10756 }
10757
10758 private final boolean bringUpServiceLocked(ServiceRecord r,
10759 int intentFlags, boolean whileRestarting) {
10760 //Log.i(TAG, "Bring up service:");
10761 //r.dump(" ");
10762
Dianne Hackborn36124872009-10-08 16:22:03 -070010763 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010764 sendServiceArgsLocked(r, false);
10765 return true;
10766 }
10767
10768 if (!whileRestarting && r.restartDelay > 0) {
10769 // If waiting for a restart, then do nothing.
10770 return true;
10771 }
10772
10773 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10774 + " " + r.intent);
10775
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010776 // We are now bringing the service up, so no longer in the
10777 // restarting state.
10778 mRestartingServices.remove(r);
10779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010780 final String appName = r.processName;
10781 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10782 if (app != null && app.thread != null) {
10783 try {
10784 realStartServiceLocked(r, app);
10785 return true;
10786 } catch (RemoteException e) {
10787 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10788 }
10789
10790 // If a dead object exception was thrown -- fall through to
10791 // restart the application.
10792 }
10793
Dianne Hackborn36124872009-10-08 16:22:03 -070010794 // Not running -- get it started, and enqueue this service record
10795 // to be executed when the app comes up.
10796 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10797 "service", r.name, false) == null) {
10798 Log.w(TAG, "Unable to launch app "
10799 + r.appInfo.packageName + "/"
10800 + r.appInfo.uid + " for service "
10801 + r.intent.getIntent() + ": process is bad");
10802 bringDownServiceLocked(r, true);
10803 return false;
10804 }
10805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010806 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010807 mPendingServices.add(r);
10808 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010809
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010810 return true;
10811 }
10812
10813 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10814 //Log.i(TAG, "Bring down service:");
10815 //r.dump(" ");
10816
10817 // Does it still need to run?
10818 if (!force && r.startRequested) {
10819 return;
10820 }
10821 if (r.connections.size() > 0) {
10822 if (!force) {
10823 // XXX should probably keep a count of the number of auto-create
10824 // connections directly in the service.
10825 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10826 while (it.hasNext()) {
10827 ConnectionRecord cr = it.next();
10828 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10829 return;
10830 }
10831 }
10832 }
10833
10834 // Report to all of the connections that the service is no longer
10835 // available.
10836 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10837 while (it.hasNext()) {
10838 ConnectionRecord c = it.next();
10839 try {
10840 // todo: shouldn't be a synchronous call!
10841 c.conn.connected(r.name, null);
10842 } catch (Exception e) {
10843 Log.w(TAG, "Failure disconnecting service " + r.name +
10844 " to connection " + c.conn.asBinder() +
10845 " (in " + c.binding.client.processName + ")", e);
10846 }
10847 }
10848 }
10849
10850 // Tell the service that it has been unbound.
10851 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10852 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10853 while (it.hasNext()) {
10854 IntentBindRecord ibr = it.next();
10855 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10856 + ": hasBound=" + ibr.hasBound);
10857 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10858 try {
10859 bumpServiceExecutingLocked(r);
10860 updateOomAdjLocked(r.app);
10861 ibr.hasBound = false;
10862 r.app.thread.scheduleUnbindService(r,
10863 ibr.intent.getIntent());
10864 } catch (Exception e) {
10865 Log.w(TAG, "Exception when unbinding service "
10866 + r.shortName, e);
10867 serviceDoneExecutingLocked(r, true);
10868 }
10869 }
10870 }
10871 }
10872
10873 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10874 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010875 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010876 System.identityHashCode(r), r.shortName,
10877 (r.app != null) ? r.app.pid : -1);
10878
10879 mServices.remove(r.name);
10880 mServicesByIntent.remove(r.intent);
10881 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10882 r.totalRestartCount = 0;
10883 unscheduleServiceRestartLocked(r);
10884
10885 // Also make sure it is not on the pending list.
10886 int N = mPendingServices.size();
10887 for (int i=0; i<N; i++) {
10888 if (mPendingServices.get(i) == r) {
10889 mPendingServices.remove(i);
10890 if (DEBUG_SERVICE) Log.v(
10891 TAG, "Removed pending service: " + r.shortName);
10892 i--;
10893 N--;
10894 }
10895 }
10896
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010897 r.cancelNotification();
10898 r.isForeground = false;
10899 r.foregroundId = 0;
10900 r.foregroundNoti = null;
10901
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010902 // Clear start entries.
10903 r.deliveredStarts.clear();
10904 r.pendingStarts.clear();
10905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010906 if (r.app != null) {
10907 synchronized (r.stats.getBatteryStats()) {
10908 r.stats.stopLaunchedLocked();
10909 }
10910 r.app.services.remove(r);
10911 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010912 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010913 if (DEBUG_SERVICE) Log.v(TAG,
10914 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010915 bumpServiceExecutingLocked(r);
10916 mStoppingServices.add(r);
10917 updateOomAdjLocked(r.app);
10918 r.app.thread.scheduleStopService(r);
10919 } catch (Exception e) {
10920 Log.w(TAG, "Exception when stopping service "
10921 + r.shortName, e);
10922 serviceDoneExecutingLocked(r, true);
10923 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010924 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010925 } else {
10926 if (DEBUG_SERVICE) Log.v(
10927 TAG, "Removed service that has no process: " + r.shortName);
10928 }
10929 } else {
10930 if (DEBUG_SERVICE) Log.v(
10931 TAG, "Removed service that is not running: " + r.shortName);
10932 }
10933 }
10934
10935 ComponentName startServiceLocked(IApplicationThread caller,
10936 Intent service, String resolvedType,
10937 int callingPid, int callingUid) {
10938 synchronized(this) {
10939 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10940 + " type=" + resolvedType + " args=" + service.getExtras());
10941
10942 if (caller != null) {
10943 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10944 if (callerApp == null) {
10945 throw new SecurityException(
10946 "Unable to find app for caller " + caller
10947 + " (pid=" + Binder.getCallingPid()
10948 + ") when starting service " + service);
10949 }
10950 }
10951
10952 ServiceLookupResult res =
10953 retrieveServiceLocked(service, resolvedType,
10954 callingPid, callingUid);
10955 if (res == null) {
10956 return null;
10957 }
10958 if (res.record == null) {
10959 return new ComponentName("!", res.permission != null
10960 ? res.permission : "private to package");
10961 }
10962 ServiceRecord r = res.record;
10963 if (unscheduleServiceRestartLocked(r)) {
10964 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10965 + r.shortName);
10966 }
10967 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010968 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010969 r.lastStartId++;
10970 if (r.lastStartId < 1) {
10971 r.lastStartId = 1;
10972 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010973 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010974 r.lastActivity = SystemClock.uptimeMillis();
10975 synchronized (r.stats.getBatteryStats()) {
10976 r.stats.startRunningLocked();
10977 }
10978 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10979 return new ComponentName("!", "Service process is bad");
10980 }
10981 return r.name;
10982 }
10983 }
10984
10985 public ComponentName startService(IApplicationThread caller, Intent service,
10986 String resolvedType) {
10987 // Refuse possible leaked file descriptors
10988 if (service != null && service.hasFileDescriptors() == true) {
10989 throw new IllegalArgumentException("File descriptors passed in Intent");
10990 }
10991
10992 synchronized(this) {
10993 final int callingPid = Binder.getCallingPid();
10994 final int callingUid = Binder.getCallingUid();
10995 final long origId = Binder.clearCallingIdentity();
10996 ComponentName res = startServiceLocked(caller, service,
10997 resolvedType, callingPid, callingUid);
10998 Binder.restoreCallingIdentity(origId);
10999 return res;
11000 }
11001 }
11002
11003 ComponentName startServiceInPackage(int uid,
11004 Intent service, String resolvedType) {
11005 synchronized(this) {
11006 final long origId = Binder.clearCallingIdentity();
11007 ComponentName res = startServiceLocked(null, service,
11008 resolvedType, -1, uid);
11009 Binder.restoreCallingIdentity(origId);
11010 return res;
11011 }
11012 }
11013
11014 public int stopService(IApplicationThread caller, Intent service,
11015 String resolvedType) {
11016 // Refuse possible leaked file descriptors
11017 if (service != null && service.hasFileDescriptors() == true) {
11018 throw new IllegalArgumentException("File descriptors passed in Intent");
11019 }
11020
11021 synchronized(this) {
11022 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11023 + " type=" + resolvedType);
11024
11025 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11026 if (caller != null && callerApp == null) {
11027 throw new SecurityException(
11028 "Unable to find app for caller " + caller
11029 + " (pid=" + Binder.getCallingPid()
11030 + ") when stopping service " + service);
11031 }
11032
11033 // If this service is active, make sure it is stopped.
11034 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11035 if (r != null) {
11036 if (r.record != null) {
11037 synchronized (r.record.stats.getBatteryStats()) {
11038 r.record.stats.stopRunningLocked();
11039 }
11040 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011041 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011042 final long origId = Binder.clearCallingIdentity();
11043 bringDownServiceLocked(r.record, false);
11044 Binder.restoreCallingIdentity(origId);
11045 return 1;
11046 }
11047 return -1;
11048 }
11049 }
11050
11051 return 0;
11052 }
11053
11054 public IBinder peekService(Intent service, String resolvedType) {
11055 // Refuse possible leaked file descriptors
11056 if (service != null && service.hasFileDescriptors() == true) {
11057 throw new IllegalArgumentException("File descriptors passed in Intent");
11058 }
11059
11060 IBinder ret = null;
11061
11062 synchronized(this) {
11063 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11064
11065 if (r != null) {
11066 // r.record is null if findServiceLocked() failed the caller permission check
11067 if (r.record == null) {
11068 throw new SecurityException(
11069 "Permission Denial: Accessing service " + r.record.name
11070 + " from pid=" + Binder.getCallingPid()
11071 + ", uid=" + Binder.getCallingUid()
11072 + " requires " + r.permission);
11073 }
11074 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11075 if (ib != null) {
11076 ret = ib.binder;
11077 }
11078 }
11079 }
11080
11081 return ret;
11082 }
11083
11084 public boolean stopServiceToken(ComponentName className, IBinder token,
11085 int startId) {
11086 synchronized(this) {
11087 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11088 + " " + token + " startId=" + startId);
11089 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011090 if (r != null) {
11091 if (startId >= 0) {
11092 // Asked to only stop if done with all work. Note that
11093 // to avoid leaks, we will take this as dropping all
11094 // start items up to and including this one.
11095 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11096 if (si != null) {
11097 while (r.deliveredStarts.size() > 0) {
11098 if (r.deliveredStarts.remove(0) == si) {
11099 break;
11100 }
11101 }
11102 }
11103
11104 if (r.lastStartId != startId) {
11105 return false;
11106 }
11107
11108 if (r.deliveredStarts.size() > 0) {
11109 Log.w(TAG, "stopServiceToken startId " + startId
11110 + " is last, but have " + r.deliveredStarts.size()
11111 + " remaining args");
11112 }
11113 }
11114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011115 synchronized (r.stats.getBatteryStats()) {
11116 r.stats.stopRunningLocked();
11117 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011118 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011119 }
11120 final long origId = Binder.clearCallingIdentity();
11121 bringDownServiceLocked(r, false);
11122 Binder.restoreCallingIdentity(origId);
11123 return true;
11124 }
11125 }
11126 return false;
11127 }
11128
11129 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011130 int id, Notification notification, boolean removeNotification) {
11131 final long origId = Binder.clearCallingIdentity();
11132 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011133 synchronized(this) {
11134 ServiceRecord r = findServiceLocked(className, token);
11135 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011136 if (id != 0) {
11137 if (notification == null) {
11138 throw new IllegalArgumentException("null notification");
11139 }
11140 if (r.foregroundId != id) {
11141 r.cancelNotification();
11142 r.foregroundId = id;
11143 }
11144 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11145 r.foregroundNoti = notification;
11146 r.isForeground = true;
11147 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011148 if (r.app != null) {
11149 updateServiceForegroundLocked(r.app, true);
11150 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011151 } else {
11152 if (r.isForeground) {
11153 r.isForeground = false;
11154 if (r.app != null) {
11155 updateServiceForegroundLocked(r.app, true);
11156 }
11157 }
11158 if (removeNotification) {
11159 r.cancelNotification();
11160 r.foregroundId = 0;
11161 r.foregroundNoti = null;
11162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011163 }
11164 }
11165 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011166 } finally {
11167 Binder.restoreCallingIdentity(origId);
11168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011169 }
11170
11171 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11172 boolean anyForeground = false;
11173 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11174 if (sr.isForeground) {
11175 anyForeground = true;
11176 break;
11177 }
11178 }
11179 if (anyForeground != proc.foregroundServices) {
11180 proc.foregroundServices = anyForeground;
11181 if (oomAdj) {
11182 updateOomAdjLocked();
11183 }
11184 }
11185 }
11186
11187 public int bindService(IApplicationThread caller, IBinder token,
11188 Intent service, String resolvedType,
11189 IServiceConnection connection, int flags) {
11190 // Refuse possible leaked file descriptors
11191 if (service != null && service.hasFileDescriptors() == true) {
11192 throw new IllegalArgumentException("File descriptors passed in Intent");
11193 }
11194
11195 synchronized(this) {
11196 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11197 + " type=" + resolvedType + " conn=" + connection.asBinder()
11198 + " flags=0x" + Integer.toHexString(flags));
11199 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11200 if (callerApp == null) {
11201 throw new SecurityException(
11202 "Unable to find app for caller " + caller
11203 + " (pid=" + Binder.getCallingPid()
11204 + ") when binding service " + service);
11205 }
11206
11207 HistoryRecord activity = null;
11208 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011209 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011210 if (aindex < 0) {
11211 Log.w(TAG, "Binding with unknown activity: " + token);
11212 return 0;
11213 }
11214 activity = (HistoryRecord)mHistory.get(aindex);
11215 }
11216
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011217 int clientLabel = 0;
11218 PendingIntent clientIntent = null;
11219
11220 if (callerApp.info.uid == Process.SYSTEM_UID) {
11221 // Hacky kind of thing -- allow system stuff to tell us
11222 // what they are, so we can report this elsewhere for
11223 // others to know why certain services are running.
11224 try {
11225 clientIntent = (PendingIntent)service.getParcelableExtra(
11226 Intent.EXTRA_CLIENT_INTENT);
11227 } catch (RuntimeException e) {
11228 }
11229 if (clientIntent != null) {
11230 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11231 if (clientLabel != 0) {
11232 // There are no useful extras in the intent, trash them.
11233 // System code calling with this stuff just needs to know
11234 // this will happen.
11235 service = service.cloneFilter();
11236 }
11237 }
11238 }
11239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011240 ServiceLookupResult res =
11241 retrieveServiceLocked(service, resolvedType,
11242 Binder.getCallingPid(), Binder.getCallingUid());
11243 if (res == null) {
11244 return 0;
11245 }
11246 if (res.record == null) {
11247 return -1;
11248 }
11249 ServiceRecord s = res.record;
11250
11251 final long origId = Binder.clearCallingIdentity();
11252
11253 if (unscheduleServiceRestartLocked(s)) {
11254 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11255 + s.shortName);
11256 }
11257
11258 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11259 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011260 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011261
11262 IBinder binder = connection.asBinder();
11263 s.connections.put(binder, c);
11264 b.connections.add(c);
11265 if (activity != null) {
11266 if (activity.connections == null) {
11267 activity.connections = new HashSet<ConnectionRecord>();
11268 }
11269 activity.connections.add(c);
11270 }
11271 b.client.connections.add(c);
11272 mServiceConnections.put(binder, c);
11273
11274 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11275 s.lastActivity = SystemClock.uptimeMillis();
11276 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11277 return 0;
11278 }
11279 }
11280
11281 if (s.app != null) {
11282 // This could have made the service more important.
11283 updateOomAdjLocked(s.app);
11284 }
11285
11286 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11287 + ": received=" + b.intent.received
11288 + " apps=" + b.intent.apps.size()
11289 + " doRebind=" + b.intent.doRebind);
11290
11291 if (s.app != null && b.intent.received) {
11292 // Service is already running, so we can immediately
11293 // publish the connection.
11294 try {
11295 c.conn.connected(s.name, b.intent.binder);
11296 } catch (Exception e) {
11297 Log.w(TAG, "Failure sending service " + s.shortName
11298 + " to connection " + c.conn.asBinder()
11299 + " (in " + c.binding.client.processName + ")", e);
11300 }
11301
11302 // If this is the first app connected back to this binding,
11303 // and the service had previously asked to be told when
11304 // rebound, then do so.
11305 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11306 requestServiceBindingLocked(s, b.intent, true);
11307 }
11308 } else if (!b.intent.requested) {
11309 requestServiceBindingLocked(s, b.intent, false);
11310 }
11311
11312 Binder.restoreCallingIdentity(origId);
11313 }
11314
11315 return 1;
11316 }
11317
11318 private void removeConnectionLocked(
11319 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11320 IBinder binder = c.conn.asBinder();
11321 AppBindRecord b = c.binding;
11322 ServiceRecord s = b.service;
11323 s.connections.remove(binder);
11324 b.connections.remove(c);
11325 if (c.activity != null && c.activity != skipAct) {
11326 if (c.activity.connections != null) {
11327 c.activity.connections.remove(c);
11328 }
11329 }
11330 if (b.client != skipApp) {
11331 b.client.connections.remove(c);
11332 }
11333 mServiceConnections.remove(binder);
11334
11335 if (b.connections.size() == 0) {
11336 b.intent.apps.remove(b.client);
11337 }
11338
11339 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11340 + ": shouldUnbind=" + b.intent.hasBound);
11341 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11342 && b.intent.hasBound) {
11343 try {
11344 bumpServiceExecutingLocked(s);
11345 updateOomAdjLocked(s.app);
11346 b.intent.hasBound = false;
11347 // Assume the client doesn't want to know about a rebind;
11348 // we will deal with that later if it asks for one.
11349 b.intent.doRebind = false;
11350 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11351 } catch (Exception e) {
11352 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11353 serviceDoneExecutingLocked(s, true);
11354 }
11355 }
11356
11357 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11358 bringDownServiceLocked(s, false);
11359 }
11360 }
11361
11362 public boolean unbindService(IServiceConnection connection) {
11363 synchronized (this) {
11364 IBinder binder = connection.asBinder();
11365 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11366 ConnectionRecord r = mServiceConnections.get(binder);
11367 if (r == null) {
11368 Log.w(TAG, "Unbind failed: could not find connection for "
11369 + connection.asBinder());
11370 return false;
11371 }
11372
11373 final long origId = Binder.clearCallingIdentity();
11374
11375 removeConnectionLocked(r, null, null);
11376
11377 if (r.binding.service.app != null) {
11378 // This could have made the service less important.
11379 updateOomAdjLocked(r.binding.service.app);
11380 }
11381
11382 Binder.restoreCallingIdentity(origId);
11383 }
11384
11385 return true;
11386 }
11387
11388 public void publishService(IBinder token, Intent intent, IBinder service) {
11389 // Refuse possible leaked file descriptors
11390 if (intent != null && intent.hasFileDescriptors() == true) {
11391 throw new IllegalArgumentException("File descriptors passed in Intent");
11392 }
11393
11394 synchronized(this) {
11395 if (!(token instanceof ServiceRecord)) {
11396 throw new IllegalArgumentException("Invalid service token");
11397 }
11398 ServiceRecord r = (ServiceRecord)token;
11399
11400 final long origId = Binder.clearCallingIdentity();
11401
11402 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11403 + " " + intent + ": " + service);
11404 if (r != null) {
11405 Intent.FilterComparison filter
11406 = new Intent.FilterComparison(intent);
11407 IntentBindRecord b = r.bindings.get(filter);
11408 if (b != null && !b.received) {
11409 b.binder = service;
11410 b.requested = true;
11411 b.received = true;
11412 if (r.connections.size() > 0) {
11413 Iterator<ConnectionRecord> it
11414 = r.connections.values().iterator();
11415 while (it.hasNext()) {
11416 ConnectionRecord c = it.next();
11417 if (!filter.equals(c.binding.intent.intent)) {
11418 if (DEBUG_SERVICE) Log.v(
11419 TAG, "Not publishing to: " + c);
11420 if (DEBUG_SERVICE) Log.v(
11421 TAG, "Bound intent: " + c.binding.intent.intent);
11422 if (DEBUG_SERVICE) Log.v(
11423 TAG, "Published intent: " + intent);
11424 continue;
11425 }
11426 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11427 try {
11428 c.conn.connected(r.name, service);
11429 } catch (Exception e) {
11430 Log.w(TAG, "Failure sending service " + r.name +
11431 " to connection " + c.conn.asBinder() +
11432 " (in " + c.binding.client.processName + ")", e);
11433 }
11434 }
11435 }
11436 }
11437
11438 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11439
11440 Binder.restoreCallingIdentity(origId);
11441 }
11442 }
11443 }
11444
11445 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11446 // Refuse possible leaked file descriptors
11447 if (intent != null && intent.hasFileDescriptors() == true) {
11448 throw new IllegalArgumentException("File descriptors passed in Intent");
11449 }
11450
11451 synchronized(this) {
11452 if (!(token instanceof ServiceRecord)) {
11453 throw new IllegalArgumentException("Invalid service token");
11454 }
11455 ServiceRecord r = (ServiceRecord)token;
11456
11457 final long origId = Binder.clearCallingIdentity();
11458
11459 if (r != null) {
11460 Intent.FilterComparison filter
11461 = new Intent.FilterComparison(intent);
11462 IntentBindRecord b = r.bindings.get(filter);
11463 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11464 + " at " + b + ": apps="
11465 + (b != null ? b.apps.size() : 0));
11466 if (b != null) {
11467 if (b.apps.size() > 0) {
11468 // Applications have already bound since the last
11469 // unbind, so just rebind right here.
11470 requestServiceBindingLocked(r, b, true);
11471 } else {
11472 // Note to tell the service the next time there is
11473 // a new client.
11474 b.doRebind = true;
11475 }
11476 }
11477
11478 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11479
11480 Binder.restoreCallingIdentity(origId);
11481 }
11482 }
11483 }
11484
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011485 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011486 synchronized(this) {
11487 if (!(token instanceof ServiceRecord)) {
11488 throw new IllegalArgumentException("Invalid service token");
11489 }
11490 ServiceRecord r = (ServiceRecord)token;
11491 boolean inStopping = mStoppingServices.contains(token);
11492 if (r != null) {
11493 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11494 + ": nesting=" + r.executeNesting
11495 + ", inStopping=" + inStopping);
11496 if (r != token) {
11497 Log.w(TAG, "Done executing service " + r.name
11498 + " with incorrect token: given " + token
11499 + ", expected " + r);
11500 return;
11501 }
11502
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011503 if (type == 1) {
11504 // This is a call from a service start... take care of
11505 // book-keeping.
11506 r.callStart = true;
11507 switch (res) {
11508 case Service.START_STICKY_COMPATIBILITY:
11509 case Service.START_STICKY: {
11510 // We are done with the associated start arguments.
11511 r.findDeliveredStart(startId, true);
11512 // Don't stop if killed.
11513 r.stopIfKilled = false;
11514 break;
11515 }
11516 case Service.START_NOT_STICKY: {
11517 // We are done with the associated start arguments.
11518 r.findDeliveredStart(startId, true);
11519 if (r.lastStartId == startId) {
11520 // There is no more work, and this service
11521 // doesn't want to hang around if killed.
11522 r.stopIfKilled = true;
11523 }
11524 break;
11525 }
11526 case Service.START_REDELIVER_INTENT: {
11527 // We'll keep this item until they explicitly
11528 // call stop for it, but keep track of the fact
11529 // that it was delivered.
11530 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11531 if (si != null) {
11532 si.deliveryCount = 0;
11533 si.doneExecutingCount++;
11534 // Don't stop if killed.
11535 r.stopIfKilled = true;
11536 }
11537 break;
11538 }
11539 default:
11540 throw new IllegalArgumentException(
11541 "Unknown service start result: " + res);
11542 }
11543 if (res == Service.START_STICKY_COMPATIBILITY) {
11544 r.callStart = false;
11545 }
11546 }
11547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011548 final long origId = Binder.clearCallingIdentity();
11549 serviceDoneExecutingLocked(r, inStopping);
11550 Binder.restoreCallingIdentity(origId);
11551 } else {
11552 Log.w(TAG, "Done executing unknown service " + r.name
11553 + " with token " + token);
11554 }
11555 }
11556 }
11557
11558 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11559 r.executeNesting--;
11560 if (r.executeNesting <= 0 && r.app != null) {
11561 r.app.executingServices.remove(r);
11562 if (r.app.executingServices.size() == 0) {
11563 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11564 }
11565 if (inStopping) {
11566 mStoppingServices.remove(r);
11567 }
11568 updateOomAdjLocked(r.app);
11569 }
11570 }
11571
11572 void serviceTimeout(ProcessRecord proc) {
11573 synchronized(this) {
11574 if (proc.executingServices.size() == 0 || proc.thread == null) {
11575 return;
11576 }
11577 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11578 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11579 ServiceRecord timeout = null;
11580 long nextTime = 0;
11581 while (it.hasNext()) {
11582 ServiceRecord sr = it.next();
11583 if (sr.executingStart < maxTime) {
11584 timeout = sr;
11585 break;
11586 }
11587 if (sr.executingStart > nextTime) {
11588 nextTime = sr.executingStart;
11589 }
11590 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011591 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011592 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnor42471dd2010-01-07 17:25:22 -080011593 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011594 } else {
11595 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11596 msg.obj = proc;
11597 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11598 }
11599 }
11600 }
11601
11602 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011603 // BACKUP AND RESTORE
11604 // =========================================================
11605
11606 // Cause the target app to be launched if necessary and its backup agent
11607 // instantiated. The backup agent will invoke backupAgentCreated() on the
11608 // activity manager to announce its creation.
11609 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11610 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11611 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11612
11613 synchronized(this) {
11614 // !!! TODO: currently no check here that we're already bound
11615 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11616 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11617 synchronized (stats) {
11618 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11619 }
11620
11621 BackupRecord r = new BackupRecord(ss, app, backupMode);
11622 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11623 // startProcessLocked() returns existing proc's record if it's already running
11624 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011625 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011626 if (proc == null) {
11627 Log.e(TAG, "Unable to start backup agent process " + r);
11628 return false;
11629 }
11630
11631 r.app = proc;
11632 mBackupTarget = r;
11633 mBackupAppName = app.packageName;
11634
Christopher Tate6fa95972009-06-05 18:43:55 -070011635 // Try not to kill the process during backup
11636 updateOomAdjLocked(proc);
11637
Christopher Tate181fafa2009-05-14 11:12:14 -070011638 // If the process is already attached, schedule the creation of the backup agent now.
11639 // If it is not yet live, this will be done when it attaches to the framework.
11640 if (proc.thread != null) {
11641 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11642 try {
11643 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11644 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011645 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011646 }
11647 } else {
11648 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11649 }
11650 // Invariants: at this point, the target app process exists and the application
11651 // is either already running or in the process of coming up. mBackupTarget and
11652 // mBackupAppName describe the app, so that when it binds back to the AM we
11653 // know that it's scheduled for a backup-agent operation.
11654 }
11655
11656 return true;
11657 }
11658
11659 // A backup agent has just come up
11660 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11661 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11662 + " = " + agent);
11663
11664 synchronized(this) {
11665 if (!agentPackageName.equals(mBackupAppName)) {
11666 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11667 return;
11668 }
11669
Christopher Tate043dadc2009-06-02 16:11:00 -070011670 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011671 try {
11672 IBackupManager bm = IBackupManager.Stub.asInterface(
11673 ServiceManager.getService(Context.BACKUP_SERVICE));
11674 bm.agentConnected(agentPackageName, agent);
11675 } catch (RemoteException e) {
11676 // can't happen; the backup manager service is local
11677 } catch (Exception e) {
11678 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11679 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011680 } finally {
11681 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011682 }
11683 }
11684 }
11685
11686 // done with this agent
11687 public void unbindBackupAgent(ApplicationInfo appInfo) {
11688 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011689 if (appInfo == null) {
11690 Log.w(TAG, "unbind backup agent for null app");
11691 return;
11692 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011693
11694 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011695 if (mBackupAppName == null) {
11696 Log.w(TAG, "Unbinding backup agent with no active backup");
11697 return;
11698 }
11699
Christopher Tate181fafa2009-05-14 11:12:14 -070011700 if (!mBackupAppName.equals(appInfo.packageName)) {
11701 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11702 return;
11703 }
11704
Christopher Tate6fa95972009-06-05 18:43:55 -070011705 ProcessRecord proc = mBackupTarget.app;
11706 mBackupTarget = null;
11707 mBackupAppName = null;
11708
11709 // Not backing this app up any more; reset its OOM adjustment
11710 updateOomAdjLocked(proc);
11711
Christopher Tatec7b31e32009-06-10 15:49:30 -070011712 // If the app crashed during backup, 'thread' will be null here
11713 if (proc.thread != null) {
11714 try {
11715 proc.thread.scheduleDestroyBackupAgent(appInfo);
11716 } catch (Exception e) {
11717 Log.e(TAG, "Exception when unbinding backup agent:");
11718 e.printStackTrace();
11719 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011720 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011721 }
11722 }
11723 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011724 // BROADCASTS
11725 // =========================================================
11726
11727 private final List getStickies(String action, IntentFilter filter,
11728 List cur) {
11729 final ContentResolver resolver = mContext.getContentResolver();
11730 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11731 if (list == null) {
11732 return cur;
11733 }
11734 int N = list.size();
11735 for (int i=0; i<N; i++) {
11736 Intent intent = list.get(i);
11737 if (filter.match(resolver, intent, true, TAG) >= 0) {
11738 if (cur == null) {
11739 cur = new ArrayList<Intent>();
11740 }
11741 cur.add(intent);
11742 }
11743 }
11744 return cur;
11745 }
11746
11747 private final void scheduleBroadcastsLocked() {
11748 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11749 + mBroadcastsScheduled);
11750
11751 if (mBroadcastsScheduled) {
11752 return;
11753 }
11754 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11755 mBroadcastsScheduled = true;
11756 }
11757
11758 public Intent registerReceiver(IApplicationThread caller,
11759 IIntentReceiver receiver, IntentFilter filter, String permission) {
11760 synchronized(this) {
11761 ProcessRecord callerApp = null;
11762 if (caller != null) {
11763 callerApp = getRecordForAppLocked(caller);
11764 if (callerApp == null) {
11765 throw new SecurityException(
11766 "Unable to find app for caller " + caller
11767 + " (pid=" + Binder.getCallingPid()
11768 + ") when registering receiver " + receiver);
11769 }
11770 }
11771
11772 List allSticky = null;
11773
11774 // Look for any matching sticky broadcasts...
11775 Iterator actions = filter.actionsIterator();
11776 if (actions != null) {
11777 while (actions.hasNext()) {
11778 String action = (String)actions.next();
11779 allSticky = getStickies(action, filter, allSticky);
11780 }
11781 } else {
11782 allSticky = getStickies(null, filter, allSticky);
11783 }
11784
11785 // The first sticky in the list is returned directly back to
11786 // the client.
11787 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11788
11789 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11790 + ": " + sticky);
11791
11792 if (receiver == null) {
11793 return sticky;
11794 }
11795
11796 ReceiverList rl
11797 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11798 if (rl == null) {
11799 rl = new ReceiverList(this, callerApp,
11800 Binder.getCallingPid(),
11801 Binder.getCallingUid(), receiver);
11802 if (rl.app != null) {
11803 rl.app.receivers.add(rl);
11804 } else {
11805 try {
11806 receiver.asBinder().linkToDeath(rl, 0);
11807 } catch (RemoteException e) {
11808 return sticky;
11809 }
11810 rl.linkedToDeath = true;
11811 }
11812 mRegisteredReceivers.put(receiver.asBinder(), rl);
11813 }
11814 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11815 rl.add(bf);
11816 if (!bf.debugCheck()) {
11817 Log.w(TAG, "==> For Dynamic broadast");
11818 }
11819 mReceiverResolver.addFilter(bf);
11820
11821 // Enqueue broadcasts for all existing stickies that match
11822 // this filter.
11823 if (allSticky != null) {
11824 ArrayList receivers = new ArrayList();
11825 receivers.add(bf);
11826
11827 int N = allSticky.size();
11828 for (int i=0; i<N; i++) {
11829 Intent intent = (Intent)allSticky.get(i);
11830 BroadcastRecord r = new BroadcastRecord(intent, null,
11831 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011832 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011833 if (mParallelBroadcasts.size() == 0) {
11834 scheduleBroadcastsLocked();
11835 }
11836 mParallelBroadcasts.add(r);
11837 }
11838 }
11839
11840 return sticky;
11841 }
11842 }
11843
11844 public void unregisterReceiver(IIntentReceiver receiver) {
11845 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11846
11847 boolean doNext = false;
11848
11849 synchronized(this) {
11850 ReceiverList rl
11851 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11852 if (rl != null) {
11853 if (rl.curBroadcast != null) {
11854 BroadcastRecord r = rl.curBroadcast;
11855 doNext = finishReceiverLocked(
11856 receiver.asBinder(), r.resultCode, r.resultData,
11857 r.resultExtras, r.resultAbort, true);
11858 }
11859
11860 if (rl.app != null) {
11861 rl.app.receivers.remove(rl);
11862 }
11863 removeReceiverLocked(rl);
11864 if (rl.linkedToDeath) {
11865 rl.linkedToDeath = false;
11866 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11867 }
11868 }
11869 }
11870
11871 if (!doNext) {
11872 return;
11873 }
11874
11875 final long origId = Binder.clearCallingIdentity();
11876 processNextBroadcast(false);
11877 trimApplications();
11878 Binder.restoreCallingIdentity(origId);
11879 }
11880
11881 void removeReceiverLocked(ReceiverList rl) {
11882 mRegisteredReceivers.remove(rl.receiver.asBinder());
11883 int N = rl.size();
11884 for (int i=0; i<N; i++) {
11885 mReceiverResolver.removeFilter(rl.get(i));
11886 }
11887 }
11888
11889 private final int broadcastIntentLocked(ProcessRecord callerApp,
11890 String callerPackage, Intent intent, String resolvedType,
11891 IIntentReceiver resultTo, int resultCode, String resultData,
11892 Bundle map, String requiredPermission,
11893 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11894 intent = new Intent(intent);
11895
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011896 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011897 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11898 + " ordered=" + ordered);
11899 if ((resultTo != null) && !ordered) {
11900 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11901 }
11902
11903 // Handle special intents: if this broadcast is from the package
11904 // manager about a package being removed, we need to remove all of
11905 // its activities from the history stack.
11906 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11907 intent.getAction());
11908 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11909 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11910 || uidRemoved) {
11911 if (checkComponentPermission(
11912 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11913 callingPid, callingUid, -1)
11914 == PackageManager.PERMISSION_GRANTED) {
11915 if (uidRemoved) {
11916 final Bundle intentExtras = intent.getExtras();
11917 final int uid = intentExtras != null
11918 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11919 if (uid >= 0) {
11920 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11921 synchronized (bs) {
11922 bs.removeUidStatsLocked(uid);
11923 }
11924 }
11925 } else {
11926 Uri data = intent.getData();
11927 String ssp;
11928 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11929 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -080011930 forceStopPackageLocked(ssp,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011931 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011932 AttributeCache ac = AttributeCache.instance();
11933 if (ac != null) {
11934 ac.removePackage(ssp);
11935 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011936 }
11937 }
11938 }
11939 } else {
11940 String msg = "Permission Denial: " + intent.getAction()
11941 + " broadcast from " + callerPackage + " (pid=" + callingPid
11942 + ", uid=" + callingUid + ")"
11943 + " requires "
11944 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11945 Log.w(TAG, msg);
11946 throw new SecurityException(msg);
11947 }
11948 }
11949
11950 /*
11951 * If this is the time zone changed action, queue up a message that will reset the timezone
11952 * of all currently running processes. This message will get queued up before the broadcast
11953 * happens.
11954 */
11955 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11956 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11957 }
11958
Dianne Hackborn854060af2009-07-09 18:14:31 -070011959 /*
11960 * Prevent non-system code (defined here to be non-persistent
11961 * processes) from sending protected broadcasts.
11962 */
11963 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11964 || callingUid == Process.SHELL_UID || callingUid == 0) {
11965 // Always okay.
11966 } else if (callerApp == null || !callerApp.persistent) {
11967 try {
11968 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11969 intent.getAction())) {
11970 String msg = "Permission Denial: not allowed to send broadcast "
11971 + intent.getAction() + " from pid="
11972 + callingPid + ", uid=" + callingUid;
11973 Log.w(TAG, msg);
11974 throw new SecurityException(msg);
11975 }
11976 } catch (RemoteException e) {
11977 Log.w(TAG, "Remote exception", e);
11978 return BROADCAST_SUCCESS;
11979 }
11980 }
11981
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011982 // Add to the sticky list if requested.
11983 if (sticky) {
11984 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11985 callingPid, callingUid)
11986 != PackageManager.PERMISSION_GRANTED) {
11987 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11988 + callingPid + ", uid=" + callingUid
11989 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11990 Log.w(TAG, msg);
11991 throw new SecurityException(msg);
11992 }
11993 if (requiredPermission != null) {
11994 Log.w(TAG, "Can't broadcast sticky intent " + intent
11995 + " and enforce permission " + requiredPermission);
11996 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11997 }
11998 if (intent.getComponent() != null) {
11999 throw new SecurityException(
12000 "Sticky broadcasts can't target a specific component");
12001 }
12002 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12003 if (list == null) {
12004 list = new ArrayList<Intent>();
12005 mStickyBroadcasts.put(intent.getAction(), list);
12006 }
12007 int N = list.size();
12008 int i;
12009 for (i=0; i<N; i++) {
12010 if (intent.filterEquals(list.get(i))) {
12011 // This sticky already exists, replace it.
12012 list.set(i, new Intent(intent));
12013 break;
12014 }
12015 }
12016 if (i >= N) {
12017 list.add(new Intent(intent));
12018 }
12019 }
12020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012021 // Figure out who all will receive this broadcast.
12022 List receivers = null;
12023 List<BroadcastFilter> registeredReceivers = null;
12024 try {
12025 if (intent.getComponent() != null) {
12026 // Broadcast is going to one specific receiver class...
12027 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012028 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012029 if (ai != null) {
12030 receivers = new ArrayList();
12031 ResolveInfo ri = new ResolveInfo();
12032 ri.activityInfo = ai;
12033 receivers.add(ri);
12034 }
12035 } else {
12036 // Need to resolve the intent to interested receivers...
12037 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12038 == 0) {
12039 receivers =
12040 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012041 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012042 }
Mihai Preda074edef2009-05-18 17:13:31 +020012043 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012044 }
12045 } catch (RemoteException ex) {
12046 // pm is in same process, this will never happen.
12047 }
12048
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012049 final boolean replacePending =
12050 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12051
12052 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12053 + " replacePending=" + replacePending);
12054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012055 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12056 if (!ordered && NR > 0) {
12057 // If we are not serializing this broadcast, then send the
12058 // registered receivers separately so they don't wait for the
12059 // components to be launched.
12060 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12061 callerPackage, callingPid, callingUid, requiredPermission,
12062 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012063 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012064 if (DEBUG_BROADCAST) Log.v(
12065 TAG, "Enqueueing parallel broadcast " + r
12066 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012067 boolean replaced = false;
12068 if (replacePending) {
12069 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12070 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12071 if (DEBUG_BROADCAST) Log.v(TAG,
12072 "***** DROPPING PARALLEL: " + intent);
12073 mParallelBroadcasts.set(i, r);
12074 replaced = true;
12075 break;
12076 }
12077 }
12078 }
12079 if (!replaced) {
12080 mParallelBroadcasts.add(r);
12081 scheduleBroadcastsLocked();
12082 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012083 registeredReceivers = null;
12084 NR = 0;
12085 }
12086
12087 // Merge into one list.
12088 int ir = 0;
12089 if (receivers != null) {
12090 // A special case for PACKAGE_ADDED: do not allow the package
12091 // being added to see this broadcast. This prevents them from
12092 // using this as a back door to get run as soon as they are
12093 // installed. Maybe in the future we want to have a special install
12094 // broadcast or such for apps, but we'd like to deliberately make
12095 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070012096 boolean skip = false;
12097 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070012098 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070012099 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
12100 skip = true;
12101 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12102 skip = true;
12103 }
12104 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012105 ? intent.getData().getSchemeSpecificPart()
12106 : null;
12107 if (skipPackage != null && receivers != null) {
12108 int NT = receivers.size();
12109 for (int it=0; it<NT; it++) {
12110 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12111 if (curt.activityInfo.packageName.equals(skipPackage)) {
12112 receivers.remove(it);
12113 it--;
12114 NT--;
12115 }
12116 }
12117 }
12118
12119 int NT = receivers != null ? receivers.size() : 0;
12120 int it = 0;
12121 ResolveInfo curt = null;
12122 BroadcastFilter curr = null;
12123 while (it < NT && ir < NR) {
12124 if (curt == null) {
12125 curt = (ResolveInfo)receivers.get(it);
12126 }
12127 if (curr == null) {
12128 curr = registeredReceivers.get(ir);
12129 }
12130 if (curr.getPriority() >= curt.priority) {
12131 // Insert this broadcast record into the final list.
12132 receivers.add(it, curr);
12133 ir++;
12134 curr = null;
12135 it++;
12136 NT++;
12137 } else {
12138 // Skip to the next ResolveInfo in the final list.
12139 it++;
12140 curt = null;
12141 }
12142 }
12143 }
12144 while (ir < NR) {
12145 if (receivers == null) {
12146 receivers = new ArrayList();
12147 }
12148 receivers.add(registeredReceivers.get(ir));
12149 ir++;
12150 }
12151
12152 if ((receivers != null && receivers.size() > 0)
12153 || resultTo != null) {
12154 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12155 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012156 receivers, resultTo, resultCode, resultData, map, ordered,
12157 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012158 if (DEBUG_BROADCAST) Log.v(
12159 TAG, "Enqueueing ordered broadcast " + r
12160 + ": prev had " + mOrderedBroadcasts.size());
12161 if (DEBUG_BROADCAST) {
12162 int seq = r.intent.getIntExtra("seq", -1);
12163 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12164 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012165 boolean replaced = false;
12166 if (replacePending) {
12167 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12168 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12169 if (DEBUG_BROADCAST) Log.v(TAG,
12170 "***** DROPPING ORDERED: " + intent);
12171 mOrderedBroadcasts.set(i, r);
12172 replaced = true;
12173 break;
12174 }
12175 }
12176 }
12177 if (!replaced) {
12178 mOrderedBroadcasts.add(r);
12179 scheduleBroadcastsLocked();
12180 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012181 }
12182
12183 return BROADCAST_SUCCESS;
12184 }
12185
12186 public final int broadcastIntent(IApplicationThread caller,
12187 Intent intent, String resolvedType, IIntentReceiver resultTo,
12188 int resultCode, String resultData, Bundle map,
12189 String requiredPermission, boolean serialized, boolean sticky) {
12190 // Refuse possible leaked file descriptors
12191 if (intent != null && intent.hasFileDescriptors() == true) {
12192 throw new IllegalArgumentException("File descriptors passed in Intent");
12193 }
12194
12195 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012196 int flags = intent.getFlags();
12197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012198 if (!mSystemReady) {
12199 // if the caller really truly claims to know what they're doing, go
12200 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012201 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12202 intent = new Intent(intent);
12203 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12204 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12205 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12206 + " before boot completion");
12207 throw new IllegalStateException("Cannot broadcast before boot completed");
12208 }
12209 }
12210
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012211 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12212 throw new IllegalArgumentException(
12213 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12214 }
12215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012216 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12217 final int callingPid = Binder.getCallingPid();
12218 final int callingUid = Binder.getCallingUid();
12219 final long origId = Binder.clearCallingIdentity();
12220 int res = broadcastIntentLocked(callerApp,
12221 callerApp != null ? callerApp.info.packageName : null,
12222 intent, resolvedType, resultTo,
12223 resultCode, resultData, map, requiredPermission, serialized,
12224 sticky, callingPid, callingUid);
12225 Binder.restoreCallingIdentity(origId);
12226 return res;
12227 }
12228 }
12229
12230 int broadcastIntentInPackage(String packageName, int uid,
12231 Intent intent, String resolvedType, IIntentReceiver resultTo,
12232 int resultCode, String resultData, Bundle map,
12233 String requiredPermission, boolean serialized, boolean sticky) {
12234 synchronized(this) {
12235 final long origId = Binder.clearCallingIdentity();
12236 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12237 resultTo, resultCode, resultData, map, requiredPermission,
12238 serialized, sticky, -1, uid);
12239 Binder.restoreCallingIdentity(origId);
12240 return res;
12241 }
12242 }
12243
12244 public final void unbroadcastIntent(IApplicationThread caller,
12245 Intent intent) {
12246 // Refuse possible leaked file descriptors
12247 if (intent != null && intent.hasFileDescriptors() == true) {
12248 throw new IllegalArgumentException("File descriptors passed in Intent");
12249 }
12250
12251 synchronized(this) {
12252 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12253 != PackageManager.PERMISSION_GRANTED) {
12254 String msg = "Permission Denial: unbroadcastIntent() from pid="
12255 + Binder.getCallingPid()
12256 + ", uid=" + Binder.getCallingUid()
12257 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12258 Log.w(TAG, msg);
12259 throw new SecurityException(msg);
12260 }
12261 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12262 if (list != null) {
12263 int N = list.size();
12264 int i;
12265 for (i=0; i<N; i++) {
12266 if (intent.filterEquals(list.get(i))) {
12267 list.remove(i);
12268 break;
12269 }
12270 }
12271 }
12272 }
12273 }
12274
12275 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12276 String resultData, Bundle resultExtras, boolean resultAbort,
12277 boolean explicit) {
12278 if (mOrderedBroadcasts.size() == 0) {
12279 if (explicit) {
12280 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12281 }
12282 return false;
12283 }
12284 BroadcastRecord r = mOrderedBroadcasts.get(0);
12285 if (r.receiver == null) {
12286 if (explicit) {
12287 Log.w(TAG, "finishReceiver called but none active");
12288 }
12289 return false;
12290 }
12291 if (r.receiver != receiver) {
12292 Log.w(TAG, "finishReceiver called but active receiver is different");
12293 return false;
12294 }
12295 int state = r.state;
12296 r.state = r.IDLE;
12297 if (state == r.IDLE) {
12298 if (explicit) {
12299 Log.w(TAG, "finishReceiver called but state is IDLE");
12300 }
12301 }
12302 r.receiver = null;
12303 r.intent.setComponent(null);
12304 if (r.curApp != null) {
12305 r.curApp.curReceiver = null;
12306 }
12307 if (r.curFilter != null) {
12308 r.curFilter.receiverList.curBroadcast = null;
12309 }
12310 r.curFilter = null;
12311 r.curApp = null;
12312 r.curComponent = null;
12313 r.curReceiver = null;
12314 mPendingBroadcast = null;
12315
12316 r.resultCode = resultCode;
12317 r.resultData = resultData;
12318 r.resultExtras = resultExtras;
12319 r.resultAbort = resultAbort;
12320
12321 // We will process the next receiver right now if this is finishing
12322 // an app receiver (which is always asynchronous) or after we have
12323 // come back from calling a receiver.
12324 return state == BroadcastRecord.APP_RECEIVE
12325 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12326 }
12327
12328 public void finishReceiver(IBinder who, int resultCode, String resultData,
12329 Bundle resultExtras, boolean resultAbort) {
12330 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12331
12332 // Refuse possible leaked file descriptors
12333 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12334 throw new IllegalArgumentException("File descriptors passed in Bundle");
12335 }
12336
12337 boolean doNext;
12338
12339 final long origId = Binder.clearCallingIdentity();
12340
12341 synchronized(this) {
12342 doNext = finishReceiverLocked(
12343 who, resultCode, resultData, resultExtras, resultAbort, true);
12344 }
12345
12346 if (doNext) {
12347 processNextBroadcast(false);
12348 }
12349 trimApplications();
12350
12351 Binder.restoreCallingIdentity(origId);
12352 }
12353
12354 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12355 if (r.nextReceiver > 0) {
12356 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12357 if (curReceiver instanceof BroadcastFilter) {
12358 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012359 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012360 System.identityHashCode(r),
12361 r.intent.getAction(),
12362 r.nextReceiver - 1,
12363 System.identityHashCode(bf));
12364 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012365 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012366 System.identityHashCode(r),
12367 r.intent.getAction(),
12368 r.nextReceiver - 1,
12369 ((ResolveInfo)curReceiver).toString());
12370 }
12371 } else {
12372 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12373 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012374 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012375 System.identityHashCode(r),
12376 r.intent.getAction(),
12377 r.nextReceiver,
12378 "NONE");
12379 }
12380 }
12381
12382 private final void broadcastTimeout() {
12383 synchronized (this) {
12384 if (mOrderedBroadcasts.size() == 0) {
12385 return;
12386 }
12387 long now = SystemClock.uptimeMillis();
12388 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012389 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012390 if (DEBUG_BROADCAST) Log.v(TAG,
12391 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012392 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012393 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012394 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012395 return;
12396 }
12397
12398 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012399 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012400 r.anrCount++;
12401
12402 // Current receiver has passed its expiration date.
12403 if (r.nextReceiver <= 0) {
12404 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12405 return;
12406 }
12407
12408 ProcessRecord app = null;
12409
12410 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12411 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12412 logBroadcastReceiverDiscard(r);
12413 if (curReceiver instanceof BroadcastFilter) {
12414 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12415 if (bf.receiverList.pid != 0
12416 && bf.receiverList.pid != MY_PID) {
12417 synchronized (this.mPidsSelfLocked) {
12418 app = this.mPidsSelfLocked.get(
12419 bf.receiverList.pid);
12420 }
12421 }
12422 } else {
12423 app = r.curApp;
12424 }
12425
12426 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012427 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012428 }
12429
12430 if (mPendingBroadcast == r) {
12431 mPendingBroadcast = null;
12432 }
12433
12434 // Move on to the next receiver.
12435 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12436 r.resultExtras, r.resultAbort, true);
12437 scheduleBroadcastsLocked();
12438 }
12439 }
12440
12441 private final void processCurBroadcastLocked(BroadcastRecord r,
12442 ProcessRecord app) throws RemoteException {
12443 if (app.thread == null) {
12444 throw new RemoteException();
12445 }
12446 r.receiver = app.thread.asBinder();
12447 r.curApp = app;
12448 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012449 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012450
12451 // Tell the application to launch this receiver.
12452 r.intent.setComponent(r.curComponent);
12453
12454 boolean started = false;
12455 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012456 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012457 "Delivering to component " + r.curComponent
12458 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012459 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012460 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12461 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12462 started = true;
12463 } finally {
12464 if (!started) {
12465 r.receiver = null;
12466 r.curApp = null;
12467 app.curReceiver = null;
12468 }
12469 }
12470
12471 }
12472
12473 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012474 Intent intent, int resultCode, String data, Bundle extras,
12475 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012476 if (app != null && app.thread != null) {
12477 // If we have an app thread, do the call through that so it is
12478 // correctly ordered with other one-way calls.
12479 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012480 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012481 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012482 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012483 }
12484 }
12485
12486 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12487 BroadcastFilter filter, boolean ordered) {
12488 boolean skip = false;
12489 if (filter.requiredPermission != null) {
12490 int perm = checkComponentPermission(filter.requiredPermission,
12491 r.callingPid, r.callingUid, -1);
12492 if (perm != PackageManager.PERMISSION_GRANTED) {
12493 Log.w(TAG, "Permission Denial: broadcasting "
12494 + r.intent.toString()
12495 + " from " + r.callerPackage + " (pid="
12496 + r.callingPid + ", uid=" + r.callingUid + ")"
12497 + " requires " + filter.requiredPermission
12498 + " due to registered receiver " + filter);
12499 skip = true;
12500 }
12501 }
12502 if (r.requiredPermission != null) {
12503 int perm = checkComponentPermission(r.requiredPermission,
12504 filter.receiverList.pid, filter.receiverList.uid, -1);
12505 if (perm != PackageManager.PERMISSION_GRANTED) {
12506 Log.w(TAG, "Permission Denial: receiving "
12507 + r.intent.toString()
12508 + " to " + filter.receiverList.app
12509 + " (pid=" + filter.receiverList.pid
12510 + ", uid=" + filter.receiverList.uid + ")"
12511 + " requires " + r.requiredPermission
12512 + " due to sender " + r.callerPackage
12513 + " (uid " + r.callingUid + ")");
12514 skip = true;
12515 }
12516 }
12517
12518 if (!skip) {
12519 // If this is not being sent as an ordered broadcast, then we
12520 // don't want to touch the fields that keep track of the current
12521 // state of ordered broadcasts.
12522 if (ordered) {
12523 r.receiver = filter.receiverList.receiver.asBinder();
12524 r.curFilter = filter;
12525 filter.receiverList.curBroadcast = r;
12526 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012527 if (filter.receiverList.app != null) {
12528 // Bump hosting application to no longer be in background
12529 // scheduling class. Note that we can't do that if there
12530 // isn't an app... but we can only be in that case for
12531 // things that directly call the IActivityManager API, which
12532 // are already core system stuff so don't matter for this.
12533 r.curApp = filter.receiverList.app;
12534 filter.receiverList.app.curReceiver = r;
12535 updateOomAdjLocked();
12536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012537 }
12538 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012539 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012540 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012541 Log.i(TAG, "Delivering to " + filter.receiverList.app
12542 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012543 }
12544 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12545 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012546 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012547 if (ordered) {
12548 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12549 }
12550 } catch (RemoteException e) {
12551 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12552 if (ordered) {
12553 r.receiver = null;
12554 r.curFilter = null;
12555 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012556 if (filter.receiverList.app != null) {
12557 filter.receiverList.app.curReceiver = null;
12558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012559 }
12560 }
12561 }
12562 }
12563
Dianne Hackborn12527f92009-11-11 17:39:50 -080012564 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12565 if (r.callingUid < 0) {
12566 // This was from a registerReceiver() call; ignore it.
12567 return;
12568 }
12569 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12570 MAX_BROADCAST_HISTORY-1);
12571 r.finishTime = SystemClock.uptimeMillis();
12572 mBroadcastHistory[0] = r;
12573 }
12574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012575 private final void processNextBroadcast(boolean fromMsg) {
12576 synchronized(this) {
12577 BroadcastRecord r;
12578
12579 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12580 + mParallelBroadcasts.size() + " broadcasts, "
12581 + mOrderedBroadcasts.size() + " serialized broadcasts");
12582
12583 updateCpuStats();
12584
12585 if (fromMsg) {
12586 mBroadcastsScheduled = false;
12587 }
12588
12589 // First, deliver any non-serialized broadcasts right away.
12590 while (mParallelBroadcasts.size() > 0) {
12591 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012592 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012593 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012594 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12595 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012596 for (int i=0; i<N; i++) {
12597 Object target = r.receivers.get(i);
12598 if (DEBUG_BROADCAST) Log.v(TAG,
12599 "Delivering non-serialized to registered "
12600 + target + ": " + r);
12601 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12602 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012603 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012604 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12605 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012606 }
12607
12608 // Now take care of the next serialized one...
12609
12610 // If we are waiting for a process to come up to handle the next
12611 // broadcast, then do nothing at this point. Just in case, we
12612 // check that the process we're waiting for still exists.
12613 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012614 if (DEBUG_BROADCAST_LIGHT) {
12615 Log.v(TAG, "processNextBroadcast: waiting for "
12616 + mPendingBroadcast.curApp);
12617 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012618
12619 boolean isDead;
12620 synchronized (mPidsSelfLocked) {
12621 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12622 }
12623 if (!isDead) {
12624 // It's still alive, so keep waiting
12625 return;
12626 } else {
12627 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12628 + " died before responding to broadcast");
12629 mPendingBroadcast = null;
12630 }
12631 }
12632
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012633 boolean looped = false;
12634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012635 do {
12636 if (mOrderedBroadcasts.size() == 0) {
12637 // No more broadcasts pending, so all done!
12638 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012639 if (looped) {
12640 // If we had finished the last ordered broadcast, then
12641 // make sure all processes have correct oom and sched
12642 // adjustments.
12643 updateOomAdjLocked();
12644 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012645 return;
12646 }
12647 r = mOrderedBroadcasts.get(0);
12648 boolean forceReceive = false;
12649
12650 // Ensure that even if something goes awry with the timeout
12651 // detection, we catch "hung" broadcasts here, discard them,
12652 // and continue to make progress.
12653 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12654 long now = SystemClock.uptimeMillis();
12655 if (r.dispatchTime > 0) {
12656 if ((numReceivers > 0) &&
12657 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12658 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12659 + " now=" + now
12660 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012661 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012662 + " intent=" + r.intent
12663 + " numReceivers=" + numReceivers
12664 + " nextReceiver=" + r.nextReceiver
12665 + " state=" + r.state);
12666 broadcastTimeout(); // forcibly finish this broadcast
12667 forceReceive = true;
12668 r.state = BroadcastRecord.IDLE;
12669 }
12670 }
12671
12672 if (r.state != BroadcastRecord.IDLE) {
12673 if (DEBUG_BROADCAST) Log.d(TAG,
12674 "processNextBroadcast() called when not idle (state="
12675 + r.state + ")");
12676 return;
12677 }
12678
12679 if (r.receivers == null || r.nextReceiver >= numReceivers
12680 || r.resultAbort || forceReceive) {
12681 // No more receivers for this broadcast! Send the final
12682 // result if requested...
12683 if (r.resultTo != null) {
12684 try {
12685 if (DEBUG_BROADCAST) {
12686 int seq = r.intent.getIntExtra("seq", -1);
12687 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12688 + " seq=" + seq + " app=" + r.callerApp);
12689 }
12690 performReceive(r.callerApp, r.resultTo,
12691 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012692 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012693 } catch (RemoteException e) {
12694 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12695 }
12696 }
12697
12698 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12699 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12700
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012701 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12702 + r);
12703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012704 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012705 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012706 mOrderedBroadcasts.remove(0);
12707 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012708 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012709 continue;
12710 }
12711 } while (r == null);
12712
12713 // Get the next receiver...
12714 int recIdx = r.nextReceiver++;
12715
12716 // Keep track of when this receiver started, and make sure there
12717 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012718 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012719 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012720 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012721
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012722 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12723 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012724 if (DEBUG_BROADCAST) Log.v(TAG,
12725 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012726 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012727 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012728 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012729 }
12730
12731 Object nextReceiver = r.receivers.get(recIdx);
12732 if (nextReceiver instanceof BroadcastFilter) {
12733 // Simple case: this is a registered receiver who gets
12734 // a direct call.
12735 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12736 if (DEBUG_BROADCAST) Log.v(TAG,
12737 "Delivering serialized to registered "
12738 + filter + ": " + r);
12739 deliverToRegisteredReceiver(r, filter, r.ordered);
12740 if (r.receiver == null || !r.ordered) {
12741 // The receiver has already finished, so schedule to
12742 // process the next one.
12743 r.state = BroadcastRecord.IDLE;
12744 scheduleBroadcastsLocked();
12745 }
12746 return;
12747 }
12748
12749 // Hard case: need to instantiate the receiver, possibly
12750 // starting its application process to host it.
12751
12752 ResolveInfo info =
12753 (ResolveInfo)nextReceiver;
12754
12755 boolean skip = false;
12756 int perm = checkComponentPermission(info.activityInfo.permission,
12757 r.callingPid, r.callingUid,
12758 info.activityInfo.exported
12759 ? -1 : info.activityInfo.applicationInfo.uid);
12760 if (perm != PackageManager.PERMISSION_GRANTED) {
12761 Log.w(TAG, "Permission Denial: broadcasting "
12762 + r.intent.toString()
12763 + " from " + r.callerPackage + " (pid=" + r.callingPid
12764 + ", uid=" + r.callingUid + ")"
12765 + " requires " + info.activityInfo.permission
12766 + " due to receiver " + info.activityInfo.packageName
12767 + "/" + info.activityInfo.name);
12768 skip = true;
12769 }
12770 if (r.callingUid != Process.SYSTEM_UID &&
12771 r.requiredPermission != null) {
12772 try {
12773 perm = ActivityThread.getPackageManager().
12774 checkPermission(r.requiredPermission,
12775 info.activityInfo.applicationInfo.packageName);
12776 } catch (RemoteException e) {
12777 perm = PackageManager.PERMISSION_DENIED;
12778 }
12779 if (perm != PackageManager.PERMISSION_GRANTED) {
12780 Log.w(TAG, "Permission Denial: receiving "
12781 + r.intent + " to "
12782 + info.activityInfo.applicationInfo.packageName
12783 + " requires " + r.requiredPermission
12784 + " due to sender " + r.callerPackage
12785 + " (uid " + r.callingUid + ")");
12786 skip = true;
12787 }
12788 }
12789 if (r.curApp != null && r.curApp.crashing) {
12790 // If the target process is crashing, just skip it.
12791 skip = true;
12792 }
12793
12794 if (skip) {
12795 r.receiver = null;
12796 r.curFilter = null;
12797 r.state = BroadcastRecord.IDLE;
12798 scheduleBroadcastsLocked();
12799 return;
12800 }
12801
12802 r.state = BroadcastRecord.APP_RECEIVE;
12803 String targetProcess = info.activityInfo.processName;
12804 r.curComponent = new ComponentName(
12805 info.activityInfo.applicationInfo.packageName,
12806 info.activityInfo.name);
12807 r.curReceiver = info.activityInfo;
12808
12809 // Is this receiver's application already running?
12810 ProcessRecord app = getProcessRecordLocked(targetProcess,
12811 info.activityInfo.applicationInfo.uid);
12812 if (app != null && app.thread != null) {
12813 try {
12814 processCurBroadcastLocked(r, app);
12815 return;
12816 } catch (RemoteException e) {
12817 Log.w(TAG, "Exception when sending broadcast to "
12818 + r.curComponent, e);
12819 }
12820
12821 // If a dead object exception was thrown -- fall through to
12822 // restart the application.
12823 }
12824
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012825 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012826 if ((r.curApp=startProcessLocked(targetProcess,
12827 info.activityInfo.applicationInfo, true,
12828 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012829 "broadcast", r.curComponent,
12830 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12831 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012832 // Ah, this recipient is unavailable. Finish it if necessary,
12833 // and mark the broadcast record as ready for the next.
12834 Log.w(TAG, "Unable to launch app "
12835 + info.activityInfo.applicationInfo.packageName + "/"
12836 + info.activityInfo.applicationInfo.uid + " for broadcast "
12837 + r.intent + ": process is bad");
12838 logBroadcastReceiverDiscard(r);
12839 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12840 r.resultExtras, r.resultAbort, true);
12841 scheduleBroadcastsLocked();
12842 r.state = BroadcastRecord.IDLE;
12843 return;
12844 }
12845
12846 mPendingBroadcast = r;
12847 }
12848 }
12849
12850 // =========================================================
12851 // INSTRUMENTATION
12852 // =========================================================
12853
12854 public boolean startInstrumentation(ComponentName className,
12855 String profileFile, int flags, Bundle arguments,
12856 IInstrumentationWatcher watcher) {
12857 // Refuse possible leaked file descriptors
12858 if (arguments != null && arguments.hasFileDescriptors()) {
12859 throw new IllegalArgumentException("File descriptors passed in Bundle");
12860 }
12861
12862 synchronized(this) {
12863 InstrumentationInfo ii = null;
12864 ApplicationInfo ai = null;
12865 try {
12866 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012867 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012868 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012869 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012870 } catch (PackageManager.NameNotFoundException e) {
12871 }
12872 if (ii == null) {
12873 reportStartInstrumentationFailure(watcher, className,
12874 "Unable to find instrumentation info for: " + className);
12875 return false;
12876 }
12877 if (ai == null) {
12878 reportStartInstrumentationFailure(watcher, className,
12879 "Unable to find instrumentation target package: " + ii.targetPackage);
12880 return false;
12881 }
12882
12883 int match = mContext.getPackageManager().checkSignatures(
12884 ii.targetPackage, ii.packageName);
12885 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12886 String msg = "Permission Denial: starting instrumentation "
12887 + className + " from pid="
12888 + Binder.getCallingPid()
12889 + ", uid=" + Binder.getCallingPid()
12890 + " not allowed because package " + ii.packageName
12891 + " does not have a signature matching the target "
12892 + ii.targetPackage;
12893 reportStartInstrumentationFailure(watcher, className, msg);
12894 throw new SecurityException(msg);
12895 }
12896
12897 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn03abb812010-01-04 18:43:19 -080012898 forceStopPackageLocked(ii.targetPackage, -1, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012899 ProcessRecord app = addAppLocked(ai);
12900 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012901 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012902 app.instrumentationProfileFile = profileFile;
12903 app.instrumentationArguments = arguments;
12904 app.instrumentationWatcher = watcher;
12905 app.instrumentationResultClass = className;
12906 Binder.restoreCallingIdentity(origId);
12907 }
12908
12909 return true;
12910 }
12911
12912 /**
12913 * Report errors that occur while attempting to start Instrumentation. Always writes the
12914 * error to the logs, but if somebody is watching, send the report there too. This enables
12915 * the "am" command to report errors with more information.
12916 *
12917 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12918 * @param cn The component name of the instrumentation.
12919 * @param report The error report.
12920 */
12921 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12922 ComponentName cn, String report) {
12923 Log.w(TAG, report);
12924 try {
12925 if (watcher != null) {
12926 Bundle results = new Bundle();
12927 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12928 results.putString("Error", report);
12929 watcher.instrumentationStatus(cn, -1, results);
12930 }
12931 } catch (RemoteException e) {
12932 Log.w(TAG, e);
12933 }
12934 }
12935
12936 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12937 if (app.instrumentationWatcher != null) {
12938 try {
12939 // NOTE: IInstrumentationWatcher *must* be oneway here
12940 app.instrumentationWatcher.instrumentationFinished(
12941 app.instrumentationClass,
12942 resultCode,
12943 results);
12944 } catch (RemoteException e) {
12945 }
12946 }
12947 app.instrumentationWatcher = null;
12948 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012949 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012950 app.instrumentationProfileFile = null;
12951 app.instrumentationArguments = null;
12952
Dianne Hackborn03abb812010-01-04 18:43:19 -080012953 forceStopPackageLocked(app.processName, -1, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012954 }
12955
12956 public void finishInstrumentation(IApplicationThread target,
12957 int resultCode, Bundle results) {
12958 // Refuse possible leaked file descriptors
12959 if (results != null && results.hasFileDescriptors()) {
12960 throw new IllegalArgumentException("File descriptors passed in Intent");
12961 }
12962
12963 synchronized(this) {
12964 ProcessRecord app = getRecordForAppLocked(target);
12965 if (app == null) {
12966 Log.w(TAG, "finishInstrumentation: no app for " + target);
12967 return;
12968 }
12969 final long origId = Binder.clearCallingIdentity();
12970 finishInstrumentationLocked(app, resultCode, results);
12971 Binder.restoreCallingIdentity(origId);
12972 }
12973 }
12974
12975 // =========================================================
12976 // CONFIGURATION
12977 // =========================================================
12978
12979 public ConfigurationInfo getDeviceConfigurationInfo() {
12980 ConfigurationInfo config = new ConfigurationInfo();
12981 synchronized (this) {
12982 config.reqTouchScreen = mConfiguration.touchscreen;
12983 config.reqKeyboardType = mConfiguration.keyboard;
12984 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012985 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12986 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012987 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12988 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012989 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12990 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012991 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12992 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012993 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012994 }
12995 return config;
12996 }
12997
12998 public Configuration getConfiguration() {
12999 Configuration ci;
13000 synchronized(this) {
13001 ci = new Configuration(mConfiguration);
13002 }
13003 return ci;
13004 }
13005
13006 public void updateConfiguration(Configuration values) {
13007 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13008 "updateConfiguration()");
13009
13010 synchronized(this) {
13011 if (values == null && mWindowManager != null) {
13012 // sentinel: fetch the current configuration from the window manager
13013 values = mWindowManager.computeNewConfiguration();
13014 }
13015
13016 final long origId = Binder.clearCallingIdentity();
13017 updateConfigurationLocked(values, null);
13018 Binder.restoreCallingIdentity(origId);
13019 }
13020 }
13021
13022 /**
13023 * Do either or both things: (1) change the current configuration, and (2)
13024 * make sure the given activity is running with the (now) current
13025 * configuration. Returns true if the activity has been left running, or
13026 * false if <var>starting</var> is being destroyed to match the new
13027 * configuration.
13028 */
13029 public boolean updateConfigurationLocked(Configuration values,
13030 HistoryRecord starting) {
13031 int changes = 0;
13032
13033 boolean kept = true;
13034
13035 if (values != null) {
13036 Configuration newConfig = new Configuration(mConfiguration);
13037 changes = newConfig.updateFrom(values);
13038 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013039 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013040 Log.i(TAG, "Updating configuration to: " + values);
13041 }
13042
Doug Zongker2bec3d42009-12-04 12:52:44 -080013043 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013044
13045 if (values.locale != null) {
13046 saveLocaleLocked(values.locale,
13047 !values.locale.equals(mConfiguration.locale),
13048 values.userSetLocale);
13049 }
13050
13051 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013052 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013053
13054 AttributeCache ac = AttributeCache.instance();
13055 if (ac != null) {
13056 ac.updateConfiguration(mConfiguration);
13057 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013058
13059 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13060 msg.obj = new Configuration(mConfiguration);
13061 mHandler.sendMessage(msg);
13062
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013063 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13064 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013065 try {
13066 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013067 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13068 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013069 app.thread.scheduleConfigurationChanged(mConfiguration);
13070 }
13071 } catch (Exception e) {
13072 }
13073 }
13074 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013075 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13076 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013077 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13078 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013079 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13080 broadcastIntentLocked(null, null,
13081 new Intent(Intent.ACTION_LOCALE_CHANGED),
13082 null, null, 0, null, null,
13083 null, false, false, MY_PID, Process.SYSTEM_UID);
13084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013085 }
13086 }
13087
13088 if (changes != 0 && starting == null) {
13089 // If the configuration changed, and the caller is not already
13090 // in the process of starting an activity, then find the top
13091 // activity to check if its configuration needs to change.
13092 starting = topRunningActivityLocked(null);
13093 }
13094
13095 if (starting != null) {
13096 kept = ensureActivityConfigurationLocked(starting, changes);
13097 if (kept) {
13098 // If this didn't result in the starting activity being
13099 // destroyed, then we need to make sure at this point that all
13100 // other activities are made visible.
13101 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13102 + ", ensuring others are correct.");
13103 ensureActivitiesVisibleLocked(starting, changes);
13104 }
13105 }
13106
13107 return kept;
13108 }
13109
13110 private final boolean relaunchActivityLocked(HistoryRecord r,
13111 int changes, boolean andResume) {
13112 List<ResultInfo> results = null;
13113 List<Intent> newIntents = null;
13114 if (andResume) {
13115 results = r.results;
13116 newIntents = r.newIntents;
13117 }
13118 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13119 + " with results=" + results + " newIntents=" + newIntents
13120 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013121 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13122 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013123 r.task.taskId, r.shortComponentName);
13124
13125 r.startFreezingScreenLocked(r.app, 0);
13126
13127 try {
13128 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13129 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013130 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013131 // Note: don't need to call pauseIfSleepingLocked() here, because
13132 // the caller will only pass in 'andResume' if this activity is
13133 // currently resumed, which implies we aren't sleeping.
13134 } catch (RemoteException e) {
13135 return false;
13136 }
13137
13138 if (andResume) {
13139 r.results = null;
13140 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013141 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013142 }
13143
13144 return true;
13145 }
13146
13147 /**
13148 * Make sure the given activity matches the current configuration. Returns
13149 * false if the activity had to be destroyed. Returns true if the
13150 * configuration is the same, or the activity will remain running as-is
13151 * for whatever reason. Ensures the HistoryRecord is updated with the
13152 * correct configuration and all other bookkeeping is handled.
13153 */
13154 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13155 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013156 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13157 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013158
13159 // Short circuit: if the two configurations are the exact same
13160 // object (the common case), then there is nothing to do.
13161 Configuration newConfig = mConfiguration;
13162 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013163 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13164 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013165 return true;
13166 }
13167
13168 // We don't worry about activities that are finishing.
13169 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013170 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013171 "Configuration doesn't matter in finishing " + r);
13172 r.stopFreezingScreenLocked(false);
13173 return true;
13174 }
13175
13176 // Okay we now are going to make this activity have the new config.
13177 // But then we need to figure out how it needs to deal with that.
13178 Configuration oldConfig = r.configuration;
13179 r.configuration = newConfig;
13180
13181 // If the activity isn't currently running, just leave the new
13182 // configuration and it will pick that up next time it starts.
13183 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013184 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013185 "Configuration doesn't matter not running " + r);
13186 r.stopFreezingScreenLocked(false);
13187 return true;
13188 }
13189
13190 // If the activity isn't persistent, there is a chance we will
13191 // need to restart it.
13192 if (!r.persistent) {
13193
13194 // Figure out what has changed between the two configurations.
13195 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013196 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13197 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013198 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013199 + Integer.toHexString(r.info.configChanges)
13200 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013201 }
13202 if ((changes&(~r.info.configChanges)) != 0) {
13203 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13204 r.configChangeFlags |= changes;
13205 r.startFreezingScreenLocked(r.app, globalChanges);
13206 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013207 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13208 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013209 destroyActivityLocked(r, true);
13210 } else if (r.state == ActivityState.PAUSING) {
13211 // A little annoying: we are waiting for this activity to
13212 // finish pausing. Let's not do anything now, but just
13213 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013214 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13215 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013216 r.configDestroy = true;
13217 return true;
13218 } else if (r.state == ActivityState.RESUMED) {
13219 // Try to optimize this case: the configuration is changing
13220 // and we need to restart the top, resumed activity.
13221 // Instead of doing the normal handshaking, just say
13222 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013223 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13224 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013225 relaunchActivityLocked(r, r.configChangeFlags, true);
13226 r.configChangeFlags = 0;
13227 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013228 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13229 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013230 relaunchActivityLocked(r, r.configChangeFlags, false);
13231 r.configChangeFlags = 0;
13232 }
13233
13234 // All done... tell the caller we weren't able to keep this
13235 // activity around.
13236 return false;
13237 }
13238 }
13239
13240 // Default case: the activity can handle this new configuration, so
13241 // hand it over. Note that we don't need to give it the new
13242 // configuration, since we always send configuration changes to all
13243 // process when they happen so it can just use whatever configuration
13244 // it last got.
13245 if (r.app != null && r.app.thread != null) {
13246 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013247 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013248 r.app.thread.scheduleActivityConfigurationChanged(r);
13249 } catch (RemoteException e) {
13250 // If process died, whatever.
13251 }
13252 }
13253 r.stopFreezingScreenLocked(false);
13254
13255 return true;
13256 }
13257
13258 /**
13259 * Save the locale. You must be inside a synchronized (this) block.
13260 */
13261 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13262 if(isDiff) {
13263 SystemProperties.set("user.language", l.getLanguage());
13264 SystemProperties.set("user.region", l.getCountry());
13265 }
13266
13267 if(isPersist) {
13268 SystemProperties.set("persist.sys.language", l.getLanguage());
13269 SystemProperties.set("persist.sys.country", l.getCountry());
13270 SystemProperties.set("persist.sys.localevar", l.getVariant());
13271 }
13272 }
13273
13274 // =========================================================
13275 // LIFETIME MANAGEMENT
13276 // =========================================================
13277
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013278 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13279 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013280 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013281 // This adjustment has already been computed. If we are calling
13282 // from the top, we may have already computed our adjustment with
13283 // an earlier hidden adjustment that isn't really for us... if
13284 // so, use the new hidden adjustment.
13285 if (!recursed && app.hidden) {
13286 app.curAdj = hiddenAdj;
13287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013288 return app.curAdj;
13289 }
13290
13291 if (app.thread == null) {
13292 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013293 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013294 return (app.curAdj=EMPTY_APP_ADJ);
13295 }
13296
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013297 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13298 // The max adjustment doesn't allow this app to be anything
13299 // below foreground, so it is not worth doing work for it.
13300 app.adjType = "fixed";
13301 app.adjSeq = mAdjSeq;
13302 app.curRawAdj = app.maxAdj;
13303 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13304 return (app.curAdj=app.maxAdj);
13305 }
13306
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013307 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013308 app.adjSource = null;
13309 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013310 app.empty = false;
13311 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013312
The Android Open Source Project4df24232009-03-05 14:34:35 -080013313 // Determine the importance of the process, starting with most
13314 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013315 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013316 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013317 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013318 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013319 // The last app on the list is the foreground app.
13320 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013321 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013322 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013323 } else if (app.instrumentationClass != null) {
13324 // Don't want to kill running instrumentation.
13325 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013326 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013327 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013328 } else if (app.persistentActivities > 0) {
13329 // Special persistent activities... shouldn't be used these days.
13330 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013331 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013332 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013333 } else if (app.curReceiver != null ||
13334 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13335 // An app that is currently receiving a broadcast also
13336 // counts as being in the foreground.
13337 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013338 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013339 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013340 } else if (app.executingServices.size() > 0) {
13341 // An app that is currently executing a service callback also
13342 // counts as being in the foreground.
13343 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013344 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013345 app.adjType = "exec-service";
13346 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013347 // The user is aware of this app, so make it visible.
13348 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013349 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013350 app.adjType = "foreground-service";
13351 } else if (app.forcingToForeground != null) {
13352 // The user is aware of this app, so make it visible.
13353 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013354 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013355 app.adjType = "force-foreground";
13356 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013357 } else if (app == mHomeProcess) {
13358 // This process is hosting what we currently consider to be the
13359 // home app, so we don't want to let it go into the background.
13360 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013361 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013362 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013363 } else if ((N=app.activities.size()) != 0) {
13364 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013365 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013366 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013367 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013368 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013369 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013370 for (int j=0; j<N; j++) {
13371 if (((HistoryRecord)app.activities.get(j)).visible) {
13372 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013373 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013374 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013375 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013376 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013377 break;
13378 }
13379 }
13380 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013381 // A very not-needed process. If this is lower in the lru list,
13382 // we will push it in to the empty bucket.
13383 app.hidden = true;
13384 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013385 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013386 adj = hiddenAdj;
13387 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013388 }
13389
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013390 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13391
The Android Open Source Project4df24232009-03-05 14:34:35 -080013392 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013393 // there are applications dependent on our services or providers, but
13394 // this gives us a baseline and makes sure we don't get into an
13395 // infinite recursion.
13396 app.adjSeq = mAdjSeq;
13397 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013398
Christopher Tate6fa95972009-06-05 18:43:55 -070013399 if (mBackupTarget != null && app == mBackupTarget.app) {
13400 // If possible we want to avoid killing apps while they're being backed up
13401 if (adj > BACKUP_APP_ADJ) {
13402 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13403 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013404 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013405 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013406 }
13407 }
13408
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013409 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13410 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013411 final long now = SystemClock.uptimeMillis();
13412 // This process is more important if the top activity is
13413 // bound to the service.
13414 Iterator jt = app.services.iterator();
13415 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13416 ServiceRecord s = (ServiceRecord)jt.next();
13417 if (s.startRequested) {
13418 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13419 // This service has seen some activity within
13420 // recent memory, so we will keep its process ahead
13421 // of the background processes.
13422 if (adj > SECONDARY_SERVER_ADJ) {
13423 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013424 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013425 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013426 }
13427 }
13428 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013429 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13430 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013431 Iterator<ConnectionRecord> kt
13432 = s.connections.values().iterator();
13433 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13434 // XXX should compute this based on the max of
13435 // all connected clients.
13436 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013437 if (cr.binding.client == app) {
13438 // Binding to ourself is not interesting.
13439 continue;
13440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013441 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13442 ProcessRecord client = cr.binding.client;
13443 int myHiddenAdj = hiddenAdj;
13444 if (myHiddenAdj > client.hiddenAdj) {
13445 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13446 myHiddenAdj = client.hiddenAdj;
13447 } else {
13448 myHiddenAdj = VISIBLE_APP_ADJ;
13449 }
13450 }
13451 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013452 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013453 if (adj > clientAdj) {
13454 adj = clientAdj > VISIBLE_APP_ADJ
13455 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013456 if (!client.hidden) {
13457 app.hidden = false;
13458 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013459 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013460 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13461 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013462 app.adjSource = cr.binding.client;
13463 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013464 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013465 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13466 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13467 schedGroup = Process.THREAD_GROUP_DEFAULT;
13468 }
13469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013470 }
13471 HistoryRecord a = cr.activity;
13472 //if (a != null) {
13473 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13474 //}
13475 if (a != null && adj > FOREGROUND_APP_ADJ &&
13476 (a.state == ActivityState.RESUMED
13477 || a.state == ActivityState.PAUSING)) {
13478 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013479 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013480 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013481 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013482 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13483 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013484 app.adjSource = a;
13485 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013486 }
13487 }
13488 }
13489 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013490
13491 // Finally, f this process has active services running in it, we
13492 // would like to avoid killing it unless it would prevent the current
13493 // application from running. By default we put the process in
13494 // with the rest of the background processes; as we scan through
13495 // its services we may bump it up from there.
13496 if (adj > hiddenAdj) {
13497 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013498 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013499 app.adjType = "bg-services";
13500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013501 }
13502
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013503 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13504 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013505 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013506 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13507 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013508 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13509 if (cpr.clients.size() != 0) {
13510 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13511 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13512 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013513 if (client == app) {
13514 // Being our own client is not interesting.
13515 continue;
13516 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013517 int myHiddenAdj = hiddenAdj;
13518 if (myHiddenAdj > client.hiddenAdj) {
13519 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13520 myHiddenAdj = client.hiddenAdj;
13521 } else {
13522 myHiddenAdj = FOREGROUND_APP_ADJ;
13523 }
13524 }
13525 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013526 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013527 if (adj > clientAdj) {
13528 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013529 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013530 if (!client.hidden) {
13531 app.hidden = false;
13532 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013533 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013534 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13535 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013536 app.adjSource = client;
13537 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013538 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013539 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13540 schedGroup = Process.THREAD_GROUP_DEFAULT;
13541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013542 }
13543 }
13544 // If the provider has external (non-framework) process
13545 // dependencies, ensure that its adjustment is at least
13546 // FOREGROUND_APP_ADJ.
13547 if (cpr.externals != 0) {
13548 if (adj > FOREGROUND_APP_ADJ) {
13549 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013550 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013551 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013552 app.adjType = "provider";
13553 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013554 }
13555 }
13556 }
13557 }
13558
13559 app.curRawAdj = adj;
13560
13561 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13562 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13563 if (adj > app.maxAdj) {
13564 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013565 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13566 schedGroup = Process.THREAD_GROUP_DEFAULT;
13567 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013568 }
13569
13570 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013571 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013573 return adj;
13574 }
13575
13576 /**
13577 * Ask a given process to GC right now.
13578 */
13579 final void performAppGcLocked(ProcessRecord app) {
13580 try {
13581 app.lastRequestedGc = SystemClock.uptimeMillis();
13582 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013583 if (app.reportLowMemory) {
13584 app.reportLowMemory = false;
13585 app.thread.scheduleLowMemory();
13586 } else {
13587 app.thread.processInBackground();
13588 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013589 }
13590 } catch (Exception e) {
13591 // whatever.
13592 }
13593 }
13594
13595 /**
13596 * Returns true if things are idle enough to perform GCs.
13597 */
13598 private final boolean canGcNow() {
13599 return mParallelBroadcasts.size() == 0
13600 && mOrderedBroadcasts.size() == 0
13601 && (mSleeping || (mResumedActivity != null &&
13602 mResumedActivity.idle));
13603 }
13604
13605 /**
13606 * Perform GCs on all processes that are waiting for it, but only
13607 * if things are idle.
13608 */
13609 final void performAppGcsLocked() {
13610 final int N = mProcessesToGc.size();
13611 if (N <= 0) {
13612 return;
13613 }
13614 if (canGcNow()) {
13615 while (mProcessesToGc.size() > 0) {
13616 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013617 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13618 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13619 <= SystemClock.uptimeMillis()) {
13620 // To avoid spamming the system, we will GC processes one
13621 // at a time, waiting a few seconds between each.
13622 performAppGcLocked(proc);
13623 scheduleAppGcsLocked();
13624 return;
13625 } else {
13626 // It hasn't been long enough since we last GCed this
13627 // process... put it in the list to wait for its time.
13628 addProcessToGcListLocked(proc);
13629 break;
13630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013631 }
13632 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013633
13634 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013635 }
13636 }
13637
13638 /**
13639 * If all looks good, perform GCs on all processes waiting for them.
13640 */
13641 final void performAppGcsIfAppropriateLocked() {
13642 if (canGcNow()) {
13643 performAppGcsLocked();
13644 return;
13645 }
13646 // Still not idle, wait some more.
13647 scheduleAppGcsLocked();
13648 }
13649
13650 /**
13651 * Schedule the execution of all pending app GCs.
13652 */
13653 final void scheduleAppGcsLocked() {
13654 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013655
13656 if (mProcessesToGc.size() > 0) {
13657 // Schedule a GC for the time to the next process.
13658 ProcessRecord proc = mProcessesToGc.get(0);
13659 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13660
13661 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13662 long now = SystemClock.uptimeMillis();
13663 if (when < (now+GC_TIMEOUT)) {
13664 when = now + GC_TIMEOUT;
13665 }
13666 mHandler.sendMessageAtTime(msg, when);
13667 }
13668 }
13669
13670 /**
13671 * Add a process to the array of processes waiting to be GCed. Keeps the
13672 * list in sorted order by the last GC time. The process can't already be
13673 * on the list.
13674 */
13675 final void addProcessToGcListLocked(ProcessRecord proc) {
13676 boolean added = false;
13677 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13678 if (mProcessesToGc.get(i).lastRequestedGc <
13679 proc.lastRequestedGc) {
13680 added = true;
13681 mProcessesToGc.add(i+1, proc);
13682 break;
13683 }
13684 }
13685 if (!added) {
13686 mProcessesToGc.add(0, proc);
13687 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013688 }
13689
13690 /**
13691 * Set up to ask a process to GC itself. This will either do it
13692 * immediately, or put it on the list of processes to gc the next
13693 * time things are idle.
13694 */
13695 final void scheduleAppGcLocked(ProcessRecord app) {
13696 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013697 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013698 return;
13699 }
13700 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013701 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013702 scheduleAppGcsLocked();
13703 }
13704 }
13705
13706 private final boolean updateOomAdjLocked(
13707 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13708 app.hiddenAdj = hiddenAdj;
13709
13710 if (app.thread == null) {
13711 return true;
13712 }
13713
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013714 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013715
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013716 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013717 if (app.curRawAdj != app.setRawAdj) {
13718 if (app.curRawAdj > FOREGROUND_APP_ADJ
13719 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13720 // If this app is transitioning from foreground to
13721 // non-foreground, have it do a gc.
13722 scheduleAppGcLocked(app);
13723 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13724 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13725 // Likewise do a gc when an app is moving in to the
13726 // background (such as a service stopping).
13727 scheduleAppGcLocked(app);
13728 }
13729 app.setRawAdj = app.curRawAdj;
13730 }
13731 if (adj != app.setAdj) {
13732 if (Process.setOomAdj(app.pid, adj)) {
13733 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13734 TAG, "Set app " + app.processName +
13735 " oom adj to " + adj);
13736 app.setAdj = adj;
13737 } else {
13738 return false;
13739 }
13740 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013741 if (app.setSchedGroup != app.curSchedGroup) {
13742 app.setSchedGroup = app.curSchedGroup;
13743 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13744 "Setting process group of " + app.processName
13745 + " to " + app.curSchedGroup);
13746 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013747 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013748 try {
13749 Process.setProcessGroup(app.pid, app.curSchedGroup);
13750 } catch (Exception e) {
13751 Log.w(TAG, "Failed setting process group of " + app.pid
13752 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013753 e.printStackTrace();
13754 } finally {
13755 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013756 }
13757 }
13758 if (false) {
13759 if (app.thread != null) {
13760 try {
13761 app.thread.setSchedulingGroup(app.curSchedGroup);
13762 } catch (RemoteException e) {
13763 }
13764 }
13765 }
13766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013767 }
13768
13769 return true;
13770 }
13771
13772 private final HistoryRecord resumedAppLocked() {
13773 HistoryRecord resumedActivity = mResumedActivity;
13774 if (resumedActivity == null || resumedActivity.app == null) {
13775 resumedActivity = mPausingActivity;
13776 if (resumedActivity == null || resumedActivity.app == null) {
13777 resumedActivity = topRunningActivityLocked(null);
13778 }
13779 }
13780 return resumedActivity;
13781 }
13782
13783 private final boolean updateOomAdjLocked(ProcessRecord app) {
13784 final HistoryRecord TOP_ACT = resumedAppLocked();
13785 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13786 int curAdj = app.curAdj;
13787 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13788 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13789
13790 mAdjSeq++;
13791
13792 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13793 if (res) {
13794 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13795 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13796 if (nowHidden != wasHidden) {
13797 // Changed to/from hidden state, so apps after it in the LRU
13798 // list may also be changed.
13799 updateOomAdjLocked();
13800 }
13801 }
13802 return res;
13803 }
13804
13805 private final boolean updateOomAdjLocked() {
13806 boolean didOomAdj = true;
13807 final HistoryRecord TOP_ACT = resumedAppLocked();
13808 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13809
13810 if (false) {
13811 RuntimeException e = new RuntimeException();
13812 e.fillInStackTrace();
13813 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13814 }
13815
13816 mAdjSeq++;
13817
13818 // First try updating the OOM adjustment for each of the
13819 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013820 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013821 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13822 while (i > 0) {
13823 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013824 ProcessRecord app = mLruProcesses.get(i);
13825 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013826 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013827 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013828 && app.curAdj == curHiddenAdj) {
13829 curHiddenAdj++;
13830 }
13831 } else {
13832 didOomAdj = false;
13833 }
13834 }
13835
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013836 // If we return false, we will fall back on killing processes to
13837 // have a fixed limit. Do this if a limit has been requested; else
13838 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013839 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13840 }
13841
13842 private final void trimApplications() {
13843 synchronized (this) {
13844 int i;
13845
13846 // First remove any unused application processes whose package
13847 // has been removed.
13848 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13849 final ProcessRecord app = mRemovedProcesses.get(i);
13850 if (app.activities.size() == 0
13851 && app.curReceiver == null && app.services.size() == 0) {
13852 Log.i(
13853 TAG, "Exiting empty application process "
13854 + app.processName + " ("
13855 + (app.thread != null ? app.thread.asBinder() : null)
13856 + ")\n");
13857 if (app.pid > 0 && app.pid != MY_PID) {
13858 Process.killProcess(app.pid);
13859 } else {
13860 try {
13861 app.thread.scheduleExit();
13862 } catch (Exception e) {
13863 // Ignore exceptions.
13864 }
13865 }
13866 cleanUpApplicationRecordLocked(app, false, -1);
13867 mRemovedProcesses.remove(i);
13868
13869 if (app.persistent) {
13870 if (app.persistent) {
13871 addAppLocked(app.info);
13872 }
13873 }
13874 }
13875 }
13876
13877 // Now try updating the OOM adjustment for each of the
13878 // application processes based on their current state.
13879 // If the setOomAdj() API is not supported, then go with our
13880 // back-up plan...
13881 if (!updateOomAdjLocked()) {
13882
13883 // Count how many processes are running services.
13884 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013885 for (i=mLruProcesses.size()-1; i>=0; i--) {
13886 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013887
13888 if (app.persistent || app.services.size() != 0
13889 || app.curReceiver != null
13890 || app.persistentActivities > 0) {
13891 // Don't count processes holding services against our
13892 // maximum process count.
13893 if (localLOGV) Log.v(
13894 TAG, "Not trimming app " + app + " with services: "
13895 + app.services);
13896 numServiceProcs++;
13897 }
13898 }
13899
13900 int curMaxProcs = mProcessLimit;
13901 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13902 if (mAlwaysFinishActivities) {
13903 curMaxProcs = 1;
13904 }
13905 curMaxProcs += numServiceProcs;
13906
13907 // Quit as many processes as we can to get down to the desired
13908 // process count. First remove any processes that no longer
13909 // have activites running in them.
13910 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013911 i<mLruProcesses.size()
13912 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013913 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013914 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013915 // Quit an application only if it is not currently
13916 // running any activities.
13917 if (!app.persistent && app.activities.size() == 0
13918 && app.curReceiver == null && app.services.size() == 0) {
13919 Log.i(
13920 TAG, "Exiting empty application process "
13921 + app.processName + " ("
13922 + (app.thread != null ? app.thread.asBinder() : null)
13923 + ")\n");
13924 if (app.pid > 0 && app.pid != MY_PID) {
13925 Process.killProcess(app.pid);
13926 } else {
13927 try {
13928 app.thread.scheduleExit();
13929 } catch (Exception e) {
13930 // Ignore exceptions.
13931 }
13932 }
13933 // todo: For now we assume the application is not buggy
13934 // or evil, and will quit as a result of our request.
13935 // Eventually we need to drive this off of the death
13936 // notification, and kill the process if it takes too long.
13937 cleanUpApplicationRecordLocked(app, false, i);
13938 i--;
13939 }
13940 }
13941
13942 // If we still have too many processes, now from the least
13943 // recently used process we start finishing activities.
13944 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013945 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013946 " of " + curMaxProcs + " processes");
13947 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013948 i<mLruProcesses.size()
13949 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013950 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013951 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013952 // Quit the application only if we have a state saved for
13953 // all of its activities.
13954 boolean canQuit = !app.persistent && app.curReceiver == null
13955 && app.services.size() == 0
13956 && app.persistentActivities == 0;
13957 int NUMA = app.activities.size();
13958 int j;
13959 if (Config.LOGV) Log.v(
13960 TAG, "Looking to quit " + app.processName);
13961 for (j=0; j<NUMA && canQuit; j++) {
13962 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13963 if (Config.LOGV) Log.v(
13964 TAG, " " + r.intent.getComponent().flattenToShortString()
13965 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13966 canQuit = (r.haveState || !r.stateNotNeeded)
13967 && !r.visible && r.stopped;
13968 }
13969 if (canQuit) {
13970 // Finish all of the activities, and then the app itself.
13971 for (j=0; j<NUMA; j++) {
13972 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13973 if (!r.finishing) {
13974 destroyActivityLocked(r, false);
13975 }
13976 r.resultTo = null;
13977 }
13978 Log.i(TAG, "Exiting application process "
13979 + app.processName + " ("
13980 + (app.thread != null ? app.thread.asBinder() : null)
13981 + ")\n");
13982 if (app.pid > 0 && app.pid != MY_PID) {
13983 Process.killProcess(app.pid);
13984 } else {
13985 try {
13986 app.thread.scheduleExit();
13987 } catch (Exception e) {
13988 // Ignore exceptions.
13989 }
13990 }
13991 // todo: For now we assume the application is not buggy
13992 // or evil, and will quit as a result of our request.
13993 // Eventually we need to drive this off of the death
13994 // notification, and kill the process if it takes too long.
13995 cleanUpApplicationRecordLocked(app, false, i);
13996 i--;
13997 //dump();
13998 }
13999 }
14000
14001 }
14002
14003 int curMaxActivities = MAX_ACTIVITIES;
14004 if (mAlwaysFinishActivities) {
14005 curMaxActivities = 1;
14006 }
14007
14008 // Finally, if there are too many activities now running, try to
14009 // finish as many as we can to get back down to the limit.
14010 for ( i=0;
14011 i<mLRUActivities.size()
14012 && mLRUActivities.size() > curMaxActivities;
14013 i++) {
14014 final HistoryRecord r
14015 = (HistoryRecord)mLRUActivities.get(i);
14016
14017 // We can finish this one if we have its icicle saved and
14018 // it is not persistent.
14019 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14020 && r.stopped && !r.persistent && !r.finishing) {
14021 final int origSize = mLRUActivities.size();
14022 destroyActivityLocked(r, true);
14023
14024 // This will remove it from the LRU list, so keep
14025 // our index at the same value. Note that this check to
14026 // see if the size changes is just paranoia -- if
14027 // something unexpected happens, we don't want to end up
14028 // in an infinite loop.
14029 if (origSize > mLRUActivities.size()) {
14030 i--;
14031 }
14032 }
14033 }
14034 }
14035 }
14036
14037 /** This method sends the specified signal to each of the persistent apps */
14038 public void signalPersistentProcesses(int sig) throws RemoteException {
14039 if (sig != Process.SIGNAL_USR1) {
14040 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14041 }
14042
14043 synchronized (this) {
14044 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14045 != PackageManager.PERMISSION_GRANTED) {
14046 throw new SecurityException("Requires permission "
14047 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14048 }
14049
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014050 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14051 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014052 if (r.thread != null && r.persistent) {
14053 Process.sendSignal(r.pid, sig);
14054 }
14055 }
14056 }
14057 }
14058
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014059 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014060 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014061
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014062 try {
14063 synchronized (this) {
14064 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14065 // its own permission.
14066 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14067 != PackageManager.PERMISSION_GRANTED) {
14068 throw new SecurityException("Requires permission "
14069 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014070 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014071
14072 if (start && fd == null) {
14073 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014074 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014075
14076 ProcessRecord proc = null;
14077 try {
14078 int pid = Integer.parseInt(process);
14079 synchronized (mPidsSelfLocked) {
14080 proc = mPidsSelfLocked.get(pid);
14081 }
14082 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014083 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014084
14085 if (proc == null) {
14086 HashMap<String, SparseArray<ProcessRecord>> all
14087 = mProcessNames.getMap();
14088 SparseArray<ProcessRecord> procs = all.get(process);
14089 if (procs != null && procs.size() > 0) {
14090 proc = procs.valueAt(0);
14091 }
14092 }
14093
14094 if (proc == null || proc.thread == null) {
14095 throw new IllegalArgumentException("Unknown process: " + process);
14096 }
14097
14098 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14099 if (isSecure) {
14100 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14101 throw new SecurityException("Process not debuggable: " + proc);
14102 }
14103 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014104
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014105 proc.thread.profilerControl(start, path, fd);
14106 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014107 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014108 }
14109 } catch (RemoteException e) {
14110 throw new IllegalStateException("Process disappeared");
14111 } finally {
14112 if (fd != null) {
14113 try {
14114 fd.close();
14115 } catch (IOException e) {
14116 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014117 }
14118 }
14119 }
14120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014121 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14122 public void monitor() {
14123 synchronized (this) { }
14124 }
14125}