blob: 5b50a3ac7390a89164824bccea89484a117425b4 [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.
Doug Zongker2bec3d42009-12-04 12:52:44 -08004613 EventLog.writeEvent(EventLogTags.ANR, app.pid, app.processName, annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004614
Dan Egnor42471dd2010-01-07 17:25:22 -08004615 // Dump thread traces as quickly as we can, starting with "interesting" processes.
4616 ArrayList<Integer> pids = new ArrayList<Integer>(20);
4617 pids.add(app.pid);
4618
4619 int parentPid = app.pid;
4620 if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
4621 if (parentPid != app.pid) pids.add(parentPid);
4622
4623 if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
4624
4625 for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
4626 ProcessRecord r = mLruProcesses.get(i);
4627 if (r != null && r.thread != null) {
4628 int pid = r.pid;
4629 if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004630 }
4631 }
4632
Dan Egnor42471dd2010-01-07 17:25:22 -08004633 File tracesFile = dumpStackTraces(pids);
4634
4635 // Log the ANR to the main log.
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004636 StringBuilder info = mStringBuilder;
4637 info.setLength(0);
Dan Egnor42471dd2010-01-07 17:25:22 -08004638 info.append("ANR in ").append(app.processName);
4639 if (activity != null && activity.shortComponentName != null) {
4640 info.append(" (").append(activity.shortComponentName).append(")");
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004641 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004642 if (annotation != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004643 info.append("\nReason: ").append(annotation).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004644 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004645 if (parent != null && parent != activity) {
4646 info.append("\nParent: ").append(parent.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004648
Dan Egnor42471dd2010-01-07 17:25:22 -08004649 String cpuInfo = null;
4650 if (MONITOR_CPU_USAGE) {
4651 updateCpuStatsNow();
4652 synchronized (mProcessStatsThread) { cpuInfo = mProcessStats.printCurrentState(); }
4653 info.append(cpuInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004654 }
4655
Dan Egnor42471dd2010-01-07 17:25:22 -08004656 Log.e(TAG, info.toString());
4657 if (tracesFile == null) {
4658 // There is no trace file, so dump (only) the alleged culprit's threads to the log
4659 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4660 }
4661
4662 addErrorToDropBox("anr", app, activity, parent, annotation, cpuInfo, tracesFile, null);
4663
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004664 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004665 try {
Dan Egnor42471dd2010-01-07 17:25:22 -08004666 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
4667 int res = mController.appNotResponding(app.processName, app.pid, info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004668 if (res != 0) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004669 if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
4670 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004671 }
4672 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004673 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004674 }
4675 }
4676
Dan Egnor42471dd2010-01-07 17:25:22 -08004677 // Unless configured otherwise, swallow ANRs in background processes & kill the process.
4678 boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
4679 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
4680 if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
4681 Process.killProcess(app.pid);
4682 return;
4683 }
4684
4685 // Set the app's notResponding state, and look up the errorReportReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004686 makeAppNotRespondingLocked(app,
4687 activity != null ? activity.shortComponentName : null,
4688 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004689 info.toString());
Dan Egnor42471dd2010-01-07 17:25:22 -08004690
4691 // Bring up the infamous App Not Responding dialog
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004692 Message msg = Message.obtain();
4693 HashMap map = new HashMap();
4694 msg.what = SHOW_NOT_RESPONDING_MSG;
4695 msg.obj = map;
4696 map.put("app", app);
4697 if (activity != null) {
4698 map.put("activity", activity);
4699 }
4700
4701 mHandler.sendMessage(msg);
4702 return;
4703 }
4704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004705 private final void decPersistentCountLocked(ProcessRecord app)
4706 {
4707 app.persistentActivities--;
4708 if (app.persistentActivities > 0) {
4709 // Still more of 'em...
4710 return;
4711 }
4712 if (app.persistent) {
4713 // Ah, but the application itself is persistent. Whatever!
4714 return;
4715 }
4716
4717 // App is no longer persistent... make sure it and the ones
4718 // following it in the LRU list have the correc oom_adj.
4719 updateOomAdjLocked();
4720 }
4721
4722 public void setPersistent(IBinder token, boolean isPersistent) {
4723 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4724 != PackageManager.PERMISSION_GRANTED) {
4725 String msg = "Permission Denial: setPersistent() from pid="
4726 + Binder.getCallingPid()
4727 + ", uid=" + Binder.getCallingUid()
4728 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4729 Log.w(TAG, msg);
4730 throw new SecurityException(msg);
4731 }
4732
4733 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004734 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004735 if (index < 0) {
4736 return;
4737 }
4738 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4739 ProcessRecord app = r.app;
4740
4741 if (localLOGV) Log.v(
4742 TAG, "Setting persistence " + isPersistent + ": " + r);
4743
4744 if (isPersistent) {
4745 if (r.persistent) {
4746 // Okay okay, I heard you already!
4747 if (localLOGV) Log.v(TAG, "Already persistent!");
4748 return;
4749 }
4750 r.persistent = true;
4751 app.persistentActivities++;
4752 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4753 if (app.persistentActivities > 1) {
4754 // We aren't the first...
4755 if (localLOGV) Log.v(TAG, "Not the first!");
4756 return;
4757 }
4758 if (app.persistent) {
4759 // This would be redundant.
4760 if (localLOGV) Log.v(TAG, "App is persistent!");
4761 return;
4762 }
4763
4764 // App is now persistent... make sure it and the ones
4765 // following it now have the correct oom_adj.
4766 final long origId = Binder.clearCallingIdentity();
4767 updateOomAdjLocked();
4768 Binder.restoreCallingIdentity(origId);
4769
4770 } else {
4771 if (!r.persistent) {
4772 // Okay okay, I heard you already!
4773 return;
4774 }
4775 r.persistent = false;
4776 final long origId = Binder.clearCallingIdentity();
4777 decPersistentCountLocked(app);
4778 Binder.restoreCallingIdentity(origId);
4779
4780 }
4781 }
4782 }
4783
4784 public boolean clearApplicationUserData(final String packageName,
4785 final IPackageDataObserver observer) {
4786 int uid = Binder.getCallingUid();
4787 int pid = Binder.getCallingPid();
4788 long callingId = Binder.clearCallingIdentity();
4789 try {
4790 IPackageManager pm = ActivityThread.getPackageManager();
4791 int pkgUid = -1;
4792 synchronized(this) {
4793 try {
4794 pkgUid = pm.getPackageUid(packageName);
4795 } catch (RemoteException e) {
4796 }
4797 if (pkgUid == -1) {
4798 Log.w(TAG, "Invalid packageName:" + packageName);
4799 return false;
4800 }
4801 if (uid == pkgUid || checkComponentPermission(
4802 android.Manifest.permission.CLEAR_APP_USER_DATA,
4803 pid, uid, -1)
4804 == PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08004805 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004806 } else {
4807 throw new SecurityException(pid+" does not have permission:"+
4808 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4809 "for process:"+packageName);
4810 }
4811 }
4812
4813 try {
4814 //clear application user data
4815 pm.clearApplicationUserData(packageName, observer);
4816 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4817 Uri.fromParts("package", packageName, null));
4818 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4819 broadcastIntentLocked(null, null, intent,
4820 null, null, 0, null, null, null,
4821 false, false, MY_PID, Process.SYSTEM_UID);
4822 } catch (RemoteException e) {
4823 }
4824 } finally {
4825 Binder.restoreCallingIdentity(callingId);
4826 }
4827 return true;
4828 }
4829
Dianne Hackborn03abb812010-01-04 18:43:19 -08004830 public void killBackgroundProcesses(final String packageName) {
4831 if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
4832 != PackageManager.PERMISSION_GRANTED &&
4833 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4834 != PackageManager.PERMISSION_GRANTED) {
4835 String msg = "Permission Denial: killBackgroundProcesses() from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004836 + Binder.getCallingPid()
4837 + ", uid=" + Binder.getCallingUid()
Dianne Hackborn03abb812010-01-04 18:43:19 -08004838 + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004839 Log.w(TAG, msg);
4840 throw new SecurityException(msg);
4841 }
4842
4843 long callingId = Binder.clearCallingIdentity();
4844 try {
4845 IPackageManager pm = ActivityThread.getPackageManager();
4846 int pkgUid = -1;
4847 synchronized(this) {
4848 try {
4849 pkgUid = pm.getPackageUid(packageName);
4850 } catch (RemoteException e) {
4851 }
4852 if (pkgUid == -1) {
4853 Log.w(TAG, "Invalid packageName: " + packageName);
4854 return;
4855 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004856 killPackageProcessesLocked(packageName, pkgUid,
4857 SECONDARY_SERVER_ADJ, false);
4858 }
4859 } finally {
4860 Binder.restoreCallingIdentity(callingId);
4861 }
4862 }
4863
4864 public void forceStopPackage(final String packageName) {
4865 if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
4866 != PackageManager.PERMISSION_GRANTED) {
4867 String msg = "Permission Denial: forceStopPackage() from pid="
4868 + Binder.getCallingPid()
4869 + ", uid=" + Binder.getCallingUid()
4870 + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
4871 Log.w(TAG, msg);
4872 throw new SecurityException(msg);
4873 }
4874
4875 long callingId = Binder.clearCallingIdentity();
4876 try {
4877 IPackageManager pm = ActivityThread.getPackageManager();
4878 int pkgUid = -1;
4879 synchronized(this) {
4880 try {
4881 pkgUid = pm.getPackageUid(packageName);
4882 } catch (RemoteException e) {
4883 }
4884 if (pkgUid == -1) {
4885 Log.w(TAG, "Invalid packageName: " + packageName);
4886 return;
4887 }
4888 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004889 }
4890 } finally {
4891 Binder.restoreCallingIdentity(callingId);
4892 }
4893 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004894
4895 /*
4896 * The pkg name and uid have to be specified.
4897 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4898 */
4899 public void killApplicationWithUid(String pkg, int uid) {
4900 if (pkg == null) {
4901 return;
4902 }
4903 // Make sure the uid is valid.
4904 if (uid < 0) {
4905 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4906 return;
4907 }
4908 int callerUid = Binder.getCallingUid();
4909 // Only the system server can kill an application
4910 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004911 // Post an aysnc message to kill the application
4912 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4913 msg.arg1 = uid;
4914 msg.arg2 = 0;
4915 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004916 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004917 } else {
4918 throw new SecurityException(callerUid + " cannot kill pkg: " +
4919 pkg);
4920 }
4921 }
4922
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004923 public void closeSystemDialogs(String reason) {
4924 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4925 if (reason != null) {
4926 intent.putExtra("reason", reason);
4927 }
4928
4929 final int uid = Binder.getCallingUid();
4930 final long origId = Binder.clearCallingIdentity();
4931 synchronized (this) {
4932 int i = mWatchers.beginBroadcast();
4933 while (i > 0) {
4934 i--;
4935 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4936 if (w != null) {
4937 try {
4938 w.closingSystemDialogs(reason);
4939 } catch (RemoteException e) {
4940 }
4941 }
4942 }
4943 mWatchers.finishBroadcast();
4944
Dianne Hackbornffa42482009-09-23 22:20:11 -07004945 mWindowManager.closeSystemDialogs(reason);
4946
4947 for (i=mHistory.size()-1; i>=0; i--) {
4948 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4949 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4950 finishActivityLocked(r, i,
4951 Activity.RESULT_CANCELED, null, "close-sys");
4952 }
4953 }
4954
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004955 broadcastIntentLocked(null, null, intent, null,
4956 null, 0, null, null, null, false, false, -1, uid);
4957 }
4958 Binder.restoreCallingIdentity(origId);
4959 }
4960
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004961 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004962 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004963 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4964 for (int i=pids.length-1; i>=0; i--) {
4965 infos[i] = new Debug.MemoryInfo();
4966 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004967 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004968 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004969 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004970
4971 public void killApplicationProcess(String processName, int uid) {
4972 if (processName == null) {
4973 return;
4974 }
4975
4976 int callerUid = Binder.getCallingUid();
4977 // Only the system server can kill an application
4978 if (callerUid == Process.SYSTEM_UID) {
4979 synchronized (this) {
4980 ProcessRecord app = getProcessRecordLocked(processName, uid);
4981 if (app != null) {
4982 try {
4983 app.thread.scheduleSuicide();
4984 } catch (RemoteException e) {
4985 // If the other end already died, then our work here is done.
4986 }
4987 } else {
4988 Log.w(TAG, "Process/uid not found attempting kill of "
4989 + processName + " / " + uid);
4990 }
4991 }
4992 } else {
4993 throw new SecurityException(callerUid + " cannot kill app process: " +
4994 processName);
4995 }
4996 }
4997
Dianne Hackborn03abb812010-01-04 18:43:19 -08004998 private void forceStopPackageLocked(final String packageName, int uid) {
4999 forceStopPackageLocked(packageName, uid, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005000 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5001 Uri.fromParts("package", packageName, null));
5002 intent.putExtra(Intent.EXTRA_UID, uid);
5003 broadcastIntentLocked(null, null, intent,
5004 null, null, 0, null, null, null,
5005 false, false, MY_PID, Process.SYSTEM_UID);
5006 }
5007
Dianne Hackborn03abb812010-01-04 18:43:19 -08005008 private final void killPackageProcessesLocked(String packageName, int uid,
5009 int minOomAdj, boolean callerWillRestart) {
5010 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005011
Dianne Hackborn03abb812010-01-04 18:43:19 -08005012 // Remove all processes this package may have touched: all with the
5013 // same UID (except for the system or root user), and all whose name
5014 // matches the package name.
5015 final String procNamePrefix = packageName + ":";
5016 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5017 final int NA = apps.size();
5018 for (int ia=0; ia<NA; ia++) {
5019 ProcessRecord app = apps.valueAt(ia);
5020 if (app.removed) {
5021 procs.add(app);
5022 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5023 || app.processName.equals(packageName)
5024 || app.processName.startsWith(procNamePrefix)) {
5025 if (app.setAdj >= minOomAdj) {
5026 app.removed = true;
5027 procs.add(app);
5028 }
5029 }
5030 }
5031 }
5032
5033 int N = procs.size();
5034 for (int i=0; i<N; i++) {
5035 removeProcessLocked(procs.get(i), callerWillRestart);
5036 }
5037 }
5038
5039 private final void forceStopPackageLocked(String name, int uid,
5040 boolean callerWillRestart) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005041 int i, N;
5042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005043 if (uid < 0) {
5044 try {
5045 uid = ActivityThread.getPackageManager().getPackageUid(name);
5046 } catch (RemoteException e) {
5047 }
5048 }
5049
Dianne Hackborn03abb812010-01-04 18:43:19 -08005050 Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
5051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005052 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5053 while (badApps.hasNext()) {
5054 SparseArray<Long> ba = badApps.next();
5055 if (ba.get(uid) != null) {
5056 badApps.remove();
5057 }
5058 }
5059
Dianne Hackborn03abb812010-01-04 18:43:19 -08005060 killPackageProcessesLocked(name, uid, -100, callerWillRestart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005061
5062 for (i=mHistory.size()-1; i>=0; i--) {
5063 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5064 if (r.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005065 Log.i(TAG, " Force finishing activity " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005066 if (r.app != null) {
5067 r.app.removed = true;
5068 }
5069 r.app = null;
5070 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5071 }
5072 }
5073
5074 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5075 for (ServiceRecord service : mServices.values()) {
5076 if (service.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005077 Log.i(TAG, " Force stopping service " + service);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005078 if (service.app != null) {
5079 service.app.removed = true;
5080 }
5081 service.app = null;
5082 services.add(service);
5083 }
5084 }
5085
5086 N = services.size();
5087 for (i=0; i<N; i++) {
5088 bringDownServiceLocked(services.get(i), true);
5089 }
5090
5091 resumeTopActivityLocked(null);
5092 }
5093
5094 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5095 final String name = app.processName;
5096 final int uid = app.info.uid;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005097 if (DEBUG_PROCESSES) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005098 TAG, "Force removing process " + app + " (" + name
5099 + "/" + uid + ")");
5100
5101 mProcessNames.remove(name, uid);
5102 boolean needRestart = false;
5103 if (app.pid > 0 && app.pid != MY_PID) {
5104 int pid = app.pid;
5105 synchronized (mPidsSelfLocked) {
5106 mPidsSelfLocked.remove(pid);
5107 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5108 }
5109 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005110 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005111 Process.killProcess(pid);
5112
5113 if (app.persistent) {
5114 if (!callerWillRestart) {
5115 addAppLocked(app.info);
5116 } else {
5117 needRestart = true;
5118 }
5119 }
5120 } else {
5121 mRemovedProcesses.add(app);
5122 }
5123
5124 return needRestart;
5125 }
5126
5127 private final void processStartTimedOutLocked(ProcessRecord app) {
5128 final int pid = app.pid;
5129 boolean gone = false;
5130 synchronized (mPidsSelfLocked) {
5131 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5132 if (knownApp != null && knownApp.thread == null) {
5133 mPidsSelfLocked.remove(pid);
5134 gone = true;
5135 }
5136 }
5137
5138 if (gone) {
5139 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005140 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005141 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005142 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005143 // Take care of any launching providers waiting for this process.
5144 checkAppInLaunchingProvidersLocked(app, true);
5145 // Take care of any services that are waiting for the process.
5146 for (int i=0; i<mPendingServices.size(); i++) {
5147 ServiceRecord sr = mPendingServices.get(i);
5148 if (app.info.uid == sr.appInfo.uid
5149 && app.processName.equals(sr.processName)) {
5150 Log.w(TAG, "Forcing bringing down service: " + sr);
5151 mPendingServices.remove(i);
5152 i--;
5153 bringDownServiceLocked(sr, true);
5154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005155 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005156 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005157 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5158 Log.w(TAG, "Unattached app died before backup, skipping");
5159 try {
5160 IBackupManager bm = IBackupManager.Stub.asInterface(
5161 ServiceManager.getService(Context.BACKUP_SERVICE));
5162 bm.agentDisconnected(app.info.packageName);
5163 } catch (RemoteException e) {
5164 // Can't happen; the backup manager is local
5165 }
5166 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005167 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5168 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5169 mPendingBroadcast = null;
5170 scheduleBroadcastsLocked();
5171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005172 } else {
5173 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5174 }
5175 }
5176
5177 private final boolean attachApplicationLocked(IApplicationThread thread,
5178 int pid) {
5179
5180 // Find the application record that is being attached... either via
5181 // the pid if we are running in multiple processes, or just pull the
5182 // next app record if we are emulating process with anonymous threads.
5183 ProcessRecord app;
5184 if (pid != MY_PID && pid >= 0) {
5185 synchronized (mPidsSelfLocked) {
5186 app = mPidsSelfLocked.get(pid);
5187 }
5188 } else if (mStartingProcesses.size() > 0) {
5189 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005190 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005191 } else {
5192 app = null;
5193 }
5194
5195 if (app == null) {
5196 Log.w(TAG, "No pending application record for pid " + pid
5197 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005198 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005199 if (pid > 0 && pid != MY_PID) {
5200 Process.killProcess(pid);
5201 } else {
5202 try {
5203 thread.scheduleExit();
5204 } catch (Exception e) {
5205 // Ignore exceptions.
5206 }
5207 }
5208 return false;
5209 }
5210
5211 // If this application record is still attached to a previous
5212 // process, clean it up now.
5213 if (app.thread != null) {
5214 handleAppDiedLocked(app, true);
5215 }
5216
5217 // Tell the process all about itself.
5218
5219 if (localLOGV) Log.v(
5220 TAG, "Binding process pid " + pid + " to record " + app);
5221
5222 String processName = app.processName;
5223 try {
5224 thread.asBinder().linkToDeath(new AppDeathRecipient(
5225 app, pid, thread), 0);
5226 } catch (RemoteException e) {
5227 app.resetPackageList();
5228 startProcessLocked(app, "link fail", processName);
5229 return false;
5230 }
5231
Doug Zongker2bec3d42009-12-04 12:52:44 -08005232 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233
5234 app.thread = thread;
5235 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005236 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5237 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005238 app.forcingToForeground = null;
5239 app.foregroundServices = false;
5240 app.debugging = false;
5241
5242 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5243
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005244 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5245 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005246
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005247 if (!normalMode) {
5248 Log.i(TAG, "Launching preboot mode app: " + app);
5249 }
5250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005251 if (localLOGV) Log.v(
5252 TAG, "New app record " + app
5253 + " thread=" + thread.asBinder() + " pid=" + pid);
5254 try {
5255 int testMode = IApplicationThread.DEBUG_OFF;
5256 if (mDebugApp != null && mDebugApp.equals(processName)) {
5257 testMode = mWaitForDebugger
5258 ? IApplicationThread.DEBUG_WAIT
5259 : IApplicationThread.DEBUG_ON;
5260 app.debugging = true;
5261 if (mDebugTransient) {
5262 mDebugApp = mOrigDebugApp;
5263 mWaitForDebugger = mOrigWaitForDebugger;
5264 }
5265 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005266
Christopher Tate181fafa2009-05-14 11:12:14 -07005267 // If the app is being launched for restore or full backup, set it up specially
5268 boolean isRestrictedBackupMode = false;
5269 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5270 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5271 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5272 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005273
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005274 ensurePackageDexOpt(app.instrumentationInfo != null
5275 ? app.instrumentationInfo.packageName
5276 : app.info.packageName);
5277 if (app.instrumentationClass != null) {
5278 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005279 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005280 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5281 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005282 thread.bindApplication(processName, app.instrumentationInfo != null
5283 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005284 app.instrumentationClass, app.instrumentationProfileFile,
5285 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005286 isRestrictedBackupMode || !normalMode,
5287 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005288 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005289 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005290 } catch (Exception e) {
5291 // todo: Yikes! What should we do? For now we will try to
5292 // start another process, but that could easily get us in
5293 // an infinite loop of restarting processes...
5294 Log.w(TAG, "Exception thrown during bind!", e);
5295
5296 app.resetPackageList();
5297 startProcessLocked(app, "bind fail", processName);
5298 return false;
5299 }
5300
5301 // Remove this record from the list of starting applications.
5302 mPersistentStartingProcesses.remove(app);
5303 mProcessesOnHold.remove(app);
5304
5305 boolean badApp = false;
5306 boolean didSomething = false;
5307
5308 // See if the top visible activity is waiting to run in this process...
5309 HistoryRecord hr = topRunningActivityLocked(null);
5310 if (hr != null) {
5311 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5312 && processName.equals(hr.processName)) {
5313 try {
5314 if (realStartActivityLocked(hr, app, true, true)) {
5315 didSomething = true;
5316 }
5317 } catch (Exception e) {
5318 Log.w(TAG, "Exception in new application when starting activity "
5319 + hr.intent.getComponent().flattenToShortString(), e);
5320 badApp = true;
5321 }
5322 } else {
5323 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5324 }
5325 }
5326
5327 // Find any services that should be running in this process...
5328 if (!badApp && mPendingServices.size() > 0) {
5329 ServiceRecord sr = null;
5330 try {
5331 for (int i=0; i<mPendingServices.size(); i++) {
5332 sr = mPendingServices.get(i);
5333 if (app.info.uid != sr.appInfo.uid
5334 || !processName.equals(sr.processName)) {
5335 continue;
5336 }
5337
5338 mPendingServices.remove(i);
5339 i--;
5340 realStartServiceLocked(sr, app);
5341 didSomething = true;
5342 }
5343 } catch (Exception e) {
5344 Log.w(TAG, "Exception in new application when starting service "
5345 + sr.shortName, e);
5346 badApp = true;
5347 }
5348 }
5349
5350 // Check if the next broadcast receiver is in this process...
5351 BroadcastRecord br = mPendingBroadcast;
5352 if (!badApp && br != null && br.curApp == app) {
5353 try {
5354 mPendingBroadcast = null;
5355 processCurBroadcastLocked(br, app);
5356 didSomething = true;
5357 } catch (Exception e) {
5358 Log.w(TAG, "Exception in new application when starting receiver "
5359 + br.curComponent.flattenToShortString(), e);
5360 badApp = true;
5361 logBroadcastReceiverDiscard(br);
5362 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5363 br.resultExtras, br.resultAbort, true);
5364 scheduleBroadcastsLocked();
5365 }
5366 }
5367
Christopher Tate181fafa2009-05-14 11:12:14 -07005368 // Check whether the next backup agent is in this process...
5369 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5370 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005371 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005372 try {
5373 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5374 } catch (Exception e) {
5375 Log.w(TAG, "Exception scheduling backup agent creation: ");
5376 e.printStackTrace();
5377 }
5378 }
5379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005380 if (badApp) {
5381 // todo: Also need to kill application to deal with all
5382 // kinds of exceptions.
5383 handleAppDiedLocked(app, false);
5384 return false;
5385 }
5386
5387 if (!didSomething) {
5388 updateOomAdjLocked();
5389 }
5390
5391 return true;
5392 }
5393
5394 public final void attachApplication(IApplicationThread thread) {
5395 synchronized (this) {
5396 int callingPid = Binder.getCallingPid();
5397 final long origId = Binder.clearCallingIdentity();
5398 attachApplicationLocked(thread, callingPid);
5399 Binder.restoreCallingIdentity(origId);
5400 }
5401 }
5402
Dianne Hackborne88846e2009-09-30 21:34:25 -07005403 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005404 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005405 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005406 Binder.restoreCallingIdentity(origId);
5407 }
5408
5409 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5410 boolean remove) {
5411 int N = mStoppingActivities.size();
5412 if (N <= 0) return null;
5413
5414 ArrayList<HistoryRecord> stops = null;
5415
5416 final boolean nowVisible = mResumedActivity != null
5417 && mResumedActivity.nowVisible
5418 && !mResumedActivity.waitingVisible;
5419 for (int i=0; i<N; i++) {
5420 HistoryRecord s = mStoppingActivities.get(i);
5421 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5422 + nowVisible + " waitingVisible=" + s.waitingVisible
5423 + " finishing=" + s.finishing);
5424 if (s.waitingVisible && nowVisible) {
5425 mWaitingVisibleActivities.remove(s);
5426 s.waitingVisible = false;
5427 if (s.finishing) {
5428 // If this activity is finishing, it is sitting on top of
5429 // everyone else but we now know it is no longer needed...
5430 // so get rid of it. Otherwise, we need to go through the
5431 // normal flow and hide it once we determine that it is
5432 // hidden by the activities in front of it.
5433 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5434 mWindowManager.setAppVisibility(s, false);
5435 }
5436 }
5437 if (!s.waitingVisible && remove) {
5438 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5439 if (stops == null) {
5440 stops = new ArrayList<HistoryRecord>();
5441 }
5442 stops.add(s);
5443 mStoppingActivities.remove(i);
5444 N--;
5445 i--;
5446 }
5447 }
5448
5449 return stops;
5450 }
5451
5452 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005453 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005454 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005455 mWindowManager.enableScreenAfterBoot();
5456 }
5457
Dianne Hackborne88846e2009-09-30 21:34:25 -07005458 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5459 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005460 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5461
5462 ArrayList<HistoryRecord> stops = null;
5463 ArrayList<HistoryRecord> finishes = null;
5464 ArrayList<HistoryRecord> thumbnails = null;
5465 int NS = 0;
5466 int NF = 0;
5467 int NT = 0;
5468 IApplicationThread sendThumbnail = null;
5469 boolean booting = false;
5470 boolean enableScreen = false;
5471
5472 synchronized (this) {
5473 if (token != null) {
5474 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5475 }
5476
5477 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005478 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005479 if (index >= 0) {
5480 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5481
Dianne Hackborne88846e2009-09-30 21:34:25 -07005482 // This is a hack to semi-deal with a race condition
5483 // in the client where it can be constructed with a
5484 // newer configuration from when we asked it to launch.
5485 // We'll update with whatever configuration it now says
5486 // it used to launch.
5487 if (config != null) {
5488 r.configuration = config;
5489 }
5490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005491 // No longer need to keep the device awake.
5492 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5493 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5494 mLaunchingActivity.release();
5495 }
5496
5497 // We are now idle. If someone is waiting for a thumbnail from
5498 // us, we can now deliver.
5499 r.idle = true;
5500 scheduleAppGcsLocked();
5501 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5502 sendThumbnail = r.app.thread;
5503 r.thumbnailNeeded = false;
5504 }
5505
5506 // If this activity is fullscreen, set up to hide those under it.
5507
5508 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5509 ensureActivitiesVisibleLocked(null, 0);
5510
5511 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5512 if (!mBooted && !fromTimeout) {
5513 mBooted = true;
5514 enableScreen = true;
5515 }
5516 }
5517
5518 // Atomically retrieve all of the other things to do.
5519 stops = processStoppingActivitiesLocked(true);
5520 NS = stops != null ? stops.size() : 0;
5521 if ((NF=mFinishingActivities.size()) > 0) {
5522 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5523 mFinishingActivities.clear();
5524 }
5525 if ((NT=mCancelledThumbnails.size()) > 0) {
5526 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5527 mCancelledThumbnails.clear();
5528 }
5529
5530 booting = mBooting;
5531 mBooting = false;
5532 }
5533
5534 int i;
5535
5536 // Send thumbnail if requested.
5537 if (sendThumbnail != null) {
5538 try {
5539 sendThumbnail.requestThumbnail(token);
5540 } catch (Exception e) {
5541 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5542 sendPendingThumbnail(null, token, null, null, true);
5543 }
5544 }
5545
5546 // Stop any activities that are scheduled to do so but have been
5547 // waiting for the next one to start.
5548 for (i=0; i<NS; i++) {
5549 HistoryRecord r = (HistoryRecord)stops.get(i);
5550 synchronized (this) {
5551 if (r.finishing) {
5552 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5553 } else {
5554 stopActivityLocked(r);
5555 }
5556 }
5557 }
5558
5559 // Finish any activities that are scheduled to do so but have been
5560 // waiting for the next one to start.
5561 for (i=0; i<NF; i++) {
5562 HistoryRecord r = (HistoryRecord)finishes.get(i);
5563 synchronized (this) {
5564 destroyActivityLocked(r, true);
5565 }
5566 }
5567
5568 // Report back to any thumbnail receivers.
5569 for (i=0; i<NT; i++) {
5570 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5571 sendPendingThumbnail(r, null, null, null, true);
5572 }
5573
5574 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005575 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005576 }
5577
5578 trimApplications();
5579 //dump();
5580 //mWindowManager.dump();
5581
5582 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005583 enableScreenAfterBoot();
5584 }
5585 }
5586
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005587 final void finishBooting() {
5588 // Ensure that any processes we had put on hold are now started
5589 // up.
5590 final int NP = mProcessesOnHold.size();
5591 if (NP > 0) {
5592 ArrayList<ProcessRecord> procs =
5593 new ArrayList<ProcessRecord>(mProcessesOnHold);
5594 for (int ip=0; ip<NP; ip++) {
5595 this.startProcessLocked(procs.get(ip), "on-hold", null);
5596 }
5597 }
5598 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5599 // Tell anyone interested that we are done booting!
5600 synchronized (this) {
5601 broadcastIntentLocked(null, null,
5602 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5603 null, null, 0, null, null,
5604 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5605 false, false, MY_PID, Process.SYSTEM_UID);
5606 }
5607 }
5608 }
5609
5610 final void ensureBootCompleted() {
5611 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005612 boolean enableScreen;
5613 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005614 booting = mBooting;
5615 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005616 enableScreen = !mBooted;
5617 mBooted = true;
5618 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005619
5620 if (booting) {
5621 finishBooting();
5622 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005623
5624 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005625 enableScreenAfterBoot();
5626 }
5627 }
5628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005629 public final void activityPaused(IBinder token, Bundle icicle) {
5630 // Refuse possible leaked file descriptors
5631 if (icicle != null && icicle.hasFileDescriptors()) {
5632 throw new IllegalArgumentException("File descriptors passed in Bundle");
5633 }
5634
5635 final long origId = Binder.clearCallingIdentity();
5636 activityPaused(token, icicle, false);
5637 Binder.restoreCallingIdentity(origId);
5638 }
5639
5640 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5641 if (DEBUG_PAUSE) Log.v(
5642 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5643 + ", timeout=" + timeout);
5644
5645 HistoryRecord r = null;
5646
5647 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005648 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005649 if (index >= 0) {
5650 r = (HistoryRecord)mHistory.get(index);
5651 if (!timeout) {
5652 r.icicle = icicle;
5653 r.haveState = true;
5654 }
5655 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5656 if (mPausingActivity == r) {
5657 r.state = ActivityState.PAUSED;
5658 completePauseLocked();
5659 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005660 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005661 System.identityHashCode(r), r.shortComponentName,
5662 mPausingActivity != null
5663 ? mPausingActivity.shortComponentName : "(none)");
5664 }
5665 }
5666 }
5667 }
5668
5669 public final void activityStopped(IBinder token, Bitmap thumbnail,
5670 CharSequence description) {
5671 if (localLOGV) Log.v(
5672 TAG, "Activity stopped: token=" + token);
5673
5674 HistoryRecord r = null;
5675
5676 final long origId = Binder.clearCallingIdentity();
5677
5678 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005679 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005680 if (index >= 0) {
5681 r = (HistoryRecord)mHistory.get(index);
5682 r.thumbnail = thumbnail;
5683 r.description = description;
5684 r.stopped = true;
5685 r.state = ActivityState.STOPPED;
5686 if (!r.finishing) {
5687 if (r.configDestroy) {
5688 destroyActivityLocked(r, true);
5689 resumeTopActivityLocked(null);
5690 }
5691 }
5692 }
5693 }
5694
5695 if (r != null) {
5696 sendPendingThumbnail(r, null, null, null, false);
5697 }
5698
5699 trimApplications();
5700
5701 Binder.restoreCallingIdentity(origId);
5702 }
5703
5704 public final void activityDestroyed(IBinder token) {
5705 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5706 synchronized (this) {
5707 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5708
Dianne Hackborn75b03852009-06-12 15:43:26 -07005709 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005710 if (index >= 0) {
5711 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5712 if (r.state == ActivityState.DESTROYING) {
5713 final long origId = Binder.clearCallingIdentity();
5714 removeActivityFromHistoryLocked(r);
5715 Binder.restoreCallingIdentity(origId);
5716 }
5717 }
5718 }
5719 }
5720
5721 public String getCallingPackage(IBinder token) {
5722 synchronized (this) {
5723 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005724 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005725 }
5726 }
5727
5728 public ComponentName getCallingActivity(IBinder token) {
5729 synchronized (this) {
5730 HistoryRecord r = getCallingRecordLocked(token);
5731 return r != null ? r.intent.getComponent() : null;
5732 }
5733 }
5734
5735 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005736 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005737 if (index >= 0) {
5738 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5739 if (r != null) {
5740 return r.resultTo;
5741 }
5742 }
5743 return null;
5744 }
5745
5746 public ComponentName getActivityClassForToken(IBinder token) {
5747 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005748 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005749 if (index >= 0) {
5750 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5751 return r.intent.getComponent();
5752 }
5753 return null;
5754 }
5755 }
5756
5757 public String getPackageForToken(IBinder token) {
5758 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005759 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005760 if (index >= 0) {
5761 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5762 return r.packageName;
5763 }
5764 return null;
5765 }
5766 }
5767
5768 public IIntentSender getIntentSender(int type,
5769 String packageName, IBinder token, String resultWho,
5770 int requestCode, Intent intent, String resolvedType, int flags) {
5771 // Refuse possible leaked file descriptors
5772 if (intent != null && intent.hasFileDescriptors() == true) {
5773 throw new IllegalArgumentException("File descriptors passed in Intent");
5774 }
5775
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005776 if (type == INTENT_SENDER_BROADCAST) {
5777 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5778 throw new IllegalArgumentException(
5779 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5780 }
5781 }
5782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005783 synchronized(this) {
5784 int callingUid = Binder.getCallingUid();
5785 try {
5786 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5787 Process.supportsProcesses()) {
5788 int uid = ActivityThread.getPackageManager()
5789 .getPackageUid(packageName);
5790 if (uid != Binder.getCallingUid()) {
5791 String msg = "Permission Denial: getIntentSender() from pid="
5792 + Binder.getCallingPid()
5793 + ", uid=" + Binder.getCallingUid()
5794 + ", (need uid=" + uid + ")"
5795 + " is not allowed to send as package " + packageName;
5796 Log.w(TAG, msg);
5797 throw new SecurityException(msg);
5798 }
5799 }
5800 } catch (RemoteException e) {
5801 throw new SecurityException(e);
5802 }
5803 HistoryRecord activity = null;
5804 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005805 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005806 if (index < 0) {
5807 return null;
5808 }
5809 activity = (HistoryRecord)mHistory.get(index);
5810 if (activity.finishing) {
5811 return null;
5812 }
5813 }
5814
5815 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5816 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5817 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5818 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5819 |PendingIntent.FLAG_UPDATE_CURRENT);
5820
5821 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5822 type, packageName, activity, resultWho,
5823 requestCode, intent, resolvedType, flags);
5824 WeakReference<PendingIntentRecord> ref;
5825 ref = mIntentSenderRecords.get(key);
5826 PendingIntentRecord rec = ref != null ? ref.get() : null;
5827 if (rec != null) {
5828 if (!cancelCurrent) {
5829 if (updateCurrent) {
5830 rec.key.requestIntent.replaceExtras(intent);
5831 }
5832 return rec;
5833 }
5834 rec.canceled = true;
5835 mIntentSenderRecords.remove(key);
5836 }
5837 if (noCreate) {
5838 return rec;
5839 }
5840 rec = new PendingIntentRecord(this, key, callingUid);
5841 mIntentSenderRecords.put(key, rec.ref);
5842 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5843 if (activity.pendingResults == null) {
5844 activity.pendingResults
5845 = new HashSet<WeakReference<PendingIntentRecord>>();
5846 }
5847 activity.pendingResults.add(rec.ref);
5848 }
5849 return rec;
5850 }
5851 }
5852
5853 public void cancelIntentSender(IIntentSender sender) {
5854 if (!(sender instanceof PendingIntentRecord)) {
5855 return;
5856 }
5857 synchronized(this) {
5858 PendingIntentRecord rec = (PendingIntentRecord)sender;
5859 try {
5860 int uid = ActivityThread.getPackageManager()
5861 .getPackageUid(rec.key.packageName);
5862 if (uid != Binder.getCallingUid()) {
5863 String msg = "Permission Denial: cancelIntentSender() from pid="
5864 + Binder.getCallingPid()
5865 + ", uid=" + Binder.getCallingUid()
5866 + " is not allowed to cancel packges "
5867 + rec.key.packageName;
5868 Log.w(TAG, msg);
5869 throw new SecurityException(msg);
5870 }
5871 } catch (RemoteException e) {
5872 throw new SecurityException(e);
5873 }
5874 cancelIntentSenderLocked(rec, true);
5875 }
5876 }
5877
5878 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5879 rec.canceled = true;
5880 mIntentSenderRecords.remove(rec.key);
5881 if (cleanActivity && rec.key.activity != null) {
5882 rec.key.activity.pendingResults.remove(rec.ref);
5883 }
5884 }
5885
5886 public String getPackageForIntentSender(IIntentSender pendingResult) {
5887 if (!(pendingResult instanceof PendingIntentRecord)) {
5888 return null;
5889 }
5890 synchronized(this) {
5891 try {
5892 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5893 return res.key.packageName;
5894 } catch (ClassCastException e) {
5895 }
5896 }
5897 return null;
5898 }
5899
5900 public void setProcessLimit(int max) {
5901 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5902 "setProcessLimit()");
5903 mProcessLimit = max;
5904 }
5905
5906 public int getProcessLimit() {
5907 return mProcessLimit;
5908 }
5909
5910 void foregroundTokenDied(ForegroundToken token) {
5911 synchronized (ActivityManagerService.this) {
5912 synchronized (mPidsSelfLocked) {
5913 ForegroundToken cur
5914 = mForegroundProcesses.get(token.pid);
5915 if (cur != token) {
5916 return;
5917 }
5918 mForegroundProcesses.remove(token.pid);
5919 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5920 if (pr == null) {
5921 return;
5922 }
5923 pr.forcingToForeground = null;
5924 pr.foregroundServices = false;
5925 }
5926 updateOomAdjLocked();
5927 }
5928 }
5929
5930 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5931 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5932 "setProcessForeground()");
5933 synchronized(this) {
5934 boolean changed = false;
5935
5936 synchronized (mPidsSelfLocked) {
5937 ProcessRecord pr = mPidsSelfLocked.get(pid);
5938 if (pr == null) {
5939 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5940 return;
5941 }
5942 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5943 if (oldToken != null) {
5944 oldToken.token.unlinkToDeath(oldToken, 0);
5945 mForegroundProcesses.remove(pid);
5946 pr.forcingToForeground = null;
5947 changed = true;
5948 }
5949 if (isForeground && token != null) {
5950 ForegroundToken newToken = new ForegroundToken() {
5951 public void binderDied() {
5952 foregroundTokenDied(this);
5953 }
5954 };
5955 newToken.pid = pid;
5956 newToken.token = token;
5957 try {
5958 token.linkToDeath(newToken, 0);
5959 mForegroundProcesses.put(pid, newToken);
5960 pr.forcingToForeground = token;
5961 changed = true;
5962 } catch (RemoteException e) {
5963 // If the process died while doing this, we will later
5964 // do the cleanup with the process death link.
5965 }
5966 }
5967 }
5968
5969 if (changed) {
5970 updateOomAdjLocked();
5971 }
5972 }
5973 }
5974
5975 // =========================================================
5976 // PERMISSIONS
5977 // =========================================================
5978
5979 static class PermissionController extends IPermissionController.Stub {
5980 ActivityManagerService mActivityManagerService;
5981 PermissionController(ActivityManagerService activityManagerService) {
5982 mActivityManagerService = activityManagerService;
5983 }
5984
5985 public boolean checkPermission(String permission, int pid, int uid) {
5986 return mActivityManagerService.checkPermission(permission, pid,
5987 uid) == PackageManager.PERMISSION_GRANTED;
5988 }
5989 }
5990
5991 /**
5992 * This can be called with or without the global lock held.
5993 */
5994 int checkComponentPermission(String permission, int pid, int uid,
5995 int reqUid) {
5996 // We might be performing an operation on behalf of an indirect binder
5997 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5998 // client identity accordingly before proceeding.
5999 Identity tlsIdentity = sCallerIdentity.get();
6000 if (tlsIdentity != null) {
6001 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6002 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6003 uid = tlsIdentity.uid;
6004 pid = tlsIdentity.pid;
6005 }
6006
6007 // Root, system server and our own process get to do everything.
6008 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6009 !Process.supportsProcesses()) {
6010 return PackageManager.PERMISSION_GRANTED;
6011 }
6012 // If the target requires a specific UID, always fail for others.
6013 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006014 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006015 return PackageManager.PERMISSION_DENIED;
6016 }
6017 if (permission == null) {
6018 return PackageManager.PERMISSION_GRANTED;
6019 }
6020 try {
6021 return ActivityThread.getPackageManager()
6022 .checkUidPermission(permission, uid);
6023 } catch (RemoteException e) {
6024 // Should never happen, but if it does... deny!
6025 Log.e(TAG, "PackageManager is dead?!?", e);
6026 }
6027 return PackageManager.PERMISSION_DENIED;
6028 }
6029
6030 /**
6031 * As the only public entry point for permissions checking, this method
6032 * can enforce the semantic that requesting a check on a null global
6033 * permission is automatically denied. (Internally a null permission
6034 * string is used when calling {@link #checkComponentPermission} in cases
6035 * when only uid-based security is needed.)
6036 *
6037 * This can be called with or without the global lock held.
6038 */
6039 public int checkPermission(String permission, int pid, int uid) {
6040 if (permission == null) {
6041 return PackageManager.PERMISSION_DENIED;
6042 }
6043 return checkComponentPermission(permission, pid, uid, -1);
6044 }
6045
6046 /**
6047 * Binder IPC calls go through the public entry point.
6048 * This can be called with or without the global lock held.
6049 */
6050 int checkCallingPermission(String permission) {
6051 return checkPermission(permission,
6052 Binder.getCallingPid(),
6053 Binder.getCallingUid());
6054 }
6055
6056 /**
6057 * This can be called with or without the global lock held.
6058 */
6059 void enforceCallingPermission(String permission, String func) {
6060 if (checkCallingPermission(permission)
6061 == PackageManager.PERMISSION_GRANTED) {
6062 return;
6063 }
6064
6065 String msg = "Permission Denial: " + func + " from pid="
6066 + Binder.getCallingPid()
6067 + ", uid=" + Binder.getCallingUid()
6068 + " requires " + permission;
6069 Log.w(TAG, msg);
6070 throw new SecurityException(msg);
6071 }
6072
6073 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6074 ProviderInfo pi, int uid, int modeFlags) {
6075 try {
6076 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6077 if ((pi.readPermission != null) &&
6078 (pm.checkUidPermission(pi.readPermission, uid)
6079 != PackageManager.PERMISSION_GRANTED)) {
6080 return false;
6081 }
6082 }
6083 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6084 if ((pi.writePermission != null) &&
6085 (pm.checkUidPermission(pi.writePermission, uid)
6086 != PackageManager.PERMISSION_GRANTED)) {
6087 return false;
6088 }
6089 }
6090 return true;
6091 } catch (RemoteException e) {
6092 return false;
6093 }
6094 }
6095
6096 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6097 int modeFlags) {
6098 // Root gets to do everything.
6099 if (uid == 0 || !Process.supportsProcesses()) {
6100 return true;
6101 }
6102 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6103 if (perms == null) return false;
6104 UriPermission perm = perms.get(uri);
6105 if (perm == null) return false;
6106 return (modeFlags&perm.modeFlags) == modeFlags;
6107 }
6108
6109 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6110 // Another redirected-binder-call permissions check as in
6111 // {@link checkComponentPermission}.
6112 Identity tlsIdentity = sCallerIdentity.get();
6113 if (tlsIdentity != null) {
6114 uid = tlsIdentity.uid;
6115 pid = tlsIdentity.pid;
6116 }
6117
6118 // Our own process gets to do everything.
6119 if (pid == MY_PID) {
6120 return PackageManager.PERMISSION_GRANTED;
6121 }
6122 synchronized(this) {
6123 return checkUriPermissionLocked(uri, uid, modeFlags)
6124 ? PackageManager.PERMISSION_GRANTED
6125 : PackageManager.PERMISSION_DENIED;
6126 }
6127 }
6128
6129 private void grantUriPermissionLocked(int callingUid,
6130 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6131 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6132 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6133 if (modeFlags == 0) {
6134 return;
6135 }
6136
6137 final IPackageManager pm = ActivityThread.getPackageManager();
6138
6139 // If this is not a content: uri, we can't do anything with it.
6140 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6141 return;
6142 }
6143
6144 String name = uri.getAuthority();
6145 ProviderInfo pi = null;
6146 ContentProviderRecord cpr
6147 = (ContentProviderRecord)mProvidersByName.get(name);
6148 if (cpr != null) {
6149 pi = cpr.info;
6150 } else {
6151 try {
6152 pi = pm.resolveContentProvider(name,
6153 PackageManager.GET_URI_PERMISSION_PATTERNS);
6154 } catch (RemoteException ex) {
6155 }
6156 }
6157 if (pi == null) {
6158 Log.w(TAG, "No content provider found for: " + name);
6159 return;
6160 }
6161
6162 int targetUid;
6163 try {
6164 targetUid = pm.getPackageUid(targetPkg);
6165 if (targetUid < 0) {
6166 return;
6167 }
6168 } catch (RemoteException ex) {
6169 return;
6170 }
6171
6172 // First... does the target actually need this permission?
6173 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6174 // No need to grant the target this permission.
6175 return;
6176 }
6177
6178 // Second... maybe someone else has already granted the
6179 // permission?
6180 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6181 // No need to grant the target this permission.
6182 return;
6183 }
6184
6185 // Third... is the provider allowing granting of URI permissions?
6186 if (!pi.grantUriPermissions) {
6187 throw new SecurityException("Provider " + pi.packageName
6188 + "/" + pi.name
6189 + " does not allow granting of Uri permissions (uri "
6190 + uri + ")");
6191 }
6192 if (pi.uriPermissionPatterns != null) {
6193 final int N = pi.uriPermissionPatterns.length;
6194 boolean allowed = false;
6195 for (int i=0; i<N; i++) {
6196 if (pi.uriPermissionPatterns[i] != null
6197 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6198 allowed = true;
6199 break;
6200 }
6201 }
6202 if (!allowed) {
6203 throw new SecurityException("Provider " + pi.packageName
6204 + "/" + pi.name
6205 + " does not allow granting of permission to path of Uri "
6206 + uri);
6207 }
6208 }
6209
6210 // Fourth... does the caller itself have permission to access
6211 // this uri?
6212 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6213 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6214 throw new SecurityException("Uid " + callingUid
6215 + " does not have permission to uri " + uri);
6216 }
6217 }
6218
6219 // Okay! So here we are: the caller has the assumed permission
6220 // to the uri, and the target doesn't. Let's now give this to
6221 // the target.
6222
6223 HashMap<Uri, UriPermission> targetUris
6224 = mGrantedUriPermissions.get(targetUid);
6225 if (targetUris == null) {
6226 targetUris = new HashMap<Uri, UriPermission>();
6227 mGrantedUriPermissions.put(targetUid, targetUris);
6228 }
6229
6230 UriPermission perm = targetUris.get(uri);
6231 if (perm == null) {
6232 perm = new UriPermission(targetUid, uri);
6233 targetUris.put(uri, perm);
6234
6235 }
6236 perm.modeFlags |= modeFlags;
6237 if (activity == null) {
6238 perm.globalModeFlags |= modeFlags;
6239 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6240 perm.readActivities.add(activity);
6241 if (activity.readUriPermissions == null) {
6242 activity.readUriPermissions = new HashSet<UriPermission>();
6243 }
6244 activity.readUriPermissions.add(perm);
6245 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6246 perm.writeActivities.add(activity);
6247 if (activity.writeUriPermissions == null) {
6248 activity.writeUriPermissions = new HashSet<UriPermission>();
6249 }
6250 activity.writeUriPermissions.add(perm);
6251 }
6252 }
6253
6254 private void grantUriPermissionFromIntentLocked(int callingUid,
6255 String targetPkg, Intent intent, HistoryRecord activity) {
6256 if (intent == null) {
6257 return;
6258 }
6259 Uri data = intent.getData();
6260 if (data == null) {
6261 return;
6262 }
6263 grantUriPermissionLocked(callingUid, targetPkg, data,
6264 intent.getFlags(), activity);
6265 }
6266
6267 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6268 Uri uri, int modeFlags) {
6269 synchronized(this) {
6270 final ProcessRecord r = getRecordForAppLocked(caller);
6271 if (r == null) {
6272 throw new SecurityException("Unable to find app for caller "
6273 + caller
6274 + " when granting permission to uri " + uri);
6275 }
6276 if (targetPkg == null) {
6277 Log.w(TAG, "grantUriPermission: null target");
6278 return;
6279 }
6280 if (uri == null) {
6281 Log.w(TAG, "grantUriPermission: null uri");
6282 return;
6283 }
6284
6285 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6286 null);
6287 }
6288 }
6289
6290 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6291 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6292 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6293 HashMap<Uri, UriPermission> perms
6294 = mGrantedUriPermissions.get(perm.uid);
6295 if (perms != null) {
6296 perms.remove(perm.uri);
6297 if (perms.size() == 0) {
6298 mGrantedUriPermissions.remove(perm.uid);
6299 }
6300 }
6301 }
6302 }
6303
6304 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6305 if (activity.readUriPermissions != null) {
6306 for (UriPermission perm : activity.readUriPermissions) {
6307 perm.readActivities.remove(activity);
6308 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6309 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6310 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6311 removeUriPermissionIfNeededLocked(perm);
6312 }
6313 }
6314 }
6315 if (activity.writeUriPermissions != null) {
6316 for (UriPermission perm : activity.writeUriPermissions) {
6317 perm.writeActivities.remove(activity);
6318 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6319 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6320 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6321 removeUriPermissionIfNeededLocked(perm);
6322 }
6323 }
6324 }
6325 }
6326
6327 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6328 int modeFlags) {
6329 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6330 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6331 if (modeFlags == 0) {
6332 return;
6333 }
6334
6335 final IPackageManager pm = ActivityThread.getPackageManager();
6336
6337 final String authority = uri.getAuthority();
6338 ProviderInfo pi = null;
6339 ContentProviderRecord cpr
6340 = (ContentProviderRecord)mProvidersByName.get(authority);
6341 if (cpr != null) {
6342 pi = cpr.info;
6343 } else {
6344 try {
6345 pi = pm.resolveContentProvider(authority,
6346 PackageManager.GET_URI_PERMISSION_PATTERNS);
6347 } catch (RemoteException ex) {
6348 }
6349 }
6350 if (pi == null) {
6351 Log.w(TAG, "No content provider found for: " + authority);
6352 return;
6353 }
6354
6355 // Does the caller have this permission on the URI?
6356 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6357 // Right now, if you are not the original owner of the permission,
6358 // you are not allowed to revoke it.
6359 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6360 throw new SecurityException("Uid " + callingUid
6361 + " does not have permission to uri " + uri);
6362 //}
6363 }
6364
6365 // Go through all of the permissions and remove any that match.
6366 final List<String> SEGMENTS = uri.getPathSegments();
6367 if (SEGMENTS != null) {
6368 final int NS = SEGMENTS.size();
6369 int N = mGrantedUriPermissions.size();
6370 for (int i=0; i<N; i++) {
6371 HashMap<Uri, UriPermission> perms
6372 = mGrantedUriPermissions.valueAt(i);
6373 Iterator<UriPermission> it = perms.values().iterator();
6374 toploop:
6375 while (it.hasNext()) {
6376 UriPermission perm = it.next();
6377 Uri targetUri = perm.uri;
6378 if (!authority.equals(targetUri.getAuthority())) {
6379 continue;
6380 }
6381 List<String> targetSegments = targetUri.getPathSegments();
6382 if (targetSegments == null) {
6383 continue;
6384 }
6385 if (targetSegments.size() < NS) {
6386 continue;
6387 }
6388 for (int j=0; j<NS; j++) {
6389 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6390 continue toploop;
6391 }
6392 }
6393 perm.clearModes(modeFlags);
6394 if (perm.modeFlags == 0) {
6395 it.remove();
6396 }
6397 }
6398 if (perms.size() == 0) {
6399 mGrantedUriPermissions.remove(
6400 mGrantedUriPermissions.keyAt(i));
6401 N--;
6402 i--;
6403 }
6404 }
6405 }
6406 }
6407
6408 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6409 int modeFlags) {
6410 synchronized(this) {
6411 final ProcessRecord r = getRecordForAppLocked(caller);
6412 if (r == null) {
6413 throw new SecurityException("Unable to find app for caller "
6414 + caller
6415 + " when revoking permission to uri " + uri);
6416 }
6417 if (uri == null) {
6418 Log.w(TAG, "revokeUriPermission: null uri");
6419 return;
6420 }
6421
6422 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6423 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6424 if (modeFlags == 0) {
6425 return;
6426 }
6427
6428 final IPackageManager pm = ActivityThread.getPackageManager();
6429
6430 final String authority = uri.getAuthority();
6431 ProviderInfo pi = null;
6432 ContentProviderRecord cpr
6433 = (ContentProviderRecord)mProvidersByName.get(authority);
6434 if (cpr != null) {
6435 pi = cpr.info;
6436 } else {
6437 try {
6438 pi = pm.resolveContentProvider(authority,
6439 PackageManager.GET_URI_PERMISSION_PATTERNS);
6440 } catch (RemoteException ex) {
6441 }
6442 }
6443 if (pi == null) {
6444 Log.w(TAG, "No content provider found for: " + authority);
6445 return;
6446 }
6447
6448 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6449 }
6450 }
6451
6452 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6453 synchronized (this) {
6454 ProcessRecord app =
6455 who != null ? getRecordForAppLocked(who) : null;
6456 if (app == null) return;
6457
6458 Message msg = Message.obtain();
6459 msg.what = WAIT_FOR_DEBUGGER_MSG;
6460 msg.obj = app;
6461 msg.arg1 = waiting ? 1 : 0;
6462 mHandler.sendMessage(msg);
6463 }
6464 }
6465
6466 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6467 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006468 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006469 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006470 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006471 }
6472
6473 // =========================================================
6474 // TASK MANAGEMENT
6475 // =========================================================
6476
6477 public List getTasks(int maxNum, int flags,
6478 IThumbnailReceiver receiver) {
6479 ArrayList list = new ArrayList();
6480
6481 PendingThumbnailsRecord pending = null;
6482 IApplicationThread topThumbnail = null;
6483 HistoryRecord topRecord = null;
6484
6485 synchronized(this) {
6486 if (localLOGV) Log.v(
6487 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6488 + ", receiver=" + receiver);
6489
6490 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6491 != PackageManager.PERMISSION_GRANTED) {
6492 if (receiver != null) {
6493 // If the caller wants to wait for pending thumbnails,
6494 // it ain't gonna get them.
6495 try {
6496 receiver.finished();
6497 } catch (RemoteException ex) {
6498 }
6499 }
6500 String msg = "Permission Denial: getTasks() from pid="
6501 + Binder.getCallingPid()
6502 + ", uid=" + Binder.getCallingUid()
6503 + " requires " + android.Manifest.permission.GET_TASKS;
6504 Log.w(TAG, msg);
6505 throw new SecurityException(msg);
6506 }
6507
6508 int pos = mHistory.size()-1;
6509 HistoryRecord next =
6510 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6511 HistoryRecord top = null;
6512 CharSequence topDescription = null;
6513 TaskRecord curTask = null;
6514 int numActivities = 0;
6515 int numRunning = 0;
6516 while (pos >= 0 && maxNum > 0) {
6517 final HistoryRecord r = next;
6518 pos--;
6519 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6520
6521 // Initialize state for next task if needed.
6522 if (top == null ||
6523 (top.state == ActivityState.INITIALIZING
6524 && top.task == r.task)) {
6525 top = r;
6526 topDescription = r.description;
6527 curTask = r.task;
6528 numActivities = numRunning = 0;
6529 }
6530
6531 // Add 'r' into the current task.
6532 numActivities++;
6533 if (r.app != null && r.app.thread != null) {
6534 numRunning++;
6535 }
6536 if (topDescription == null) {
6537 topDescription = r.description;
6538 }
6539
6540 if (localLOGV) Log.v(
6541 TAG, r.intent.getComponent().flattenToShortString()
6542 + ": task=" + r.task);
6543
6544 // If the next one is a different task, generate a new
6545 // TaskInfo entry for what we have.
6546 if (next == null || next.task != curTask) {
6547 ActivityManager.RunningTaskInfo ci
6548 = new ActivityManager.RunningTaskInfo();
6549 ci.id = curTask.taskId;
6550 ci.baseActivity = r.intent.getComponent();
6551 ci.topActivity = top.intent.getComponent();
6552 ci.thumbnail = top.thumbnail;
6553 ci.description = topDescription;
6554 ci.numActivities = numActivities;
6555 ci.numRunning = numRunning;
6556 //System.out.println(
6557 // "#" + maxNum + ": " + " descr=" + ci.description);
6558 if (ci.thumbnail == null && receiver != null) {
6559 if (localLOGV) Log.v(
6560 TAG, "State=" + top.state + "Idle=" + top.idle
6561 + " app=" + top.app
6562 + " thr=" + (top.app != null ? top.app.thread : null));
6563 if (top.state == ActivityState.RESUMED
6564 || top.state == ActivityState.PAUSING) {
6565 if (top.idle && top.app != null
6566 && top.app.thread != null) {
6567 topRecord = top;
6568 topThumbnail = top.app.thread;
6569 } else {
6570 top.thumbnailNeeded = true;
6571 }
6572 }
6573 if (pending == null) {
6574 pending = new PendingThumbnailsRecord(receiver);
6575 }
6576 pending.pendingRecords.add(top);
6577 }
6578 list.add(ci);
6579 maxNum--;
6580 top = null;
6581 }
6582 }
6583
6584 if (pending != null) {
6585 mPendingThumbnails.add(pending);
6586 }
6587 }
6588
6589 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6590
6591 if (topThumbnail != null) {
6592 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6593 try {
6594 topThumbnail.requestThumbnail(topRecord);
6595 } catch (Exception e) {
6596 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6597 sendPendingThumbnail(null, topRecord, null, null, true);
6598 }
6599 }
6600
6601 if (pending == null && receiver != null) {
6602 // In this case all thumbnails were available and the client
6603 // is being asked to be told when the remaining ones come in...
6604 // which is unusually, since the top-most currently running
6605 // activity should never have a canned thumbnail! Oh well.
6606 try {
6607 receiver.finished();
6608 } catch (RemoteException ex) {
6609 }
6610 }
6611
6612 return list;
6613 }
6614
6615 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6616 int flags) {
6617 synchronized (this) {
6618 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6619 "getRecentTasks()");
6620
6621 final int N = mRecentTasks.size();
6622 ArrayList<ActivityManager.RecentTaskInfo> res
6623 = new ArrayList<ActivityManager.RecentTaskInfo>(
6624 maxNum < N ? maxNum : N);
6625 for (int i=0; i<N && maxNum > 0; i++) {
6626 TaskRecord tr = mRecentTasks.get(i);
6627 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6628 || (tr.intent == null)
6629 || ((tr.intent.getFlags()
6630 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6631 ActivityManager.RecentTaskInfo rti
6632 = new ActivityManager.RecentTaskInfo();
6633 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6634 rti.baseIntent = new Intent(
6635 tr.intent != null ? tr.intent : tr.affinityIntent);
6636 rti.origActivity = tr.origActivity;
6637 res.add(rti);
6638 maxNum--;
6639 }
6640 }
6641 return res;
6642 }
6643 }
6644
6645 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6646 int j;
6647 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6648 TaskRecord jt = startTask;
6649
6650 // First look backwards
6651 for (j=startIndex-1; j>=0; j--) {
6652 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6653 if (r.task != jt) {
6654 jt = r.task;
6655 if (affinity.equals(jt.affinity)) {
6656 return j;
6657 }
6658 }
6659 }
6660
6661 // Now look forwards
6662 final int N = mHistory.size();
6663 jt = startTask;
6664 for (j=startIndex+1; j<N; j++) {
6665 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6666 if (r.task != jt) {
6667 if (affinity.equals(jt.affinity)) {
6668 return j;
6669 }
6670 jt = r.task;
6671 }
6672 }
6673
6674 // Might it be at the top?
6675 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6676 return N-1;
6677 }
6678
6679 return -1;
6680 }
6681
6682 /**
6683 * Perform a reset of the given task, if needed as part of launching it.
6684 * Returns the new HistoryRecord at the top of the task.
6685 */
6686 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6687 HistoryRecord newActivity) {
6688 boolean forceReset = (newActivity.info.flags
6689 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6690 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6691 if ((newActivity.info.flags
6692 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6693 forceReset = true;
6694 }
6695 }
6696
6697 final TaskRecord task = taskTop.task;
6698
6699 // We are going to move through the history list so that we can look
6700 // at each activity 'target' with 'below' either the interesting
6701 // activity immediately below it in the stack or null.
6702 HistoryRecord target = null;
6703 int targetI = 0;
6704 int taskTopI = -1;
6705 int replyChainEnd = -1;
6706 int lastReparentPos = -1;
6707 for (int i=mHistory.size()-1; i>=-1; i--) {
6708 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6709
6710 if (below != null && below.finishing) {
6711 continue;
6712 }
6713 if (target == null) {
6714 target = below;
6715 targetI = i;
6716 // If we were in the middle of a reply chain before this
6717 // task, it doesn't appear like the root of the chain wants
6718 // anything interesting, so drop it.
6719 replyChainEnd = -1;
6720 continue;
6721 }
6722
6723 final int flags = target.info.flags;
6724
6725 final boolean finishOnTaskLaunch =
6726 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6727 final boolean allowTaskReparenting =
6728 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6729
6730 if (target.task == task) {
6731 // We are inside of the task being reset... we'll either
6732 // finish this activity, push it out for another task,
6733 // or leave it as-is. We only do this
6734 // for activities that are not the root of the task (since
6735 // if we finish the root, we may no longer have the task!).
6736 if (taskTopI < 0) {
6737 taskTopI = targetI;
6738 }
6739 if (below != null && below.task == task) {
6740 final boolean clearWhenTaskReset =
6741 (target.intent.getFlags()
6742 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006743 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006744 // If this activity is sending a reply to a previous
6745 // activity, we can't do anything with it now until
6746 // we reach the start of the reply chain.
6747 // XXX note that we are assuming the result is always
6748 // to the previous activity, which is almost always
6749 // the case but we really shouldn't count on.
6750 if (replyChainEnd < 0) {
6751 replyChainEnd = targetI;
6752 }
Ed Heyl73798232009-03-24 21:32:21 -07006753 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006754 && target.taskAffinity != null
6755 && !target.taskAffinity.equals(task.affinity)) {
6756 // If this activity has an affinity for another
6757 // task, then we need to move it out of here. We will
6758 // move it as far out of the way as possible, to the
6759 // bottom of the activity stack. This also keeps it
6760 // correctly ordered with any activities we previously
6761 // moved.
6762 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6763 if (target.taskAffinity != null
6764 && target.taskAffinity.equals(p.task.affinity)) {
6765 // If the activity currently at the bottom has the
6766 // same task affinity as the one we are moving,
6767 // then merge it into the same task.
6768 target.task = p.task;
6769 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6770 + " out to bottom task " + p.task);
6771 } else {
6772 mCurTask++;
6773 if (mCurTask <= 0) {
6774 mCurTask = 1;
6775 }
6776 target.task = new TaskRecord(mCurTask, target.info, null,
6777 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6778 target.task.affinityIntent = target.intent;
6779 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6780 + " out to new task " + target.task);
6781 }
6782 mWindowManager.setAppGroupId(target, task.taskId);
6783 if (replyChainEnd < 0) {
6784 replyChainEnd = targetI;
6785 }
6786 int dstPos = 0;
6787 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6788 p = (HistoryRecord)mHistory.get(srcPos);
6789 if (p.finishing) {
6790 continue;
6791 }
6792 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6793 + " out to target's task " + target.task);
6794 task.numActivities--;
6795 p.task = target.task;
6796 target.task.numActivities++;
6797 mHistory.remove(srcPos);
6798 mHistory.add(dstPos, p);
6799 mWindowManager.moveAppToken(dstPos, p);
6800 mWindowManager.setAppGroupId(p, p.task.taskId);
6801 dstPos++;
6802 if (VALIDATE_TOKENS) {
6803 mWindowManager.validateAppTokens(mHistory);
6804 }
6805 i++;
6806 }
6807 if (taskTop == p) {
6808 taskTop = below;
6809 }
6810 if (taskTopI == replyChainEnd) {
6811 taskTopI = -1;
6812 }
6813 replyChainEnd = -1;
6814 addRecentTask(target.task);
6815 } else if (forceReset || finishOnTaskLaunch
6816 || clearWhenTaskReset) {
6817 // If the activity should just be removed -- either
6818 // because it asks for it, or the task should be
6819 // cleared -- then finish it and anything that is
6820 // part of its reply chain.
6821 if (clearWhenTaskReset) {
6822 // In this case, we want to finish this activity
6823 // and everything above it, so be sneaky and pretend
6824 // like these are all in the reply chain.
6825 replyChainEnd = targetI+1;
6826 while (replyChainEnd < mHistory.size() &&
6827 ((HistoryRecord)mHistory.get(
6828 replyChainEnd)).task == task) {
6829 replyChainEnd++;
6830 }
6831 replyChainEnd--;
6832 } else if (replyChainEnd < 0) {
6833 replyChainEnd = targetI;
6834 }
6835 HistoryRecord p = null;
6836 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6837 p = (HistoryRecord)mHistory.get(srcPos);
6838 if (p.finishing) {
6839 continue;
6840 }
6841 if (finishActivityLocked(p, srcPos,
6842 Activity.RESULT_CANCELED, null, "reset")) {
6843 replyChainEnd--;
6844 srcPos--;
6845 }
6846 }
6847 if (taskTop == p) {
6848 taskTop = below;
6849 }
6850 if (taskTopI == replyChainEnd) {
6851 taskTopI = -1;
6852 }
6853 replyChainEnd = -1;
6854 } else {
6855 // If we were in the middle of a chain, well the
6856 // activity that started it all doesn't want anything
6857 // special, so leave it all as-is.
6858 replyChainEnd = -1;
6859 }
6860 } else {
6861 // Reached the bottom of the task -- any reply chain
6862 // should be left as-is.
6863 replyChainEnd = -1;
6864 }
6865
6866 } else if (target.resultTo != null) {
6867 // If this activity is sending a reply to a previous
6868 // activity, we can't do anything with it now until
6869 // we reach the start of the reply chain.
6870 // XXX note that we are assuming the result is always
6871 // to the previous activity, which is almost always
6872 // the case but we really shouldn't count on.
6873 if (replyChainEnd < 0) {
6874 replyChainEnd = targetI;
6875 }
6876
6877 } else if (taskTopI >= 0 && allowTaskReparenting
6878 && task.affinity != null
6879 && task.affinity.equals(target.taskAffinity)) {
6880 // We are inside of another task... if this activity has
6881 // an affinity for our task, then either remove it if we are
6882 // clearing or move it over to our task. Note that
6883 // we currently punt on the case where we are resetting a
6884 // task that is not at the top but who has activities above
6885 // with an affinity to it... this is really not a normal
6886 // case, and we will need to later pull that task to the front
6887 // and usually at that point we will do the reset and pick
6888 // up those remaining activities. (This only happens if
6889 // someone starts an activity in a new task from an activity
6890 // in a task that is not currently on top.)
6891 if (forceReset || finishOnTaskLaunch) {
6892 if (replyChainEnd < 0) {
6893 replyChainEnd = targetI;
6894 }
6895 HistoryRecord p = null;
6896 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6897 p = (HistoryRecord)mHistory.get(srcPos);
6898 if (p.finishing) {
6899 continue;
6900 }
6901 if (finishActivityLocked(p, srcPos,
6902 Activity.RESULT_CANCELED, null, "reset")) {
6903 taskTopI--;
6904 lastReparentPos--;
6905 replyChainEnd--;
6906 srcPos--;
6907 }
6908 }
6909 replyChainEnd = -1;
6910 } else {
6911 if (replyChainEnd < 0) {
6912 replyChainEnd = targetI;
6913 }
6914 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6915 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6916 if (p.finishing) {
6917 continue;
6918 }
6919 if (lastReparentPos < 0) {
6920 lastReparentPos = taskTopI;
6921 taskTop = p;
6922 } else {
6923 lastReparentPos--;
6924 }
6925 mHistory.remove(srcPos);
6926 p.task.numActivities--;
6927 p.task = task;
6928 mHistory.add(lastReparentPos, p);
6929 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6930 + " in to resetting task " + task);
6931 task.numActivities++;
6932 mWindowManager.moveAppToken(lastReparentPos, p);
6933 mWindowManager.setAppGroupId(p, p.task.taskId);
6934 if (VALIDATE_TOKENS) {
6935 mWindowManager.validateAppTokens(mHistory);
6936 }
6937 }
6938 replyChainEnd = -1;
6939
6940 // Now we've moved it in to place... but what if this is
6941 // a singleTop activity and we have put it on top of another
6942 // instance of the same activity? Then we drop the instance
6943 // below so it remains singleTop.
6944 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6945 for (int j=lastReparentPos-1; j>=0; j--) {
6946 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6947 if (p.finishing) {
6948 continue;
6949 }
6950 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6951 if (finishActivityLocked(p, j,
6952 Activity.RESULT_CANCELED, null, "replace")) {
6953 taskTopI--;
6954 lastReparentPos--;
6955 }
6956 }
6957 }
6958 }
6959 }
6960 }
6961
6962 target = below;
6963 targetI = i;
6964 }
6965
6966 return taskTop;
6967 }
6968
6969 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006970 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006971 */
6972 public void moveTaskToFront(int task) {
6973 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6974 "moveTaskToFront()");
6975
6976 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006977 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6978 Binder.getCallingUid(), "Task to front")) {
6979 return;
6980 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006981 final long origId = Binder.clearCallingIdentity();
6982 try {
6983 int N = mRecentTasks.size();
6984 for (int i=0; i<N; i++) {
6985 TaskRecord tr = mRecentTasks.get(i);
6986 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006987 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006988 return;
6989 }
6990 }
6991 for (int i=mHistory.size()-1; i>=0; i--) {
6992 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6993 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006994 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006995 return;
6996 }
6997 }
6998 } finally {
6999 Binder.restoreCallingIdentity(origId);
7000 }
7001 }
7002 }
7003
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007004 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007005 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7006
7007 final int task = tr.taskId;
7008 int top = mHistory.size()-1;
7009
7010 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7011 // nothing to do!
7012 return;
7013 }
7014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007015 ArrayList moved = new ArrayList();
7016
7017 // Applying the affinities may have removed entries from the history,
7018 // so get the size again.
7019 top = mHistory.size()-1;
7020 int pos = top;
7021
7022 // Shift all activities with this task up to the top
7023 // of the stack, keeping them in the same internal order.
7024 while (pos >= 0) {
7025 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7026 if (localLOGV) Log.v(
7027 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7028 boolean first = true;
7029 if (r.task.taskId == task) {
7030 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7031 mHistory.remove(pos);
7032 mHistory.add(top, r);
7033 moved.add(0, r);
7034 top--;
7035 if (first) {
7036 addRecentTask(r.task);
7037 first = false;
7038 }
7039 }
7040 pos--;
7041 }
7042
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007043 if (DEBUG_TRANSITION) Log.v(TAG,
7044 "Prepare to front transition: task=" + tr);
7045 if (reason != null &&
7046 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7047 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7048 HistoryRecord r = topRunningActivityLocked(null);
7049 if (r != null) {
7050 mNoAnimActivities.add(r);
7051 }
7052 } else {
7053 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7054 }
7055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007056 mWindowManager.moveAppTokensToTop(moved);
7057 if (VALIDATE_TOKENS) {
7058 mWindowManager.validateAppTokens(mHistory);
7059 }
7060
7061 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007062 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007063 }
7064
7065 private final void finishTaskMove(int task) {
7066 resumeTopActivityLocked(null);
7067 }
7068
7069 public void moveTaskToBack(int task) {
7070 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7071 "moveTaskToBack()");
7072
7073 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007074 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7075 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7076 Binder.getCallingUid(), "Task to back")) {
7077 return;
7078 }
7079 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007080 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007081 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007082 Binder.restoreCallingIdentity(origId);
7083 }
7084 }
7085
7086 /**
7087 * Moves an activity, and all of the other activities within the same task, to the bottom
7088 * of the history stack. The activity's order within the task is unchanged.
7089 *
7090 * @param token A reference to the activity we wish to move
7091 * @param nonRoot If false then this only works if the activity is the root
7092 * of a task; if true it will work for any activity in a task.
7093 * @return Returns true if the move completed, false if not.
7094 */
7095 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7096 synchronized(this) {
7097 final long origId = Binder.clearCallingIdentity();
7098 int taskId = getTaskForActivityLocked(token, !nonRoot);
7099 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007100 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007101 }
7102 Binder.restoreCallingIdentity(origId);
7103 }
7104 return false;
7105 }
7106
7107 /**
7108 * Worker method for rearranging history stack. Implements the function of moving all
7109 * activities for a specific task (gathering them if disjoint) into a single group at the
7110 * bottom of the stack.
7111 *
7112 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7113 * to premeptively cancel the move.
7114 *
7115 * @param task The taskId to collect and move to the bottom.
7116 * @return Returns true if the move completed, false if not.
7117 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007118 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007119 Log.i(TAG, "moveTaskToBack: " + task);
7120
7121 // If we have a watcher, preflight the move before committing to it. First check
7122 // for *other* available tasks, but if none are available, then try again allowing the
7123 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007124 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007125 HistoryRecord next = topRunningActivityLocked(null, task);
7126 if (next == null) {
7127 next = topRunningActivityLocked(null, 0);
7128 }
7129 if (next != null) {
7130 // ask watcher if this is allowed
7131 boolean moveOK = true;
7132 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007133 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007134 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007135 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007136 }
7137 if (!moveOK) {
7138 return false;
7139 }
7140 }
7141 }
7142
7143 ArrayList moved = new ArrayList();
7144
7145 if (DEBUG_TRANSITION) Log.v(TAG,
7146 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007147
7148 final int N = mHistory.size();
7149 int bottom = 0;
7150 int pos = 0;
7151
7152 // Shift all activities with this task down to the bottom
7153 // of the stack, keeping them in the same internal order.
7154 while (pos < N) {
7155 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7156 if (localLOGV) Log.v(
7157 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7158 if (r.task.taskId == task) {
7159 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7160 mHistory.remove(pos);
7161 mHistory.add(bottom, r);
7162 moved.add(r);
7163 bottom++;
7164 }
7165 pos++;
7166 }
7167
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007168 if (reason != null &&
7169 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7170 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7171 HistoryRecord r = topRunningActivityLocked(null);
7172 if (r != null) {
7173 mNoAnimActivities.add(r);
7174 }
7175 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007176 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007177 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007178 mWindowManager.moveAppTokensToBottom(moved);
7179 if (VALIDATE_TOKENS) {
7180 mWindowManager.validateAppTokens(mHistory);
7181 }
7182
7183 finishTaskMove(task);
7184 return true;
7185 }
7186
7187 public void moveTaskBackwards(int task) {
7188 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7189 "moveTaskBackwards()");
7190
7191 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007192 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7193 Binder.getCallingUid(), "Task backwards")) {
7194 return;
7195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007196 final long origId = Binder.clearCallingIdentity();
7197 moveTaskBackwardsLocked(task);
7198 Binder.restoreCallingIdentity(origId);
7199 }
7200 }
7201
7202 private final void moveTaskBackwardsLocked(int task) {
7203 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7204 }
7205
7206 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7207 synchronized(this) {
7208 return getTaskForActivityLocked(token, onlyRoot);
7209 }
7210 }
7211
7212 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7213 final int N = mHistory.size();
7214 TaskRecord lastTask = null;
7215 for (int i=0; i<N; i++) {
7216 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7217 if (r == token) {
7218 if (!onlyRoot || lastTask != r.task) {
7219 return r.task.taskId;
7220 }
7221 return -1;
7222 }
7223 lastTask = r.task;
7224 }
7225
7226 return -1;
7227 }
7228
7229 /**
7230 * Returns the top activity in any existing task matching the given
7231 * Intent. Returns null if no such task is found.
7232 */
7233 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7234 ComponentName cls = intent.getComponent();
7235 if (info.targetActivity != null) {
7236 cls = new ComponentName(info.packageName, info.targetActivity);
7237 }
7238
7239 TaskRecord cp = null;
7240
7241 final int N = mHistory.size();
7242 for (int i=(N-1); i>=0; i--) {
7243 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7244 if (!r.finishing && r.task != cp
7245 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7246 cp = r.task;
7247 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7248 // + "/aff=" + r.task.affinity + " to new cls="
7249 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7250 if (r.task.affinity != null) {
7251 if (r.task.affinity.equals(info.taskAffinity)) {
7252 //Log.i(TAG, "Found matching affinity!");
7253 return r;
7254 }
7255 } else if (r.task.intent != null
7256 && r.task.intent.getComponent().equals(cls)) {
7257 //Log.i(TAG, "Found matching class!");
7258 //dump();
7259 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7260 return r;
7261 } else if (r.task.affinityIntent != null
7262 && r.task.affinityIntent.getComponent().equals(cls)) {
7263 //Log.i(TAG, "Found matching class!");
7264 //dump();
7265 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7266 return r;
7267 }
7268 }
7269 }
7270
7271 return null;
7272 }
7273
7274 /**
7275 * Returns the first activity (starting from the top of the stack) that
7276 * is the same as the given activity. Returns null if no such activity
7277 * is found.
7278 */
7279 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7280 ComponentName cls = intent.getComponent();
7281 if (info.targetActivity != null) {
7282 cls = new ComponentName(info.packageName, info.targetActivity);
7283 }
7284
7285 final int N = mHistory.size();
7286 for (int i=(N-1); i>=0; i--) {
7287 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7288 if (!r.finishing) {
7289 if (r.intent.getComponent().equals(cls)) {
7290 //Log.i(TAG, "Found matching class!");
7291 //dump();
7292 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7293 return r;
7294 }
7295 }
7296 }
7297
7298 return null;
7299 }
7300
7301 public void finishOtherInstances(IBinder token, ComponentName className) {
7302 synchronized(this) {
7303 final long origId = Binder.clearCallingIdentity();
7304
7305 int N = mHistory.size();
7306 TaskRecord lastTask = null;
7307 for (int i=0; i<N; i++) {
7308 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7309 if (r.realActivity.equals(className)
7310 && r != token && lastTask != r.task) {
7311 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7312 null, "others")) {
7313 i--;
7314 N--;
7315 }
7316 }
7317 lastTask = r.task;
7318 }
7319
7320 Binder.restoreCallingIdentity(origId);
7321 }
7322 }
7323
7324 // =========================================================
7325 // THUMBNAILS
7326 // =========================================================
7327
7328 public void reportThumbnail(IBinder token,
7329 Bitmap thumbnail, CharSequence description) {
7330 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7331 final long origId = Binder.clearCallingIdentity();
7332 sendPendingThumbnail(null, token, thumbnail, description, true);
7333 Binder.restoreCallingIdentity(origId);
7334 }
7335
7336 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7337 Bitmap thumbnail, CharSequence description, boolean always) {
7338 TaskRecord task = null;
7339 ArrayList receivers = null;
7340
7341 //System.out.println("Send pending thumbnail: " + r);
7342
7343 synchronized(this) {
7344 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007345 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007346 if (index < 0) {
7347 return;
7348 }
7349 r = (HistoryRecord)mHistory.get(index);
7350 }
7351 if (thumbnail == null) {
7352 thumbnail = r.thumbnail;
7353 description = r.description;
7354 }
7355 if (thumbnail == null && !always) {
7356 // If there is no thumbnail, and this entry is not actually
7357 // going away, then abort for now and pick up the next
7358 // thumbnail we get.
7359 return;
7360 }
7361 task = r.task;
7362
7363 int N = mPendingThumbnails.size();
7364 int i=0;
7365 while (i<N) {
7366 PendingThumbnailsRecord pr =
7367 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7368 //System.out.println("Looking in " + pr.pendingRecords);
7369 if (pr.pendingRecords.remove(r)) {
7370 if (receivers == null) {
7371 receivers = new ArrayList();
7372 }
7373 receivers.add(pr);
7374 if (pr.pendingRecords.size() == 0) {
7375 pr.finished = true;
7376 mPendingThumbnails.remove(i);
7377 N--;
7378 continue;
7379 }
7380 }
7381 i++;
7382 }
7383 }
7384
7385 if (receivers != null) {
7386 final int N = receivers.size();
7387 for (int i=0; i<N; i++) {
7388 try {
7389 PendingThumbnailsRecord pr =
7390 (PendingThumbnailsRecord)receivers.get(i);
7391 pr.receiver.newThumbnail(
7392 task != null ? task.taskId : -1, thumbnail, description);
7393 if (pr.finished) {
7394 pr.receiver.finished();
7395 }
7396 } catch (Exception e) {
7397 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7398 }
7399 }
7400 }
7401 }
7402
7403 // =========================================================
7404 // CONTENT PROVIDERS
7405 // =========================================================
7406
7407 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7408 List providers = null;
7409 try {
7410 providers = ActivityThread.getPackageManager().
7411 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007412 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007413 } catch (RemoteException ex) {
7414 }
7415 if (providers != null) {
7416 final int N = providers.size();
7417 for (int i=0; i<N; i++) {
7418 ProviderInfo cpi =
7419 (ProviderInfo)providers.get(i);
7420 ContentProviderRecord cpr =
7421 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7422 if (cpr == null) {
7423 cpr = new ContentProviderRecord(cpi, app.info);
7424 mProvidersByClass.put(cpi.name, cpr);
7425 }
7426 app.pubProviders.put(cpi.name, cpr);
7427 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007428 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007429 }
7430 }
7431 return providers;
7432 }
7433
7434 private final String checkContentProviderPermissionLocked(
7435 ProviderInfo cpi, ProcessRecord r, int mode) {
7436 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7437 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7438 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7439 cpi.exported ? -1 : cpi.applicationInfo.uid)
7440 == PackageManager.PERMISSION_GRANTED
7441 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7442 return null;
7443 }
7444 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7445 cpi.exported ? -1 : cpi.applicationInfo.uid)
7446 == PackageManager.PERMISSION_GRANTED) {
7447 return null;
7448 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007449
7450 PathPermission[] pps = cpi.pathPermissions;
7451 if (pps != null) {
7452 int i = pps.length;
7453 while (i > 0) {
7454 i--;
7455 PathPermission pp = pps[i];
7456 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7457 cpi.exported ? -1 : cpi.applicationInfo.uid)
7458 == PackageManager.PERMISSION_GRANTED
7459 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7460 return null;
7461 }
7462 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7463 cpi.exported ? -1 : cpi.applicationInfo.uid)
7464 == PackageManager.PERMISSION_GRANTED) {
7465 return null;
7466 }
7467 }
7468 }
7469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007470 String msg = "Permission Denial: opening provider " + cpi.name
7471 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7472 + ", uid=" + callingUid + ") requires "
7473 + cpi.readPermission + " or " + cpi.writePermission;
7474 Log.w(TAG, msg);
7475 return msg;
7476 }
7477
7478 private final ContentProviderHolder getContentProviderImpl(
7479 IApplicationThread caller, String name) {
7480 ContentProviderRecord cpr;
7481 ProviderInfo cpi = null;
7482
7483 synchronized(this) {
7484 ProcessRecord r = null;
7485 if (caller != null) {
7486 r = getRecordForAppLocked(caller);
7487 if (r == null) {
7488 throw new SecurityException(
7489 "Unable to find app for caller " + caller
7490 + " (pid=" + Binder.getCallingPid()
7491 + ") when getting content provider " + name);
7492 }
7493 }
7494
7495 // First check if this content provider has been published...
7496 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7497 if (cpr != null) {
7498 cpi = cpr.info;
7499 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7500 return new ContentProviderHolder(cpi,
7501 cpi.readPermission != null
7502 ? cpi.readPermission : cpi.writePermission);
7503 }
7504
7505 if (r != null && cpr.canRunHere(r)) {
7506 // This provider has been published or is in the process
7507 // of being published... but it is also allowed to run
7508 // in the caller's process, so don't make a connection
7509 // and just let the caller instantiate its own instance.
7510 if (cpr.provider != null) {
7511 // don't give caller the provider object, it needs
7512 // to make its own.
7513 cpr = new ContentProviderRecord(cpr);
7514 }
7515 return cpr;
7516 }
7517
7518 final long origId = Binder.clearCallingIdentity();
7519
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007520 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007521 // return it right away.
7522 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007523 if (DEBUG_PROVIDER) Log.v(TAG,
7524 "Adding provider requested by "
7525 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007526 + cpr.info.processName);
7527 Integer cnt = r.conProviders.get(cpr);
7528 if (cnt == null) {
7529 r.conProviders.put(cpr, new Integer(1));
7530 } else {
7531 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007533 cpr.clients.add(r);
7534 } else {
7535 cpr.externals++;
7536 }
7537
7538 if (cpr.app != null) {
7539 updateOomAdjLocked(cpr.app);
7540 }
7541
7542 Binder.restoreCallingIdentity(origId);
7543
7544 } else {
7545 try {
7546 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007547 resolveContentProvider(name,
7548 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007549 } catch (RemoteException ex) {
7550 }
7551 if (cpi == null) {
7552 return null;
7553 }
7554
7555 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7556 return new ContentProviderHolder(cpi,
7557 cpi.readPermission != null
7558 ? cpi.readPermission : cpi.writePermission);
7559 }
7560
7561 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7562 final boolean firstClass = cpr == null;
7563 if (firstClass) {
7564 try {
7565 ApplicationInfo ai =
7566 ActivityThread.getPackageManager().
7567 getApplicationInfo(
7568 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007569 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007570 if (ai == null) {
7571 Log.w(TAG, "No package info for content provider "
7572 + cpi.name);
7573 return null;
7574 }
7575 cpr = new ContentProviderRecord(cpi, ai);
7576 } catch (RemoteException ex) {
7577 // pm is in same process, this will never happen.
7578 }
7579 }
7580
7581 if (r != null && cpr.canRunHere(r)) {
7582 // If this is a multiprocess provider, then just return its
7583 // info and allow the caller to instantiate it. Only do
7584 // this if the provider is the same user as the caller's
7585 // process, or can run as root (so can be in any process).
7586 return cpr;
7587 }
7588
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007589 if (DEBUG_PROVIDER) {
7590 RuntimeException e = new RuntimeException("here");
7591 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7592 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007593 }
7594
7595 // This is single process, and our app is now connecting to it.
7596 // See if we are already in the process of launching this
7597 // provider.
7598 final int N = mLaunchingProviders.size();
7599 int i;
7600 for (i=0; i<N; i++) {
7601 if (mLaunchingProviders.get(i) == cpr) {
7602 break;
7603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007604 }
7605
7606 // If the provider is not already being launched, then get it
7607 // started.
7608 if (i >= N) {
7609 final long origId = Binder.clearCallingIdentity();
7610 ProcessRecord proc = startProcessLocked(cpi.processName,
7611 cpr.appInfo, false, 0, "content provider",
7612 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007613 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007614 if (proc == null) {
7615 Log.w(TAG, "Unable to launch app "
7616 + cpi.applicationInfo.packageName + "/"
7617 + cpi.applicationInfo.uid + " for provider "
7618 + name + ": process is bad");
7619 return null;
7620 }
7621 cpr.launchingApp = proc;
7622 mLaunchingProviders.add(cpr);
7623 Binder.restoreCallingIdentity(origId);
7624 }
7625
7626 // Make sure the provider is published (the same provider class
7627 // may be published under multiple names).
7628 if (firstClass) {
7629 mProvidersByClass.put(cpi.name, cpr);
7630 }
7631 mProvidersByName.put(name, cpr);
7632
7633 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007634 if (DEBUG_PROVIDER) Log.v(TAG,
7635 "Adding provider requested by "
7636 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007637 + cpr.info.processName);
7638 Integer cnt = r.conProviders.get(cpr);
7639 if (cnt == null) {
7640 r.conProviders.put(cpr, new Integer(1));
7641 } else {
7642 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007644 cpr.clients.add(r);
7645 } else {
7646 cpr.externals++;
7647 }
7648 }
7649 }
7650
7651 // Wait for the provider to be published...
7652 synchronized (cpr) {
7653 while (cpr.provider == null) {
7654 if (cpr.launchingApp == null) {
7655 Log.w(TAG, "Unable to launch app "
7656 + cpi.applicationInfo.packageName + "/"
7657 + cpi.applicationInfo.uid + " for provider "
7658 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007659 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007660 cpi.applicationInfo.packageName,
7661 cpi.applicationInfo.uid, name);
7662 return null;
7663 }
7664 try {
7665 cpr.wait();
7666 } catch (InterruptedException ex) {
7667 }
7668 }
7669 }
7670 return cpr;
7671 }
7672
7673 public final ContentProviderHolder getContentProvider(
7674 IApplicationThread caller, String name) {
7675 if (caller == null) {
7676 String msg = "null IApplicationThread when getting content provider "
7677 + name;
7678 Log.w(TAG, msg);
7679 throw new SecurityException(msg);
7680 }
7681
7682 return getContentProviderImpl(caller, name);
7683 }
7684
7685 private ContentProviderHolder getContentProviderExternal(String name) {
7686 return getContentProviderImpl(null, name);
7687 }
7688
7689 /**
7690 * Drop a content provider from a ProcessRecord's bookkeeping
7691 * @param cpr
7692 */
7693 public void removeContentProvider(IApplicationThread caller, String name) {
7694 synchronized (this) {
7695 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7696 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007697 // remove from mProvidersByClass
7698 if (DEBUG_PROVIDER) Log.v(TAG, name +
7699 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007700 return;
7701 }
7702 final ProcessRecord r = getRecordForAppLocked(caller);
7703 if (r == null) {
7704 throw new SecurityException(
7705 "Unable to find app for caller " + caller +
7706 " when removing content provider " + name);
7707 }
7708 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007709 ContentProviderRecord localCpr = (ContentProviderRecord)
7710 mProvidersByClass.get(cpr.info.name);
7711 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7712 + r.info.processName + " from process "
7713 + localCpr.appInfo.processName);
7714 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007715 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007716 Log.w(TAG, "removeContentProvider called on local provider: "
7717 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007718 return;
7719 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007720 Integer cnt = r.conProviders.get(localCpr);
7721 if (cnt == null || cnt.intValue() <= 1) {
7722 localCpr.clients.remove(r);
7723 r.conProviders.remove(localCpr);
7724 } else {
7725 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7726 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007727 }
7728 updateOomAdjLocked();
7729 }
7730 }
7731
7732 private void removeContentProviderExternal(String name) {
7733 synchronized (this) {
7734 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7735 if(cpr == null) {
7736 //remove from mProvidersByClass
7737 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7738 return;
7739 }
7740
7741 //update content provider record entry info
7742 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7743 localCpr.externals--;
7744 if (localCpr.externals < 0) {
7745 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7746 }
7747 updateOomAdjLocked();
7748 }
7749 }
7750
7751 public final void publishContentProviders(IApplicationThread caller,
7752 List<ContentProviderHolder> providers) {
7753 if (providers == null) {
7754 return;
7755 }
7756
7757 synchronized(this) {
7758 final ProcessRecord r = getRecordForAppLocked(caller);
7759 if (r == null) {
7760 throw new SecurityException(
7761 "Unable to find app for caller " + caller
7762 + " (pid=" + Binder.getCallingPid()
7763 + ") when publishing content providers");
7764 }
7765
7766 final long origId = Binder.clearCallingIdentity();
7767
7768 final int N = providers.size();
7769 for (int i=0; i<N; i++) {
7770 ContentProviderHolder src = providers.get(i);
7771 if (src == null || src.info == null || src.provider == null) {
7772 continue;
7773 }
7774 ContentProviderRecord dst =
7775 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7776 if (dst != null) {
7777 mProvidersByClass.put(dst.info.name, dst);
7778 String names[] = dst.info.authority.split(";");
7779 for (int j = 0; j < names.length; j++) {
7780 mProvidersByName.put(names[j], dst);
7781 }
7782
7783 int NL = mLaunchingProviders.size();
7784 int j;
7785 for (j=0; j<NL; j++) {
7786 if (mLaunchingProviders.get(j) == dst) {
7787 mLaunchingProviders.remove(j);
7788 j--;
7789 NL--;
7790 }
7791 }
7792 synchronized (dst) {
7793 dst.provider = src.provider;
7794 dst.app = r;
7795 dst.notifyAll();
7796 }
7797 updateOomAdjLocked(r);
7798 }
7799 }
7800
7801 Binder.restoreCallingIdentity(origId);
7802 }
7803 }
7804
7805 public static final void installSystemProviders() {
7806 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7807 List providers = mSelf.generateApplicationProvidersLocked(app);
7808 mSystemThread.installSystemProviders(providers);
7809 }
7810
7811 // =========================================================
7812 // GLOBAL MANAGEMENT
7813 // =========================================================
7814
7815 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7816 ApplicationInfo info, String customProcess) {
7817 String proc = customProcess != null ? customProcess : info.processName;
7818 BatteryStatsImpl.Uid.Proc ps = null;
7819 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7820 synchronized (stats) {
7821 ps = stats.getProcessStatsLocked(info.uid, proc);
7822 }
7823 return new ProcessRecord(ps, thread, info, proc);
7824 }
7825
7826 final ProcessRecord addAppLocked(ApplicationInfo info) {
7827 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7828
7829 if (app == null) {
7830 app = newProcessRecordLocked(null, info, null);
7831 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007832 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007833 }
7834
7835 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7836 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7837 app.persistent = true;
7838 app.maxAdj = CORE_SERVER_ADJ;
7839 }
7840 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7841 mPersistentStartingProcesses.add(app);
7842 startProcessLocked(app, "added application", app.processName);
7843 }
7844
7845 return app;
7846 }
7847
7848 public void unhandledBack() {
7849 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7850 "unhandledBack()");
7851
7852 synchronized(this) {
7853 int count = mHistory.size();
Dianne Hackborn03abb812010-01-04 18:43:19 -08007854 if (DEBUG_SWITCH) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007855 TAG, "Performing unhandledBack(): stack size = " + count);
7856 if (count > 1) {
7857 final long origId = Binder.clearCallingIdentity();
7858 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7859 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7860 Binder.restoreCallingIdentity(origId);
7861 }
7862 }
7863 }
7864
7865 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7866 String name = uri.getAuthority();
7867 ContentProviderHolder cph = getContentProviderExternal(name);
7868 ParcelFileDescriptor pfd = null;
7869 if (cph != null) {
7870 // We record the binder invoker's uid in thread-local storage before
7871 // going to the content provider to open the file. Later, in the code
7872 // that handles all permissions checks, we look for this uid and use
7873 // that rather than the Activity Manager's own uid. The effect is that
7874 // we do the check against the caller's permissions even though it looks
7875 // to the content provider like the Activity Manager itself is making
7876 // the request.
7877 sCallerIdentity.set(new Identity(
7878 Binder.getCallingPid(), Binder.getCallingUid()));
7879 try {
7880 pfd = cph.provider.openFile(uri, "r");
7881 } catch (FileNotFoundException e) {
7882 // do nothing; pfd will be returned null
7883 } finally {
7884 // Ensure that whatever happens, we clean up the identity state
7885 sCallerIdentity.remove();
7886 }
7887
7888 // We've got the fd now, so we're done with the provider.
7889 removeContentProviderExternal(name);
7890 } else {
7891 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7892 }
7893 return pfd;
7894 }
7895
7896 public void goingToSleep() {
7897 synchronized(this) {
7898 mSleeping = true;
7899 mWindowManager.setEventDispatching(false);
7900
7901 if (mResumedActivity != null) {
7902 pauseIfSleepingLocked();
7903 } else {
7904 Log.w(TAG, "goingToSleep with no resumed activity!");
7905 }
7906 }
7907 }
7908
Dianne Hackborn55280a92009-05-07 15:53:46 -07007909 public boolean shutdown(int timeout) {
7910 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7911 != PackageManager.PERMISSION_GRANTED) {
7912 throw new SecurityException("Requires permission "
7913 + android.Manifest.permission.SHUTDOWN);
7914 }
7915
7916 boolean timedout = false;
7917
7918 synchronized(this) {
7919 mShuttingDown = true;
7920 mWindowManager.setEventDispatching(false);
7921
7922 if (mResumedActivity != null) {
7923 pauseIfSleepingLocked();
7924 final long endTime = System.currentTimeMillis() + timeout;
7925 while (mResumedActivity != null || mPausingActivity != null) {
7926 long delay = endTime - System.currentTimeMillis();
7927 if (delay <= 0) {
7928 Log.w(TAG, "Activity manager shutdown timed out");
7929 timedout = true;
7930 break;
7931 }
7932 try {
7933 this.wait();
7934 } catch (InterruptedException e) {
7935 }
7936 }
7937 }
7938 }
7939
7940 mUsageStatsService.shutdown();
7941 mBatteryStatsService.shutdown();
7942
7943 return timedout;
7944 }
7945
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007946 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007947 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007948 if (!mGoingToSleep.isHeld()) {
7949 mGoingToSleep.acquire();
7950 if (mLaunchingActivity.isHeld()) {
7951 mLaunchingActivity.release();
7952 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7953 }
7954 }
7955
7956 // If we are not currently pausing an activity, get the current
7957 // one to pause. If we are pausing one, we will just let that stuff
7958 // run and release the wake lock when all done.
7959 if (mPausingActivity == null) {
7960 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7961 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7962 startPausingLocked(false, true);
7963 }
7964 }
7965 }
7966
7967 public void wakingUp() {
7968 synchronized(this) {
7969 if (mGoingToSleep.isHeld()) {
7970 mGoingToSleep.release();
7971 }
7972 mWindowManager.setEventDispatching(true);
7973 mSleeping = false;
7974 resumeTopActivityLocked(null);
7975 }
7976 }
7977
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007978 public void stopAppSwitches() {
7979 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7980 != PackageManager.PERMISSION_GRANTED) {
7981 throw new SecurityException("Requires permission "
7982 + android.Manifest.permission.STOP_APP_SWITCHES);
7983 }
7984
7985 synchronized(this) {
7986 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7987 + APP_SWITCH_DELAY_TIME;
7988 mDidAppSwitch = false;
7989 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7990 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7991 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7992 }
7993 }
7994
7995 public void resumeAppSwitches() {
7996 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7997 != PackageManager.PERMISSION_GRANTED) {
7998 throw new SecurityException("Requires permission "
7999 + android.Manifest.permission.STOP_APP_SWITCHES);
8000 }
8001
8002 synchronized(this) {
8003 // Note that we don't execute any pending app switches... we will
8004 // let those wait until either the timeout, or the next start
8005 // activity request.
8006 mAppSwitchesAllowedTime = 0;
8007 }
8008 }
8009
8010 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8011 String name) {
8012 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8013 return true;
8014 }
8015
8016 final int perm = checkComponentPermission(
8017 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8018 callingUid, -1);
8019 if (perm == PackageManager.PERMISSION_GRANTED) {
8020 return true;
8021 }
8022
8023 Log.w(TAG, name + " request from " + callingUid + " stopped");
8024 return false;
8025 }
8026
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008027 public void setDebugApp(String packageName, boolean waitForDebugger,
8028 boolean persistent) {
8029 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8030 "setDebugApp()");
8031
8032 // Note that this is not really thread safe if there are multiple
8033 // callers into it at the same time, but that's not a situation we
8034 // care about.
8035 if (persistent) {
8036 final ContentResolver resolver = mContext.getContentResolver();
8037 Settings.System.putString(
8038 resolver, Settings.System.DEBUG_APP,
8039 packageName);
8040 Settings.System.putInt(
8041 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8042 waitForDebugger ? 1 : 0);
8043 }
8044
8045 synchronized (this) {
8046 if (!persistent) {
8047 mOrigDebugApp = mDebugApp;
8048 mOrigWaitForDebugger = mWaitForDebugger;
8049 }
8050 mDebugApp = packageName;
8051 mWaitForDebugger = waitForDebugger;
8052 mDebugTransient = !persistent;
8053 if (packageName != null) {
8054 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn03abb812010-01-04 18:43:19 -08008055 forceStopPackageLocked(packageName, -1, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008056 Binder.restoreCallingIdentity(origId);
8057 }
8058 }
8059 }
8060
8061 public void setAlwaysFinish(boolean enabled) {
8062 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8063 "setAlwaysFinish()");
8064
8065 Settings.System.putInt(
8066 mContext.getContentResolver(),
8067 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8068
8069 synchronized (this) {
8070 mAlwaysFinishActivities = enabled;
8071 }
8072 }
8073
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008074 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008075 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008076 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008077 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008078 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008079 }
8080 }
8081
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008082 public void registerActivityWatcher(IActivityWatcher watcher) {
8083 mWatchers.register(watcher);
8084 }
8085
8086 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8087 mWatchers.unregister(watcher);
8088 }
8089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008090 public final void enterSafeMode() {
8091 synchronized(this) {
8092 // It only makes sense to do this before the system is ready
8093 // and started launching other packages.
8094 if (!mSystemReady) {
8095 try {
8096 ActivityThread.getPackageManager().enterSafeMode();
8097 } catch (RemoteException e) {
8098 }
8099
8100 View v = LayoutInflater.from(mContext).inflate(
8101 com.android.internal.R.layout.safe_mode, null);
8102 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8103 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8104 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8105 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8106 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8107 lp.format = v.getBackground().getOpacity();
8108 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8109 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8110 ((WindowManager)mContext.getSystemService(
8111 Context.WINDOW_SERVICE)).addView(v, lp);
8112 }
8113 }
8114 }
8115
8116 public void noteWakeupAlarm(IIntentSender sender) {
8117 if (!(sender instanceof PendingIntentRecord)) {
8118 return;
8119 }
8120 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8121 synchronized (stats) {
8122 if (mBatteryStatsService.isOnBattery()) {
8123 mBatteryStatsService.enforceCallingPermission();
8124 PendingIntentRecord rec = (PendingIntentRecord)sender;
8125 int MY_UID = Binder.getCallingUid();
8126 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8127 BatteryStatsImpl.Uid.Pkg pkg =
8128 stats.getPackageStatsLocked(uid, rec.key.packageName);
8129 pkg.incWakeupsLocked();
8130 }
8131 }
8132 }
8133
8134 public boolean killPidsForMemory(int[] pids) {
8135 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8136 throw new SecurityException("killPidsForMemory only available to the system");
8137 }
8138
8139 // XXX Note: don't acquire main activity lock here, because the window
8140 // manager calls in with its locks held.
8141
8142 boolean killed = false;
8143 synchronized (mPidsSelfLocked) {
8144 int[] types = new int[pids.length];
8145 int worstType = 0;
8146 for (int i=0; i<pids.length; i++) {
8147 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8148 if (proc != null) {
8149 int type = proc.setAdj;
8150 types[i] = type;
8151 if (type > worstType) {
8152 worstType = type;
8153 }
8154 }
8155 }
8156
8157 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8158 // then constrain it so we will kill all hidden procs.
8159 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8160 worstType = HIDDEN_APP_MIN_ADJ;
8161 }
8162 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8163 for (int i=0; i<pids.length; i++) {
8164 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8165 if (proc == null) {
8166 continue;
8167 }
8168 int adj = proc.setAdj;
8169 if (adj >= worstType) {
8170 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8171 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008172 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008173 proc.processName, adj);
8174 killed = true;
8175 Process.killProcess(pids[i]);
8176 }
8177 }
8178 }
8179 return killed;
8180 }
8181
8182 public void reportPss(IApplicationThread caller, int pss) {
8183 Watchdog.PssRequestor req;
8184 String name;
8185 ProcessRecord callerApp;
8186 synchronized (this) {
8187 if (caller == null) {
8188 return;
8189 }
8190 callerApp = getRecordForAppLocked(caller);
8191 if (callerApp == null) {
8192 return;
8193 }
8194 callerApp.lastPss = pss;
8195 req = callerApp;
8196 name = callerApp.processName;
8197 }
8198 Watchdog.getInstance().reportPss(req, name, pss);
8199 if (!callerApp.persistent) {
8200 removeRequestedPss(callerApp);
8201 }
8202 }
8203
8204 public void requestPss(Runnable completeCallback) {
8205 ArrayList<ProcessRecord> procs;
8206 synchronized (this) {
8207 mRequestPssCallback = completeCallback;
8208 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008209 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8210 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008211 if (!proc.persistent) {
8212 mRequestPssList.add(proc);
8213 }
8214 }
8215 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8216 }
8217
8218 int oldPri = Process.getThreadPriority(Process.myTid());
8219 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8220 for (int i=procs.size()-1; i>=0; i--) {
8221 ProcessRecord proc = procs.get(i);
8222 proc.lastPss = 0;
8223 proc.requestPss();
8224 }
8225 Process.setThreadPriority(oldPri);
8226 }
8227
8228 void removeRequestedPss(ProcessRecord proc) {
8229 Runnable callback = null;
8230 synchronized (this) {
8231 if (mRequestPssList.remove(proc)) {
8232 if (mRequestPssList.size() == 0) {
8233 callback = mRequestPssCallback;
8234 mRequestPssCallback = null;
8235 }
8236 }
8237 }
8238
8239 if (callback != null) {
8240 callback.run();
8241 }
8242 }
8243
8244 public void collectPss(Watchdog.PssStats stats) {
8245 stats.mEmptyPss = 0;
8246 stats.mEmptyCount = 0;
8247 stats.mBackgroundPss = 0;
8248 stats.mBackgroundCount = 0;
8249 stats.mServicePss = 0;
8250 stats.mServiceCount = 0;
8251 stats.mVisiblePss = 0;
8252 stats.mVisibleCount = 0;
8253 stats.mForegroundPss = 0;
8254 stats.mForegroundCount = 0;
8255 stats.mNoPssCount = 0;
8256 synchronized (this) {
8257 int i;
8258 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8259 ? mProcDeaths.length : stats.mProcDeaths.length;
8260 int aggr = 0;
8261 for (i=0; i<NPD; i++) {
8262 aggr += mProcDeaths[i];
8263 stats.mProcDeaths[i] = aggr;
8264 }
8265 while (i<stats.mProcDeaths.length) {
8266 stats.mProcDeaths[i] = 0;
8267 i++;
8268 }
8269
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008270 for (i=mLruProcesses.size()-1; i>=0; i--) {
8271 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008272 if (proc.persistent) {
8273 continue;
8274 }
8275 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8276 if (proc.lastPss == 0) {
8277 stats.mNoPssCount++;
8278 continue;
8279 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008280 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8281 if (proc.empty) {
8282 stats.mEmptyPss += proc.lastPss;
8283 stats.mEmptyCount++;
8284 } else {
8285 stats.mBackgroundPss += proc.lastPss;
8286 stats.mBackgroundCount++;
8287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008288 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8289 stats.mVisiblePss += proc.lastPss;
8290 stats.mVisibleCount++;
8291 } else {
8292 stats.mForegroundPss += proc.lastPss;
8293 stats.mForegroundCount++;
8294 }
8295 }
8296 }
8297 }
8298
8299 public final void startRunning(String pkg, String cls, String action,
8300 String data) {
8301 synchronized(this) {
8302 if (mStartRunning) {
8303 return;
8304 }
8305 mStartRunning = true;
8306 mTopComponent = pkg != null && cls != null
8307 ? new ComponentName(pkg, cls) : null;
8308 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8309 mTopData = data;
8310 if (!mSystemReady) {
8311 return;
8312 }
8313 }
8314
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008315 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008316 }
8317
8318 private void retrieveSettings() {
8319 final ContentResolver resolver = mContext.getContentResolver();
8320 String debugApp = Settings.System.getString(
8321 resolver, Settings.System.DEBUG_APP);
8322 boolean waitForDebugger = Settings.System.getInt(
8323 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8324 boolean alwaysFinishActivities = Settings.System.getInt(
8325 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8326
8327 Configuration configuration = new Configuration();
8328 Settings.System.getConfiguration(resolver, configuration);
8329
8330 synchronized (this) {
8331 mDebugApp = mOrigDebugApp = debugApp;
8332 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8333 mAlwaysFinishActivities = alwaysFinishActivities;
8334 // This happens before any activities are started, so we can
8335 // change mConfiguration in-place.
8336 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008337 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008338 }
8339 }
8340
8341 public boolean testIsSystemReady() {
8342 // no need to synchronize(this) just to read & return the value
8343 return mSystemReady;
8344 }
8345
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008346 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008347 // In the simulator, startRunning will never have been called, which
8348 // normally sets a few crucial variables. Do it here instead.
8349 if (!Process.supportsProcesses()) {
8350 mStartRunning = true;
8351 mTopAction = Intent.ACTION_MAIN;
8352 }
8353
8354 synchronized(this) {
8355 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008356 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008357 return;
8358 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008359
8360 // Check to see if there are any update receivers to run.
8361 if (!mDidUpdate) {
8362 if (mWaitingUpdate) {
8363 return;
8364 }
8365 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8366 List<ResolveInfo> ris = null;
8367 try {
8368 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8369 intent, null, 0);
8370 } catch (RemoteException e) {
8371 }
8372 if (ris != null) {
8373 for (int i=ris.size()-1; i>=0; i--) {
8374 if ((ris.get(i).activityInfo.applicationInfo.flags
8375 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8376 ris.remove(i);
8377 }
8378 }
8379 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8380 for (int i=0; i<ris.size(); i++) {
8381 ActivityInfo ai = ris.get(i).activityInfo;
8382 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8383 IIntentReceiver finisher = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -08008384 if (i == ris.size()-1) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008385 finisher = new IIntentReceiver.Stub() {
8386 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008387 String data, Bundle extras, boolean ordered,
8388 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008389 throws RemoteException {
8390 synchronized (ActivityManagerService.this) {
8391 mDidUpdate = true;
8392 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008393 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008394 }
8395 };
8396 }
8397 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8398 broadcastIntentLocked(null, null, intent, null, finisher,
8399 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornd6847842010-01-12 18:14:19 -08008400 if (finisher != null) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008401 mWaitingUpdate = true;
8402 }
8403 }
8404 }
8405 if (mWaitingUpdate) {
8406 return;
8407 }
8408 mDidUpdate = true;
8409 }
8410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008411 mSystemReady = true;
8412 if (!mStartRunning) {
8413 return;
8414 }
8415 }
8416
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008417 ArrayList<ProcessRecord> procsToKill = null;
8418 synchronized(mPidsSelfLocked) {
8419 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8420 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8421 if (!isAllowedWhileBooting(proc.info)){
8422 if (procsToKill == null) {
8423 procsToKill = new ArrayList<ProcessRecord>();
8424 }
8425 procsToKill.add(proc);
8426 }
8427 }
8428 }
8429
8430 if (procsToKill != null) {
8431 synchronized(this) {
8432 for (int i=procsToKill.size()-1; i>=0; i--) {
8433 ProcessRecord proc = procsToKill.get(i);
8434 Log.i(TAG, "Removing system update proc: " + proc);
8435 removeProcessLocked(proc, true);
8436 }
8437 }
8438 }
8439
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008440 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008441 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008442 SystemClock.uptimeMillis());
8443
8444 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008445 // Make sure we have no pre-ready processes sitting around.
8446
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008447 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8448 ResolveInfo ri = mContext.getPackageManager()
8449 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008450 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008451 CharSequence errorMsg = null;
8452 if (ri != null) {
8453 ActivityInfo ai = ri.activityInfo;
8454 ApplicationInfo app = ai.applicationInfo;
8455 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8456 mTopAction = Intent.ACTION_FACTORY_TEST;
8457 mTopData = null;
8458 mTopComponent = new ComponentName(app.packageName,
8459 ai.name);
8460 } else {
8461 errorMsg = mContext.getResources().getText(
8462 com.android.internal.R.string.factorytest_not_system);
8463 }
8464 } else {
8465 errorMsg = mContext.getResources().getText(
8466 com.android.internal.R.string.factorytest_no_action);
8467 }
8468 if (errorMsg != null) {
8469 mTopAction = null;
8470 mTopData = null;
8471 mTopComponent = null;
8472 Message msg = Message.obtain();
8473 msg.what = SHOW_FACTORY_ERROR_MSG;
8474 msg.getData().putCharSequence("msg", errorMsg);
8475 mHandler.sendMessage(msg);
8476 }
8477 }
8478 }
8479
8480 retrieveSettings();
8481
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008482 if (goingCallback != null) goingCallback.run();
8483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008484 synchronized (this) {
8485 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8486 try {
8487 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008488 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008489 if (apps != null) {
8490 int N = apps.size();
8491 int i;
8492 for (i=0; i<N; i++) {
8493 ApplicationInfo info
8494 = (ApplicationInfo)apps.get(i);
8495 if (info != null &&
8496 !info.packageName.equals("android")) {
8497 addAppLocked(info);
8498 }
8499 }
8500 }
8501 } catch (RemoteException ex) {
8502 // pm is in same process, this will never happen.
8503 }
8504 }
8505
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008506 // Start up initial activity.
8507 mBooting = true;
8508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008509 try {
8510 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8511 Message msg = Message.obtain();
8512 msg.what = SHOW_UID_ERROR_MSG;
8513 mHandler.sendMessage(msg);
8514 }
8515 } catch (RemoteException e) {
8516 }
8517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008518 resumeTopActivityLocked(null);
8519 }
8520 }
8521
Dan Egnorb7f03672009-12-09 16:22:32 -08008522 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008523 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008524 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008525 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008526 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008527 startAppProblemLocked(app);
8528 app.stopFreezingAllLocked();
8529 return handleAppCrashLocked(app);
8530 }
8531
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008532 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Doug Zongker43866e02010-01-07 12:09:54 -08008533 // check if error reporting is enabled in secure settings
8534 int enabled = Settings.Secure.getInt(mContext.getContentResolver(),
8535 Settings.Secure.SEND_ACTION_APP_ERROR, 0);
Jacek Surazskia2339432009-09-18 15:01:26 +02008536 if (enabled == 0) {
8537 return null;
8538 }
8539
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008540 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008541
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008542 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008543 // look for receiver in the installer package
8544 String candidate = pm.getInstallerPackageName(app.info.packageName);
8545 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8546 if (result != null) {
8547 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008548 }
8549
Jacek Surazski82a73df2009-06-17 14:33:18 +02008550 // if the error app is on the system image, look for system apps
8551 // error receiver
8552 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8553 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8554 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8555 if (result != null) {
8556 return result;
8557 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008558 }
8559
Jacek Surazski82a73df2009-06-17 14:33:18 +02008560 // if there is a default receiver, try that
8561 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8562 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008563 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008564 // should not happen
8565 Log.e(TAG, "error talking to PackageManager", e);
8566 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008567 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008568 }
8569
8570 /**
8571 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8572 *
8573 * @param pm PackageManager isntance
8574 * @param errorPackage package which caused the error
8575 * @param receiverPackage candidate package to receive the error
8576 * @return activity component within receiverPackage which handles
8577 * ACTION_APP_ERROR, or null if not found
8578 */
8579 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8580 String receiverPackage) throws RemoteException {
8581 if (receiverPackage == null || receiverPackage.length() == 0) {
8582 return null;
8583 }
8584
8585 // break the loop if it's the error report receiver package that crashed
8586 if (receiverPackage.equals(errorPackage)) {
8587 return null;
8588 }
8589
8590 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8591 intent.setPackage(receiverPackage);
8592 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8593 if (info == null || info.activityInfo == null) {
8594 return null;
8595 }
8596 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008597 }
8598
Dan Egnorb7f03672009-12-09 16:22:32 -08008599 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008600 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008601 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008602 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008603 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8604 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008605 startAppProblemLocked(app);
8606 app.stopFreezingAllLocked();
8607 }
8608
8609 /**
8610 * Generate a process error record, suitable for attachment to a ProcessRecord.
8611 *
8612 * @param app The ProcessRecord in which the error occurred.
8613 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8614 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008615 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008616 * @param shortMsg Short message describing the crash.
8617 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008618 * @param stackTrace Full crash stack trace, may be null.
8619 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008620 * @return Returns a fully-formed AppErrorStateInfo record.
8621 */
8622 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008623 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008624 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008625
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008626 report.condition = condition;
8627 report.processName = app.processName;
8628 report.pid = app.pid;
8629 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008630 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008631 report.shortMsg = shortMsg;
8632 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008633 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008634
8635 return report;
8636 }
8637
Dan Egnor42471dd2010-01-07 17:25:22 -08008638 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008639 synchronized (this) {
8640 app.crashing = false;
8641 app.crashingReport = null;
8642 app.notResponding = false;
8643 app.notRespondingReport = null;
8644 if (app.anrDialog == fromDialog) {
8645 app.anrDialog = null;
8646 }
8647 if (app.waitDialog == fromDialog) {
8648 app.waitDialog = null;
8649 }
8650 if (app.pid > 0 && app.pid != MY_PID) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008651 handleAppCrashLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008652 Log.i(ActivityManagerService.TAG, "Killing process "
8653 + app.processName
8654 + " (pid=" + app.pid + ") at user's request");
8655 Process.killProcess(app.pid);
8656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008657 }
8658 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008659
Dan Egnorb7f03672009-12-09 16:22:32 -08008660 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008661 long now = SystemClock.uptimeMillis();
8662
8663 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8664 app.info.uid);
8665 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8666 // This process loses!
8667 Log.w(TAG, "Process " + app.info.processName
8668 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008669 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008670 app.info.processName, app.info.uid);
8671 killServicesLocked(app, false);
8672 for (int i=mHistory.size()-1; i>=0; i--) {
8673 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8674 if (r.app == app) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08008675 Log.w(TAG, " Force finishing activity "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008676 + r.intent.getComponent().flattenToShortString());
8677 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8678 }
8679 }
8680 if (!app.persistent) {
8681 // We don't want to start this process again until the user
8682 // explicitly does so... but for persistent process, we really
8683 // need to keep it running. If a persistent process is actually
8684 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008685 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008686 app.info.processName);
8687 mBadProcesses.put(app.info.processName, app.info.uid, now);
8688 app.bad = true;
8689 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8690 app.removed = true;
8691 removeProcessLocked(app, false);
8692 return false;
8693 }
8694 }
8695
8696 // Bump up the crash count of any services currently running in the proc.
8697 if (app.services.size() != 0) {
8698 // Any services running in the application need to be placed
8699 // back in the pending list.
8700 Iterator it = app.services.iterator();
8701 while (it.hasNext()) {
8702 ServiceRecord sr = (ServiceRecord)it.next();
8703 sr.crashCount++;
8704 }
8705 }
8706
8707 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8708 return true;
8709 }
8710
8711 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008712 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008713 skipCurrentReceiverLocked(app);
8714 }
8715
8716 void skipCurrentReceiverLocked(ProcessRecord app) {
8717 boolean reschedule = false;
8718 BroadcastRecord r = app.curReceiver;
8719 if (r != null) {
8720 // The current broadcast is waiting for this app's receiver
8721 // to be finished. Looks like that's not going to happen, so
8722 // let the broadcast continue.
8723 logBroadcastReceiverDiscard(r);
8724 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8725 r.resultExtras, r.resultAbort, true);
8726 reschedule = true;
8727 }
8728 r = mPendingBroadcast;
8729 if (r != null && r.curApp == app) {
8730 if (DEBUG_BROADCAST) Log.v(TAG,
8731 "skip & discard pending app " + r);
8732 logBroadcastReceiverDiscard(r);
8733 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8734 r.resultExtras, r.resultAbort, true);
8735 reschedule = true;
8736 }
8737 if (reschedule) {
8738 scheduleBroadcastsLocked();
8739 }
8740 }
8741
Dan Egnor60d87622009-12-16 16:32:58 -08008742 /**
8743 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8744 * The application process will exit immediately after this call returns.
8745 * @param app object of the crashing app, null for the system server
8746 * @param crashInfo describing the exception
8747 */
8748 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8749 ProcessRecord r = findAppProcess(app);
8750
8751 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8752 app == null ? "system" : (r == null ? "unknown" : r.processName),
8753 crashInfo.exceptionClassName,
8754 crashInfo.exceptionMessage,
8755 crashInfo.throwFileName,
8756 crashInfo.throwLineNumber);
8757
Dan Egnor42471dd2010-01-07 17:25:22 -08008758 addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008759
8760 crashApplication(r, crashInfo);
8761 }
8762
8763 /**
8764 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8765 * @param app object of the crashing app, null for the system server
8766 * @param tag reported by the caller
8767 * @param crashInfo describing the context of the error
8768 * @return true if the process should exit immediately (WTF is fatal)
8769 */
8770 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008771 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008772 ProcessRecord r = findAppProcess(app);
8773
8774 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8775 app == null ? "system" : (r == null ? "unknown" : r.processName),
8776 tag, crashInfo.exceptionMessage);
8777
Dan Egnor42471dd2010-01-07 17:25:22 -08008778 addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008779
Doug Zongker43866e02010-01-07 12:09:54 -08008780 if (Settings.Secure.getInt(mContext.getContentResolver(),
8781 Settings.Secure.WTF_IS_FATAL, 0) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008782 crashApplication(r, crashInfo);
8783 return true;
8784 } else {
8785 return false;
8786 }
8787 }
8788
8789 /**
8790 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8791 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8792 */
8793 private ProcessRecord findAppProcess(IBinder app) {
8794 if (app == null) {
8795 return null;
8796 }
8797
8798 synchronized (this) {
8799 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8800 final int NA = apps.size();
8801 for (int ia=0; ia<NA; ia++) {
8802 ProcessRecord p = apps.valueAt(ia);
8803 if (p.thread != null && p.thread.asBinder() == app) {
8804 return p;
8805 }
8806 }
8807 }
8808
8809 Log.w(TAG, "Can't find mystery application: " + app);
8810 return null;
8811 }
8812 }
8813
8814 /**
Dan Egnor42471dd2010-01-07 17:25:22 -08008815 * Write a description of an error (crash, WTF, ANR) to the drop box.
Dan Egnor60d87622009-12-16 16:32:58 -08008816 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
Dan Egnor42471dd2010-01-07 17:25:22 -08008817 * @param process which caused the error, null means the system server
8818 * @param activity which triggered the error, null if unknown
8819 * @param parent activity related to the error, null if unknown
8820 * @param subject line related to the error, null if absent
8821 * @param report in long form describing the error, null if absent
8822 * @param logFile to include in the report, null if none
8823 * @param crashInfo giving an application stack trace, null if absent
Dan Egnor60d87622009-12-16 16:32:58 -08008824 */
Dan Egnor42471dd2010-01-07 17:25:22 -08008825 private void addErrorToDropBox(String eventType,
8826 ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
8827 String subject, String report, File logFile,
Dan Egnor60d87622009-12-16 16:32:58 -08008828 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008829 String dropboxTag;
8830 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008831 dropboxTag = "system_server_" + eventType;
Dan Egnor42471dd2010-01-07 17:25:22 -08008832 } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008833 dropboxTag = "system_app_" + eventType;
8834 } else {
8835 dropboxTag = "data_app_" + eventType;
8836 }
8837
8838 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8839 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8840 StringBuilder sb = new StringBuilder(1024);
Dan Egnor42471dd2010-01-07 17:25:22 -08008841 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008842 sb.append("Process: system_server\n");
8843 } else {
Dan Egnor42471dd2010-01-07 17:25:22 -08008844 sb.append("Process: ").append(process.processName).append("\n");
8845 }
8846 if (activity != null) {
8847 sb.append("Activity: ").append(activity.shortComponentName).append("\n");
8848 }
8849 if (parent != null && parent.app != null && parent.app.pid != process.pid) {
8850 sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
8851 }
8852 if (parent != null && parent != activity) {
8853 sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
8854 }
8855 if (subject != null) {
8856 sb.append("Subject: ").append(subject).append("\n");
8857 }
8858 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8859 sb.append("\n");
8860 if (report != null) {
8861 sb.append(report);
8862 }
8863 if (logFile != null) {
8864 try {
8865 sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
8866 } catch (IOException e) {
8867 Log.e(TAG, "Error reading " + logFile, e);
Dan Egnor60d87622009-12-16 16:32:58 -08008868 }
8869 }
Dan Egnor60d87622009-12-16 16:32:58 -08008870 if (crashInfo != null && crashInfo.stackTrace != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008871 sb.append(crashInfo.stackTrace);
Dan Egnor60d87622009-12-16 16:32:58 -08008872 }
8873 dbox.addText(dropboxTag, sb.toString());
8874 }
8875 }
8876
8877 /**
8878 * Bring up the "unexpected error" dialog box for a crashing app.
8879 * Deal with edge cases (intercepts from instrumented applications,
8880 * ActivityController, error intent receivers, that sort of thing).
8881 * @param r the application crashing
8882 * @param crashInfo describing the failure
8883 */
8884 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008885 long timeMillis = System.currentTimeMillis();
8886 String shortMsg = crashInfo.exceptionClassName;
8887 String longMsg = crashInfo.exceptionMessage;
8888 String stackTrace = crashInfo.stackTrace;
8889 if (shortMsg != null && longMsg != null) {
8890 longMsg = shortMsg + ": " + longMsg;
8891 } else if (shortMsg != null) {
8892 longMsg = shortMsg;
8893 }
8894
Dan Egnor60d87622009-12-16 16:32:58 -08008895 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008896 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008897 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008898 try {
8899 String name = r != null ? r.processName : null;
8900 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008901 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008902 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008903 Log.w(TAG, "Force-killing crashed app " + name
8904 + " at watcher's request");
8905 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008906 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008907 }
8908 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008909 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008910 }
8911 }
8912
8913 final long origId = Binder.clearCallingIdentity();
8914
8915 // If this process is running instrumentation, finish it.
8916 if (r != null && r.instrumentationClass != null) {
8917 Log.w(TAG, "Error in app " + r.processName
8918 + " running instrumentation " + r.instrumentationClass + ":");
8919 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8920 if (longMsg != null) Log.w(TAG, " " + longMsg);
8921 Bundle info = new Bundle();
8922 info.putString("shortMsg", shortMsg);
8923 info.putString("longMsg", longMsg);
8924 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8925 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008926 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008927 }
8928
Dan Egnor60d87622009-12-16 16:32:58 -08008929 // If we can't identify the process or it's already exceeded its crash quota,
8930 // quit right away without showing a crash dialog.
8931 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008932 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008933 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008934 }
8935
8936 Message msg = Message.obtain();
8937 msg.what = SHOW_ERROR_MSG;
8938 HashMap data = new HashMap();
8939 data.put("result", result);
8940 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008941 msg.obj = data;
8942 mHandler.sendMessage(msg);
8943
8944 Binder.restoreCallingIdentity(origId);
8945 }
8946
8947 int res = result.get();
8948
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008949 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008950 synchronized (this) {
8951 if (r != null) {
8952 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8953 SystemClock.uptimeMillis());
8954 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008955 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008956 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008957 }
8958 }
8959
8960 if (appErrorIntent != null) {
8961 try {
8962 mContext.startActivity(appErrorIntent);
8963 } catch (ActivityNotFoundException e) {
8964 Log.w(TAG, "bug report receiver dissappeared", e);
8965 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008966 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008967 }
Dan Egnorb7f03672009-12-09 16:22:32 -08008968
8969 Intent createAppErrorIntentLocked(ProcessRecord r,
8970 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
8971 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008972 if (report == null) {
8973 return null;
8974 }
8975 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8976 result.setComponent(r.errorReportReceiver);
8977 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8978 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8979 return result;
8980 }
8981
Dan Egnorb7f03672009-12-09 16:22:32 -08008982 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
8983 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008984 if (r.errorReportReceiver == null) {
8985 return null;
8986 }
8987
8988 if (!r.crashing && !r.notResponding) {
8989 return null;
8990 }
8991
Dan Egnorb7f03672009-12-09 16:22:32 -08008992 ApplicationErrorReport report = new ApplicationErrorReport();
8993 report.packageName = r.info.packageName;
8994 report.installerPackageName = r.errorReportReceiver.getPackageName();
8995 report.processName = r.processName;
8996 report.time = timeMillis;
Jacek Surazskie0ee6ef2010-01-07 16:23:03 +01008997 report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008998
Dan Egnorb7f03672009-12-09 16:22:32 -08008999 if (r.crashing) {
9000 report.type = ApplicationErrorReport.TYPE_CRASH;
9001 report.crashInfo = crashInfo;
9002 } else if (r.notResponding) {
9003 report.type = ApplicationErrorReport.TYPE_ANR;
9004 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009005
Dan Egnorb7f03672009-12-09 16:22:32 -08009006 report.anrInfo.activity = r.notRespondingReport.tag;
9007 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9008 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009009 }
9010
Dan Egnorb7f03672009-12-09 16:22:32 -08009011 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009012 }
9013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009014 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9015 // assume our apps are happy - lazy create the list
9016 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9017
9018 synchronized (this) {
9019
9020 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009021 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9022 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009023 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9024 // This one's in trouble, so we'll generate a report for it
9025 // crashes are higher priority (in case there's a crash *and* an anr)
9026 ActivityManager.ProcessErrorStateInfo report = null;
9027 if (app.crashing) {
9028 report = app.crashingReport;
9029 } else if (app.notResponding) {
9030 report = app.notRespondingReport;
9031 }
9032
9033 if (report != null) {
9034 if (errList == null) {
9035 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9036 }
9037 errList.add(report);
9038 } else {
9039 Log.w(TAG, "Missing app error report, app = " + app.processName +
9040 " crashing = " + app.crashing +
9041 " notResponding = " + app.notResponding);
9042 }
9043 }
9044 }
9045 }
9046
9047 return errList;
9048 }
9049
9050 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9051 // Lazy instantiation of list
9052 List<ActivityManager.RunningAppProcessInfo> runList = null;
9053 synchronized (this) {
9054 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009055 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9056 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009057 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9058 // Generate process state info for running application
9059 ActivityManager.RunningAppProcessInfo currApp =
9060 new ActivityManager.RunningAppProcessInfo(app.processName,
9061 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009062 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009063 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009064 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009065 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9066 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9067 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009068 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9069 } else if (adj >= HOME_APP_ADJ) {
9070 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9071 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009072 } else if (adj >= SECONDARY_SERVER_ADJ) {
9073 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9074 } else if (adj >= VISIBLE_APP_ADJ) {
9075 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9076 } else {
9077 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9078 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009079 currApp.importanceReasonCode = app.adjTypeCode;
9080 if (app.adjSource instanceof ProcessRecord) {
9081 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9082 } else if (app.adjSource instanceof HistoryRecord) {
9083 HistoryRecord r = (HistoryRecord)app.adjSource;
9084 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9085 }
9086 if (app.adjTarget instanceof ComponentName) {
9087 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009089 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9090 // + " lru=" + currApp.lru);
9091 if (runList == null) {
9092 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9093 }
9094 runList.add(currApp);
9095 }
9096 }
9097 }
9098 return runList;
9099 }
9100
9101 @Override
9102 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009103 if (checkCallingPermission(android.Manifest.permission.DUMP)
9104 != PackageManager.PERMISSION_GRANTED) {
9105 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9106 + Binder.getCallingPid()
9107 + ", uid=" + Binder.getCallingUid()
9108 + " without permission "
9109 + android.Manifest.permission.DUMP);
9110 return;
9111 }
9112
9113 boolean dumpAll = false;
9114
9115 int opti = 0;
9116 while (opti < args.length) {
9117 String opt = args[opti];
9118 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9119 break;
9120 }
9121 opti++;
9122 if ("-a".equals(opt)) {
9123 dumpAll = true;
9124 } else if ("-h".equals(opt)) {
9125 pw.println("Activity manager dump options:");
9126 pw.println(" [-a] [h- [cmd] ...");
9127 pw.println(" cmd may be one of:");
9128 pw.println(" activities: activity stack state");
9129 pw.println(" broadcasts: broadcast state");
9130 pw.println(" intents: pending intent state");
9131 pw.println(" processes: process state");
9132 pw.println(" providers: content provider state");
9133 pw.println(" services: service state");
9134 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009135 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009136 } else {
9137 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009138 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009139 }
9140
9141 // Is the caller requesting to dump a particular piece of data?
9142 if (opti < args.length) {
9143 String cmd = args[opti];
9144 opti++;
9145 if ("activities".equals(cmd) || "a".equals(cmd)) {
9146 synchronized (this) {
9147 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009148 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009149 return;
9150 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9151 synchronized (this) {
9152 dumpBroadcastsLocked(fd, pw, args, opti, true);
9153 }
9154 return;
9155 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9156 synchronized (this) {
9157 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9158 }
9159 return;
9160 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9161 synchronized (this) {
9162 dumpProcessesLocked(fd, pw, args, opti, true);
9163 }
9164 return;
9165 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9166 synchronized (this) {
9167 dumpProvidersLocked(fd, pw, args, opti, true);
9168 }
9169 return;
9170 } else if ("service".equals(cmd)) {
9171 dumpService(fd, pw, args, opti, true);
9172 return;
9173 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9174 synchronized (this) {
9175 dumpServicesLocked(fd, pw, args, opti, true);
9176 }
9177 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009178 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009179 }
9180
9181 // No piece of data specified, dump everything.
9182 synchronized (this) {
9183 boolean needSep;
9184 if (dumpAll) {
9185 pw.println("Providers in Current Activity Manager State:");
9186 }
9187 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9188 if (needSep) {
9189 pw.println(" ");
9190 }
9191 if (dumpAll) {
9192 pw.println("-------------------------------------------------------------------------------");
9193 pw.println("Broadcasts in Current Activity Manager State:");
9194 }
9195 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9196 if (needSep) {
9197 pw.println(" ");
9198 }
9199 if (dumpAll) {
9200 pw.println("-------------------------------------------------------------------------------");
9201 pw.println("Services in Current Activity Manager State:");
9202 }
9203 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9204 if (needSep) {
9205 pw.println(" ");
9206 }
9207 if (dumpAll) {
9208 pw.println("-------------------------------------------------------------------------------");
9209 pw.println("PendingIntents in Current Activity Manager State:");
9210 }
9211 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9212 if (needSep) {
9213 pw.println(" ");
9214 }
9215 if (dumpAll) {
9216 pw.println("-------------------------------------------------------------------------------");
9217 pw.println("Activities in Current Activity Manager State:");
9218 }
9219 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9220 if (needSep) {
9221 pw.println(" ");
9222 }
9223 if (dumpAll) {
9224 pw.println("-------------------------------------------------------------------------------");
9225 pw.println("Processes in Current Activity Manager State:");
9226 }
9227 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9228 }
9229 }
9230
9231 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9232 int opti, boolean dumpAll, boolean needHeader) {
9233 if (needHeader) {
9234 pw.println(" Activity stack:");
9235 }
9236 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9237 pw.println(" ");
9238 pw.println(" Running activities (most recent first):");
9239 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9240 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009241 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009242 pw.println(" Activities waiting for another to become visible:");
9243 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9244 }
9245 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009246 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009247 pw.println(" Activities waiting to stop:");
9248 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9249 }
9250 if (mFinishingActivities.size() > 0) {
9251 pw.println(" ");
9252 pw.println(" Activities waiting to finish:");
9253 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009255
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009256 pw.println(" ");
9257 pw.println(" mPausingActivity: " + mPausingActivity);
9258 pw.println(" mResumedActivity: " + mResumedActivity);
9259 pw.println(" mFocusedActivity: " + mFocusedActivity);
9260 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009261
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009262 if (dumpAll && mRecentTasks.size() > 0) {
9263 pw.println(" ");
9264 pw.println("Recent tasks in Current Activity Manager State:");
9265
9266 final int N = mRecentTasks.size();
9267 for (int i=0; i<N; i++) {
9268 TaskRecord tr = mRecentTasks.get(i);
9269 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9270 pw.println(tr);
9271 mRecentTasks.get(i).dump(pw, " ");
9272 }
9273 }
9274
9275 pw.println(" ");
9276 pw.println(" mCurTask: " + mCurTask);
9277
9278 return true;
9279 }
9280
9281 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9282 int opti, boolean dumpAll) {
9283 boolean needSep = false;
9284 int numPers = 0;
9285
9286 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009287 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9288 final int NA = procs.size();
9289 for (int ia=0; ia<NA; ia++) {
9290 if (!needSep) {
9291 pw.println(" All known processes:");
9292 needSep = true;
9293 }
9294 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009295 pw.print(r.persistent ? " *PERS*" : " *APP*");
9296 pw.print(" UID "); pw.print(procs.keyAt(ia));
9297 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009298 r.dump(pw, " ");
9299 if (r.persistent) {
9300 numPers++;
9301 }
9302 }
9303 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009304 }
9305
9306 if (mLruProcesses.size() > 0) {
9307 if (needSep) pw.println(" ");
9308 needSep = true;
9309 pw.println(" Running processes (most recent first):");
9310 dumpProcessList(pw, this, mLruProcesses, " ",
9311 "App ", "PERS", true);
9312 needSep = true;
9313 }
9314
9315 synchronized (mPidsSelfLocked) {
9316 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009317 if (needSep) pw.println(" ");
9318 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009319 pw.println(" PID mappings:");
9320 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9321 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9322 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009323 }
9324 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009325 }
9326
9327 if (mForegroundProcesses.size() > 0) {
9328 if (needSep) pw.println(" ");
9329 needSep = true;
9330 pw.println(" Foreground Processes:");
9331 for (int i=0; i<mForegroundProcesses.size(); i++) {
9332 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9333 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009334 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009335 }
9336
9337 if (mPersistentStartingProcesses.size() > 0) {
9338 if (needSep) pw.println(" ");
9339 needSep = true;
9340 pw.println(" Persisent processes that are starting:");
9341 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9342 "Starting Norm", "Restarting PERS", false);
9343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009344
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009345 if (mStartingProcesses.size() > 0) {
9346 if (needSep) pw.println(" ");
9347 needSep = true;
9348 pw.println(" Processes that are starting:");
9349 dumpProcessList(pw, this, mStartingProcesses, " ",
9350 "Starting Norm", "Starting PERS", false);
9351 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009352
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009353 if (mRemovedProcesses.size() > 0) {
9354 if (needSep) pw.println(" ");
9355 needSep = true;
9356 pw.println(" Processes that are being removed:");
9357 dumpProcessList(pw, this, mRemovedProcesses, " ",
9358 "Removed Norm", "Removed PERS", false);
9359 }
9360
9361 if (mProcessesOnHold.size() > 0) {
9362 if (needSep) pw.println(" ");
9363 needSep = true;
9364 pw.println(" Processes that are on old until the system is ready:");
9365 dumpProcessList(pw, this, mProcessesOnHold, " ",
9366 "OnHold Norm", "OnHold PERS", false);
9367 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009368
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009369 if (mProcessesToGc.size() > 0) {
9370 if (needSep) pw.println(" ");
9371 needSep = true;
9372 pw.println(" Processes that are waiting to GC:");
9373 long now = SystemClock.uptimeMillis();
9374 for (int i=0; i<mProcessesToGc.size(); i++) {
9375 ProcessRecord proc = mProcessesToGc.get(i);
9376 pw.print(" Process "); pw.println(proc);
9377 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9378 pw.print(", last gced=");
9379 pw.print(now-proc.lastRequestedGc);
9380 pw.print(" ms ago, last lowMem=");
9381 pw.print(now-proc.lastLowMemory);
9382 pw.println(" ms ago");
9383
9384 }
9385 }
9386
9387 if (mProcessCrashTimes.getMap().size() > 0) {
9388 if (needSep) pw.println(" ");
9389 needSep = true;
9390 pw.println(" Time since processes crashed:");
9391 long now = SystemClock.uptimeMillis();
9392 for (Map.Entry<String, SparseArray<Long>> procs
9393 : mProcessCrashTimes.getMap().entrySet()) {
9394 SparseArray<Long> uids = procs.getValue();
9395 final int N = uids.size();
9396 for (int i=0; i<N; i++) {
9397 pw.print(" Process "); pw.print(procs.getKey());
9398 pw.print(" uid "); pw.print(uids.keyAt(i));
9399 pw.print(": last crashed ");
9400 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009401 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009402 }
9403 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009404 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009405
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009406 if (mBadProcesses.getMap().size() > 0) {
9407 if (needSep) pw.println(" ");
9408 needSep = true;
9409 pw.println(" Bad processes:");
9410 for (Map.Entry<String, SparseArray<Long>> procs
9411 : mBadProcesses.getMap().entrySet()) {
9412 SparseArray<Long> uids = procs.getValue();
9413 final int N = uids.size();
9414 for (int i=0; i<N; i++) {
9415 pw.print(" Bad process "); pw.print(procs.getKey());
9416 pw.print(" uid "); pw.print(uids.keyAt(i));
9417 pw.print(": crashed at time ");
9418 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009419 }
9420 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009421 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009422
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009423 pw.println(" ");
9424 pw.println(" mHomeProcess: " + mHomeProcess);
9425 pw.println(" mConfiguration: " + mConfiguration);
9426 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9427 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9428 || mOrigWaitForDebugger) {
9429 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9430 + " mDebugTransient=" + mDebugTransient
9431 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9432 }
9433 if (mAlwaysFinishActivities || mController != null) {
9434 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9435 + " mController=" + mController);
9436 }
9437 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009438 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009439 pw.println(" mStartRunning=" + mStartRunning
9440 + " mSystemReady=" + mSystemReady
9441 + " mBooting=" + mBooting
9442 + " mBooted=" + mBooted
9443 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009444 pw.println(" mGoingToSleep=" + mGoingToSleep);
9445 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009446 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009447
9448 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009449 }
9450
9451 /**
9452 * There are three ways to call this:
9453 * - no service specified: dump all the services
9454 * - a flattened component name that matched an existing service was specified as the
9455 * first arg: dump that one service
9456 * - the first arg isn't the flattened component name of an existing service:
9457 * dump all services whose component contains the first arg as a substring
9458 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009459 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9460 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009461 String[] newArgs;
9462 String componentNameString;
9463 ServiceRecord r;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009464 if (opti <= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009465 componentNameString = null;
9466 newArgs = EMPTY_STRING_ARRAY;
9467 r = null;
9468 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009469 componentNameString = args[opti];
9470 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009471 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9472 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009473 newArgs = new String[args.length - opti];
9474 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009475 }
9476
9477 if (r != null) {
9478 dumpService(fd, pw, r, newArgs);
9479 } else {
9480 for (ServiceRecord r1 : mServices.values()) {
9481 if (componentNameString == null
9482 || r1.name.flattenToString().contains(componentNameString)) {
9483 dumpService(fd, pw, r1, newArgs);
9484 }
9485 }
9486 }
9487 }
9488
9489 /**
9490 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9491 * there is a thread associated with the service.
9492 */
9493 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9494 pw.println(" Service " + r.name.flattenToString());
9495 if (r.app != null && r.app.thread != null) {
9496 try {
9497 // flush anything that is already in the PrintWriter since the thread is going
9498 // to write to the file descriptor directly
9499 pw.flush();
9500 r.app.thread.dumpService(fd, r, args);
9501 pw.print("\n");
9502 } catch (RemoteException e) {
9503 pw.println("got a RemoteException while dumping the service");
9504 }
9505 }
9506 }
9507
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009508 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9509 int opti, boolean dumpAll) {
9510 boolean needSep = false;
9511
9512 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009513 if (mRegisteredReceivers.size() > 0) {
9514 pw.println(" ");
9515 pw.println(" Registered Receivers:");
9516 Iterator it = mRegisteredReceivers.values().iterator();
9517 while (it.hasNext()) {
9518 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009519 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009520 r.dump(pw, " ");
9521 }
9522 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009524 pw.println(" ");
9525 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009526 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009527 needSep = true;
9528 }
9529
9530 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9531 || mPendingBroadcast != null) {
9532 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009533 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009534 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009535 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009536 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9537 pw.println(" Broadcast #" + i + ":");
9538 mParallelBroadcasts.get(i).dump(pw, " ");
9539 }
9540 if (mOrderedBroadcasts.size() > 0) {
9541 pw.println(" ");
9542 pw.println(" Active serialized broadcasts:");
9543 }
9544 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9545 pw.println(" Serialized Broadcast #" + i + ":");
9546 mOrderedBroadcasts.get(i).dump(pw, " ");
9547 }
9548 pw.println(" ");
9549 pw.println(" Pending broadcast:");
9550 if (mPendingBroadcast != null) {
9551 mPendingBroadcast.dump(pw, " ");
9552 } else {
9553 pw.println(" (null)");
9554 }
9555 needSep = true;
9556 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009557
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009558 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009559 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009560 pw.println(" Historical broadcasts:");
9561 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9562 BroadcastRecord r = mBroadcastHistory[i];
9563 if (r == null) {
9564 break;
9565 }
9566 pw.println(" Historical Broadcast #" + i + ":");
9567 r.dump(pw, " ");
9568 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009569 needSep = true;
9570 }
9571
9572 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009573 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009574 pw.println(" Sticky broadcasts:");
9575 StringBuilder sb = new StringBuilder(128);
9576 for (Map.Entry<String, ArrayList<Intent>> ent
9577 : mStickyBroadcasts.entrySet()) {
9578 pw.print(" * Sticky action "); pw.print(ent.getKey());
9579 pw.println(":");
9580 ArrayList<Intent> intents = ent.getValue();
9581 final int N = intents.size();
9582 for (int i=0; i<N; i++) {
9583 sb.setLength(0);
9584 sb.append(" Intent: ");
9585 intents.get(i).toShortString(sb, true, false);
9586 pw.println(sb.toString());
9587 Bundle bundle = intents.get(i).getExtras();
9588 if (bundle != null) {
9589 pw.print(" ");
9590 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009591 }
9592 }
9593 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009594 needSep = true;
9595 }
9596
9597 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009598 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009599 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009600 pw.println(" mHandler:");
9601 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009602 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009603 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009604
9605 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009606 }
9607
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009608 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9609 int opti, boolean dumpAll) {
9610 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009611
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009612 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009613 if (mServices.size() > 0) {
9614 pw.println(" Active services:");
9615 Iterator<ServiceRecord> it = mServices.values().iterator();
9616 while (it.hasNext()) {
9617 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009618 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009619 r.dump(pw, " ");
9620 }
9621 needSep = true;
9622 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009623 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009624
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009625 if (mPendingServices.size() > 0) {
9626 if (needSep) pw.println(" ");
9627 pw.println(" Pending services:");
9628 for (int i=0; i<mPendingServices.size(); i++) {
9629 ServiceRecord r = mPendingServices.get(i);
9630 pw.print(" * Pending "); pw.println(r);
9631 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009632 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009633 needSep = true;
9634 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009635
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009636 if (mRestartingServices.size() > 0) {
9637 if (needSep) pw.println(" ");
9638 pw.println(" Restarting services:");
9639 for (int i=0; i<mRestartingServices.size(); i++) {
9640 ServiceRecord r = mRestartingServices.get(i);
9641 pw.print(" * Restarting "); pw.println(r);
9642 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009643 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009644 needSep = true;
9645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009646
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009647 if (mStoppingServices.size() > 0) {
9648 if (needSep) pw.println(" ");
9649 pw.println(" Stopping services:");
9650 for (int i=0; i<mStoppingServices.size(); i++) {
9651 ServiceRecord r = mStoppingServices.get(i);
9652 pw.print(" * Stopping "); pw.println(r);
9653 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009654 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009655 needSep = true;
9656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009657
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009658 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009659 if (mServiceConnections.size() > 0) {
9660 if (needSep) pw.println(" ");
9661 pw.println(" Connection bindings to services:");
9662 Iterator<ConnectionRecord> it
9663 = mServiceConnections.values().iterator();
9664 while (it.hasNext()) {
9665 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009666 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009667 r.dump(pw, " ");
9668 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009669 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009670 }
9671 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009672
9673 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009674 }
9675
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009676 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9677 int opti, boolean dumpAll) {
9678 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009679
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009680 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009681 if (mProvidersByClass.size() > 0) {
9682 if (needSep) pw.println(" ");
9683 pw.println(" Published content providers (by class):");
9684 Iterator it = mProvidersByClass.entrySet().iterator();
9685 while (it.hasNext()) {
9686 Map.Entry e = (Map.Entry)it.next();
9687 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009688 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009689 r.dump(pw, " ");
9690 }
9691 needSep = true;
9692 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009693
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009694 if (mProvidersByName.size() > 0) {
9695 pw.println(" ");
9696 pw.println(" Authority to provider mappings:");
9697 Iterator it = mProvidersByName.entrySet().iterator();
9698 while (it.hasNext()) {
9699 Map.Entry e = (Map.Entry)it.next();
9700 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9701 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9702 pw.println(r);
9703 }
9704 needSep = true;
9705 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009706 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009707
9708 if (mLaunchingProviders.size() > 0) {
9709 if (needSep) pw.println(" ");
9710 pw.println(" Launching content providers:");
9711 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9712 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9713 pw.println(mLaunchingProviders.get(i));
9714 }
9715 needSep = true;
9716 }
9717
9718 if (mGrantedUriPermissions.size() > 0) {
9719 pw.println();
9720 pw.println("Granted Uri Permissions:");
9721 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9722 int uid = mGrantedUriPermissions.keyAt(i);
9723 HashMap<Uri, UriPermission> perms
9724 = mGrantedUriPermissions.valueAt(i);
9725 pw.print(" * UID "); pw.print(uid);
9726 pw.println(" holds:");
9727 for (UriPermission perm : perms.values()) {
9728 pw.print(" "); pw.println(perm);
9729 perm.dump(pw, " ");
9730 }
9731 }
9732 needSep = true;
9733 }
9734
9735 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009736 }
9737
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009738 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9739 int opti, boolean dumpAll) {
9740 boolean needSep = false;
9741
9742 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009743 if (this.mIntentSenderRecords.size() > 0) {
9744 Iterator<WeakReference<PendingIntentRecord>> it
9745 = mIntentSenderRecords.values().iterator();
9746 while (it.hasNext()) {
9747 WeakReference<PendingIntentRecord> ref = it.next();
9748 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009749 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009750 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009751 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009752 rec.dump(pw, " ");
9753 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009754 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009755 }
9756 }
9757 }
9758 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009759
9760 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009761 }
9762
9763 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009764 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009765 TaskRecord lastTask = null;
9766 for (int i=list.size()-1; i>=0; i--) {
9767 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009768 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009769 if (lastTask != r.task) {
9770 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009771 pw.print(prefix);
9772 pw.print(full ? "* " : " ");
9773 pw.println(lastTask);
9774 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009775 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009776 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009777 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009778 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9779 pw.print(" #"); pw.print(i); pw.print(": ");
9780 pw.println(r);
9781 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009782 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009784 }
9785 }
9786
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009787 private static String buildOomTag(String prefix, String space, int val, int base) {
9788 if (val == base) {
9789 if (space == null) return prefix;
9790 return prefix + " ";
9791 }
9792 return prefix + "+" + Integer.toString(val-base);
9793 }
9794
9795 private static final int dumpProcessList(PrintWriter pw,
9796 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009797 String prefix, String normalLabel, String persistentLabel,
9798 boolean inclOomAdj) {
9799 int numPers = 0;
9800 for (int i=list.size()-1; i>=0; i--) {
9801 ProcessRecord r = (ProcessRecord)list.get(i);
9802 if (false) {
9803 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9804 + " #" + i + ":");
9805 r.dump(pw, prefix + " ");
9806 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009807 String oomAdj;
9808 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009809 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009810 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009811 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9812 } else if (r.setAdj >= HOME_APP_ADJ) {
9813 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9814 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9815 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9816 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9817 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9818 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9819 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9820 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9821 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009822 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009823 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009824 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009825 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009826 } else {
9827 oomAdj = Integer.toString(r.setAdj);
9828 }
9829 String schedGroup;
9830 switch (r.setSchedGroup) {
9831 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9832 schedGroup = "B";
9833 break;
9834 case Process.THREAD_GROUP_DEFAULT:
9835 schedGroup = "F";
9836 break;
9837 default:
9838 schedGroup = Integer.toString(r.setSchedGroup);
9839 break;
9840 }
9841 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009842 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009843 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009844 if (r.adjSource != null || r.adjTarget != null) {
9845 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009846 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009847 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009848 } else {
9849 pw.println(String.format("%s%s #%2d: %s",
9850 prefix, (r.persistent ? persistentLabel : normalLabel),
9851 i, r.toString()));
9852 }
9853 if (r.persistent) {
9854 numPers++;
9855 }
9856 }
9857 return numPers;
9858 }
9859
9860 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9861 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009862 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009863 long uptime = SystemClock.uptimeMillis();
9864 long realtime = SystemClock.elapsedRealtime();
9865
9866 if (isCheckinRequest) {
9867 // short checkin version
9868 pw.println(uptime + "," + realtime);
9869 pw.flush();
9870 } else {
9871 pw.println("Applications Memory Usage (kB):");
9872 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9873 }
9874 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9875 ProcessRecord r = (ProcessRecord)list.get(i);
9876 if (r.thread != null) {
9877 if (!isCheckinRequest) {
9878 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9879 pw.flush();
9880 }
9881 try {
9882 r.thread.asBinder().dump(fd, args);
9883 } catch (RemoteException e) {
9884 if (!isCheckinRequest) {
9885 pw.println("Got RemoteException!");
9886 pw.flush();
9887 }
9888 }
9889 }
9890 }
9891 }
9892
9893 /**
9894 * Searches array of arguments for the specified string
9895 * @param args array of argument strings
9896 * @param value value to search for
9897 * @return true if the value is contained in the array
9898 */
9899 private static boolean scanArgs(String[] args, String value) {
9900 if (args != null) {
9901 for (String arg : args) {
9902 if (value.equals(arg)) {
9903 return true;
9904 }
9905 }
9906 }
9907 return false;
9908 }
9909
Dianne Hackborn75b03852009-06-12 15:43:26 -07009910 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009911 int count = mHistory.size();
9912
9913 // convert the token to an entry in the history.
9914 HistoryRecord r = null;
9915 int index = -1;
9916 for (int i=count-1; i>=0; i--) {
9917 Object o = mHistory.get(i);
9918 if (o == token) {
9919 r = (HistoryRecord)o;
9920 index = i;
9921 break;
9922 }
9923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009924
9925 return index;
9926 }
9927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009928 private final void killServicesLocked(ProcessRecord app,
9929 boolean allowRestart) {
9930 // Report disconnected services.
9931 if (false) {
9932 // XXX we are letting the client link to the service for
9933 // death notifications.
9934 if (app.services.size() > 0) {
9935 Iterator it = app.services.iterator();
9936 while (it.hasNext()) {
9937 ServiceRecord r = (ServiceRecord)it.next();
9938 if (r.connections.size() > 0) {
9939 Iterator<ConnectionRecord> jt
9940 = r.connections.values().iterator();
9941 while (jt.hasNext()) {
9942 ConnectionRecord c = jt.next();
9943 if (c.binding.client != app) {
9944 try {
9945 //c.conn.connected(r.className, null);
9946 } catch (Exception e) {
9947 // todo: this should be asynchronous!
9948 Log.w(TAG, "Exception thrown disconnected servce "
9949 + r.shortName
9950 + " from app " + app.processName, e);
9951 }
9952 }
9953 }
9954 }
9955 }
9956 }
9957 }
9958
9959 // Clean up any connections this application has to other services.
9960 if (app.connections.size() > 0) {
9961 Iterator<ConnectionRecord> it = app.connections.iterator();
9962 while (it.hasNext()) {
9963 ConnectionRecord r = it.next();
9964 removeConnectionLocked(r, app, null);
9965 }
9966 }
9967 app.connections.clear();
9968
9969 if (app.services.size() != 0) {
9970 // Any services running in the application need to be placed
9971 // back in the pending list.
9972 Iterator it = app.services.iterator();
9973 while (it.hasNext()) {
9974 ServiceRecord sr = (ServiceRecord)it.next();
9975 synchronized (sr.stats.getBatteryStats()) {
9976 sr.stats.stopLaunchedLocked();
9977 }
9978 sr.app = null;
9979 sr.executeNesting = 0;
9980 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009981
9982 boolean hasClients = sr.bindings.size() > 0;
9983 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009984 Iterator<IntentBindRecord> bindings
9985 = sr.bindings.values().iterator();
9986 while (bindings.hasNext()) {
9987 IntentBindRecord b = bindings.next();
9988 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9989 + ": shouldUnbind=" + b.hasBound);
9990 b.binder = null;
9991 b.requested = b.received = b.hasBound = false;
9992 }
9993 }
9994
9995 if (sr.crashCount >= 2) {
9996 Log.w(TAG, "Service crashed " + sr.crashCount
9997 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -08009998 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009999 sr.crashCount, sr.shortName, app.pid);
10000 bringDownServiceLocked(sr, true);
10001 } else if (!allowRestart) {
10002 bringDownServiceLocked(sr, true);
10003 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010004 boolean canceled = scheduleServiceRestartLocked(sr, true);
10005
10006 // Should the service remain running? Note that in the
10007 // extreme case of so many attempts to deliver a command
10008 // that it failed, that we also will stop it here.
10009 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10010 if (sr.pendingStarts.size() == 0) {
10011 sr.startRequested = false;
10012 if (!hasClients) {
10013 // Whoops, no reason to restart!
10014 bringDownServiceLocked(sr, true);
10015 }
10016 }
10017 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010018 }
10019 }
10020
10021 if (!allowRestart) {
10022 app.services.clear();
10023 }
10024 }
10025
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010026 // Make sure we have no more records on the stopping list.
10027 int i = mStoppingServices.size();
10028 while (i > 0) {
10029 i--;
10030 ServiceRecord sr = mStoppingServices.get(i);
10031 if (sr.app == app) {
10032 mStoppingServices.remove(i);
10033 }
10034 }
10035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010036 app.executingServices.clear();
10037 }
10038
10039 private final void removeDyingProviderLocked(ProcessRecord proc,
10040 ContentProviderRecord cpr) {
10041 synchronized (cpr) {
10042 cpr.launchingApp = null;
10043 cpr.notifyAll();
10044 }
10045
10046 mProvidersByClass.remove(cpr.info.name);
10047 String names[] = cpr.info.authority.split(";");
10048 for (int j = 0; j < names.length; j++) {
10049 mProvidersByName.remove(names[j]);
10050 }
10051
10052 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10053 while (cit.hasNext()) {
10054 ProcessRecord capp = cit.next();
10055 if (!capp.persistent && capp.thread != null
10056 && capp.pid != 0
10057 && capp.pid != MY_PID) {
10058 Log.i(TAG, "Killing app " + capp.processName
10059 + " (pid " + capp.pid
10060 + ") because provider " + cpr.info.name
10061 + " is in dying process " + proc.processName);
10062 Process.killProcess(capp.pid);
10063 }
10064 }
10065
10066 mLaunchingProviders.remove(cpr);
10067 }
10068
10069 /**
10070 * Main code for cleaning up a process when it has gone away. This is
10071 * called both as a result of the process dying, or directly when stopping
10072 * a process when running in single process mode.
10073 */
10074 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10075 boolean restarting, int index) {
10076 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010077 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010078 }
10079
Dianne Hackborn36124872009-10-08 16:22:03 -070010080 mProcessesToGc.remove(app);
10081
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010082 // Dismiss any open dialogs.
10083 if (app.crashDialog != null) {
10084 app.crashDialog.dismiss();
10085 app.crashDialog = null;
10086 }
10087 if (app.anrDialog != null) {
10088 app.anrDialog.dismiss();
10089 app.anrDialog = null;
10090 }
10091 if (app.waitDialog != null) {
10092 app.waitDialog.dismiss();
10093 app.waitDialog = null;
10094 }
10095
10096 app.crashing = false;
10097 app.notResponding = false;
10098
10099 app.resetPackageList();
10100 app.thread = null;
10101 app.forcingToForeground = null;
10102 app.foregroundServices = false;
10103
10104 killServicesLocked(app, true);
10105
10106 boolean restart = false;
10107
10108 int NL = mLaunchingProviders.size();
10109
10110 // Remove published content providers.
10111 if (!app.pubProviders.isEmpty()) {
10112 Iterator it = app.pubProviders.values().iterator();
10113 while (it.hasNext()) {
10114 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10115 cpr.provider = null;
10116 cpr.app = null;
10117
10118 // See if someone is waiting for this provider... in which
10119 // case we don't remove it, but just let it restart.
10120 int i = 0;
10121 if (!app.bad) {
10122 for (; i<NL; i++) {
10123 if (mLaunchingProviders.get(i) == cpr) {
10124 restart = true;
10125 break;
10126 }
10127 }
10128 } else {
10129 i = NL;
10130 }
10131
10132 if (i >= NL) {
10133 removeDyingProviderLocked(app, cpr);
10134 NL = mLaunchingProviders.size();
10135 }
10136 }
10137 app.pubProviders.clear();
10138 }
10139
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010140 // Take care of any launching providers waiting for this process.
10141 if (checkAppInLaunchingProvidersLocked(app, false)) {
10142 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010143 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010145 // Unregister from connected content providers.
10146 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010147 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010148 while (it.hasNext()) {
10149 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10150 cpr.clients.remove(app);
10151 }
10152 app.conProviders.clear();
10153 }
10154
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010155 // At this point there may be remaining entries in mLaunchingProviders
10156 // where we were the only one waiting, so they are no longer of use.
10157 // Look for these and clean up if found.
10158 // XXX Commented out for now. Trying to figure out a way to reproduce
10159 // the actual situation to identify what is actually going on.
10160 if (false) {
10161 for (int i=0; i<NL; i++) {
10162 ContentProviderRecord cpr = (ContentProviderRecord)
10163 mLaunchingProviders.get(i);
10164 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10165 synchronized (cpr) {
10166 cpr.launchingApp = null;
10167 cpr.notifyAll();
10168 }
10169 }
10170 }
10171 }
10172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010173 skipCurrentReceiverLocked(app);
10174
10175 // Unregister any receivers.
10176 if (app.receivers.size() > 0) {
10177 Iterator<ReceiverList> it = app.receivers.iterator();
10178 while (it.hasNext()) {
10179 removeReceiverLocked(it.next());
10180 }
10181 app.receivers.clear();
10182 }
10183
Christopher Tate181fafa2009-05-14 11:12:14 -070010184 // If the app is undergoing backup, tell the backup manager about it
10185 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10186 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10187 try {
10188 IBackupManager bm = IBackupManager.Stub.asInterface(
10189 ServiceManager.getService(Context.BACKUP_SERVICE));
10190 bm.agentDisconnected(app.info.packageName);
10191 } catch (RemoteException e) {
10192 // can't happen; backup manager is local
10193 }
10194 }
10195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010196 // If the caller is restarting this app, then leave it in its
10197 // current lists and let the caller take care of it.
10198 if (restarting) {
10199 return;
10200 }
10201
10202 if (!app.persistent) {
10203 if (DEBUG_PROCESSES) Log.v(TAG,
10204 "Removing non-persistent process during cleanup: " + app);
10205 mProcessNames.remove(app.processName, app.info.uid);
10206 } else if (!app.removed) {
10207 // This app is persistent, so we need to keep its record around.
10208 // If it is not already on the pending app list, add it there
10209 // and start a new process for it.
10210 app.thread = null;
10211 app.forcingToForeground = null;
10212 app.foregroundServices = false;
10213 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10214 mPersistentStartingProcesses.add(app);
10215 restart = true;
10216 }
10217 }
10218 mProcessesOnHold.remove(app);
10219
The Android Open Source Project4df24232009-03-05 14:34:35 -080010220 if (app == mHomeProcess) {
10221 mHomeProcess = null;
10222 }
10223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010224 if (restart) {
10225 // We have components that still need to be running in the
10226 // process, so re-launch it.
10227 mProcessNames.put(app.processName, app.info.uid, app);
10228 startProcessLocked(app, "restart", app.processName);
10229 } else if (app.pid > 0 && app.pid != MY_PID) {
10230 // Goodbye!
10231 synchronized (mPidsSelfLocked) {
10232 mPidsSelfLocked.remove(app.pid);
10233 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10234 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010235 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010236 }
10237 }
10238
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010239 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10240 // Look through the content providers we are waiting to have launched,
10241 // and if any run in this process then either schedule a restart of
10242 // the process or kill the client waiting for it if this process has
10243 // gone bad.
10244 int NL = mLaunchingProviders.size();
10245 boolean restart = false;
10246 for (int i=0; i<NL; i++) {
10247 ContentProviderRecord cpr = (ContentProviderRecord)
10248 mLaunchingProviders.get(i);
10249 if (cpr.launchingApp == app) {
10250 if (!alwaysBad && !app.bad) {
10251 restart = true;
10252 } else {
10253 removeDyingProviderLocked(app, cpr);
10254 NL = mLaunchingProviders.size();
10255 }
10256 }
10257 }
10258 return restart;
10259 }
10260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010261 // =========================================================
10262 // SERVICES
10263 // =========================================================
10264
10265 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10266 ActivityManager.RunningServiceInfo info =
10267 new ActivityManager.RunningServiceInfo();
10268 info.service = r.name;
10269 if (r.app != null) {
10270 info.pid = r.app.pid;
10271 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010272 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010273 info.process = r.processName;
10274 info.foreground = r.isForeground;
10275 info.activeSince = r.createTime;
10276 info.started = r.startRequested;
10277 info.clientCount = r.connections.size();
10278 info.crashCount = r.crashCount;
10279 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010280 if (r.isForeground) {
10281 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10282 }
10283 if (r.startRequested) {
10284 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10285 }
Dan Egnor42471dd2010-01-07 17:25:22 -080010286 if (r.app != null && r.app.pid == MY_PID) {
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010287 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10288 }
10289 if (r.app != null && r.app.persistent) {
10290 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10291 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010292 for (ConnectionRecord conn : r.connections.values()) {
10293 if (conn.clientLabel != 0) {
10294 info.clientPackage = conn.binding.client.info.packageName;
10295 info.clientLabel = conn.clientLabel;
10296 break;
10297 }
10298 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010299 return info;
10300 }
10301
10302 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10303 int flags) {
10304 synchronized (this) {
10305 ArrayList<ActivityManager.RunningServiceInfo> res
10306 = new ArrayList<ActivityManager.RunningServiceInfo>();
10307
10308 if (mServices.size() > 0) {
10309 Iterator<ServiceRecord> it = mServices.values().iterator();
10310 while (it.hasNext() && res.size() < maxNum) {
10311 res.add(makeRunningServiceInfoLocked(it.next()));
10312 }
10313 }
10314
10315 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10316 ServiceRecord r = mRestartingServices.get(i);
10317 ActivityManager.RunningServiceInfo info =
10318 makeRunningServiceInfoLocked(r);
10319 info.restarting = r.nextRestartTime;
10320 res.add(info);
10321 }
10322
10323 return res;
10324 }
10325 }
10326
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010327 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10328 synchronized (this) {
10329 ServiceRecord r = mServices.get(name);
10330 if (r != null) {
10331 for (ConnectionRecord conn : r.connections.values()) {
10332 if (conn.clientIntent != null) {
10333 return conn.clientIntent;
10334 }
10335 }
10336 }
10337 }
10338 return null;
10339 }
10340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010341 private final ServiceRecord findServiceLocked(ComponentName name,
10342 IBinder token) {
10343 ServiceRecord r = mServices.get(name);
10344 return r == token ? r : null;
10345 }
10346
10347 private final class ServiceLookupResult {
10348 final ServiceRecord record;
10349 final String permission;
10350
10351 ServiceLookupResult(ServiceRecord _record, String _permission) {
10352 record = _record;
10353 permission = _permission;
10354 }
10355 };
10356
10357 private ServiceLookupResult findServiceLocked(Intent service,
10358 String resolvedType) {
10359 ServiceRecord r = null;
10360 if (service.getComponent() != null) {
10361 r = mServices.get(service.getComponent());
10362 }
10363 if (r == null) {
10364 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10365 r = mServicesByIntent.get(filter);
10366 }
10367
10368 if (r == null) {
10369 try {
10370 ResolveInfo rInfo =
10371 ActivityThread.getPackageManager().resolveService(
10372 service, resolvedType, 0);
10373 ServiceInfo sInfo =
10374 rInfo != null ? rInfo.serviceInfo : null;
10375 if (sInfo == null) {
10376 return null;
10377 }
10378
10379 ComponentName name = new ComponentName(
10380 sInfo.applicationInfo.packageName, sInfo.name);
10381 r = mServices.get(name);
10382 } catch (RemoteException ex) {
10383 // pm is in same process, this will never happen.
10384 }
10385 }
10386 if (r != null) {
10387 int callingPid = Binder.getCallingPid();
10388 int callingUid = Binder.getCallingUid();
10389 if (checkComponentPermission(r.permission,
10390 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10391 != PackageManager.PERMISSION_GRANTED) {
10392 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10393 + " from pid=" + callingPid
10394 + ", uid=" + callingUid
10395 + " requires " + r.permission);
10396 return new ServiceLookupResult(null, r.permission);
10397 }
10398 return new ServiceLookupResult(r, null);
10399 }
10400 return null;
10401 }
10402
10403 private class ServiceRestarter implements Runnable {
10404 private ServiceRecord mService;
10405
10406 void setService(ServiceRecord service) {
10407 mService = service;
10408 }
10409
10410 public void run() {
10411 synchronized(ActivityManagerService.this) {
10412 performServiceRestartLocked(mService);
10413 }
10414 }
10415 }
10416
10417 private ServiceLookupResult retrieveServiceLocked(Intent service,
10418 String resolvedType, int callingPid, int callingUid) {
10419 ServiceRecord r = null;
10420 if (service.getComponent() != null) {
10421 r = mServices.get(service.getComponent());
10422 }
10423 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10424 r = mServicesByIntent.get(filter);
10425 if (r == null) {
10426 try {
10427 ResolveInfo rInfo =
10428 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010429 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010430 ServiceInfo sInfo =
10431 rInfo != null ? rInfo.serviceInfo : null;
10432 if (sInfo == null) {
10433 Log.w(TAG, "Unable to start service " + service +
10434 ": not found");
10435 return null;
10436 }
10437
10438 ComponentName name = new ComponentName(
10439 sInfo.applicationInfo.packageName, sInfo.name);
10440 r = mServices.get(name);
10441 if (r == null) {
10442 filter = new Intent.FilterComparison(service.cloneFilter());
10443 ServiceRestarter res = new ServiceRestarter();
10444 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10445 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10446 synchronized (stats) {
10447 ss = stats.getServiceStatsLocked(
10448 sInfo.applicationInfo.uid, sInfo.packageName,
10449 sInfo.name);
10450 }
10451 r = new ServiceRecord(ss, name, filter, sInfo, res);
10452 res.setService(r);
10453 mServices.put(name, r);
10454 mServicesByIntent.put(filter, r);
10455
10456 // Make sure this component isn't in the pending list.
10457 int N = mPendingServices.size();
10458 for (int i=0; i<N; i++) {
10459 ServiceRecord pr = mPendingServices.get(i);
10460 if (pr.name.equals(name)) {
10461 mPendingServices.remove(i);
10462 i--;
10463 N--;
10464 }
10465 }
10466 }
10467 } catch (RemoteException ex) {
10468 // pm is in same process, this will never happen.
10469 }
10470 }
10471 if (r != null) {
10472 if (checkComponentPermission(r.permission,
10473 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10474 != PackageManager.PERMISSION_GRANTED) {
10475 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10476 + " from pid=" + Binder.getCallingPid()
10477 + ", uid=" + Binder.getCallingUid()
10478 + " requires " + r.permission);
10479 return new ServiceLookupResult(null, r.permission);
10480 }
10481 return new ServiceLookupResult(r, null);
10482 }
10483 return null;
10484 }
10485
10486 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10487 long now = SystemClock.uptimeMillis();
10488 if (r.executeNesting == 0 && r.app != null) {
10489 if (r.app.executingServices.size() == 0) {
10490 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10491 msg.obj = r.app;
10492 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10493 }
10494 r.app.executingServices.add(r);
10495 }
10496 r.executeNesting++;
10497 r.executingStart = now;
10498 }
10499
10500 private final void sendServiceArgsLocked(ServiceRecord r,
10501 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010502 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010503 if (N == 0) {
10504 return;
10505 }
10506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010507 int i = 0;
10508 while (i < N) {
10509 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010510 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010511 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010512 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010513 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010514 // If somehow we got a dummy start at the front, then
10515 // just drop it here.
10516 i++;
10517 continue;
10518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010519 bumpServiceExecutingLocked(r);
10520 if (!oomAdjusted) {
10521 oomAdjusted = true;
10522 updateOomAdjLocked(r.app);
10523 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010524 int flags = 0;
10525 if (si.deliveryCount > 0) {
10526 flags |= Service.START_FLAG_RETRY;
10527 }
10528 if (si.doneExecutingCount > 0) {
10529 flags |= Service.START_FLAG_REDELIVERY;
10530 }
10531 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10532 si.deliveredTime = SystemClock.uptimeMillis();
10533 r.deliveredStarts.add(si);
10534 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010535 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010536 } catch (RemoteException e) {
10537 // Remote process gone... we'll let the normal cleanup take
10538 // care of this.
10539 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010540 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010541 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010542 break;
10543 }
10544 }
10545 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010546 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010547 } else {
10548 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010549 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010550 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010551 }
10552 }
10553 }
10554
10555 private final boolean requestServiceBindingLocked(ServiceRecord r,
10556 IntentBindRecord i, boolean rebind) {
10557 if (r.app == null || r.app.thread == null) {
10558 // If service is not currently running, can't yet bind.
10559 return false;
10560 }
10561 if ((!i.requested || rebind) && i.apps.size() > 0) {
10562 try {
10563 bumpServiceExecutingLocked(r);
10564 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10565 + ": shouldUnbind=" + i.hasBound);
10566 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10567 if (!rebind) {
10568 i.requested = true;
10569 }
10570 i.hasBound = true;
10571 i.doRebind = false;
10572 } catch (RemoteException e) {
10573 return false;
10574 }
10575 }
10576 return true;
10577 }
10578
10579 private final void requestServiceBindingsLocked(ServiceRecord r) {
10580 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10581 while (bindings.hasNext()) {
10582 IntentBindRecord i = bindings.next();
10583 if (!requestServiceBindingLocked(r, i, false)) {
10584 break;
10585 }
10586 }
10587 }
10588
10589 private final void realStartServiceLocked(ServiceRecord r,
10590 ProcessRecord app) throws RemoteException {
10591 if (app.thread == null) {
10592 throw new RemoteException();
10593 }
10594
10595 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010596 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010597
10598 app.services.add(r);
10599 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010600 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010601
10602 boolean created = false;
10603 try {
10604 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10605 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010606 mStringBuilder.setLength(0);
10607 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010608 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010609 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010610 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010611 synchronized (r.stats.getBatteryStats()) {
10612 r.stats.startLaunchedLocked();
10613 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010614 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010615 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010616 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010617 created = true;
10618 } finally {
10619 if (!created) {
10620 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010621 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010622 }
10623 }
10624
10625 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010626
10627 // If the service is in the started state, and there are no
10628 // pending arguments, then fake up one so its onStartCommand() will
10629 // be called.
10630 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10631 r.lastStartId++;
10632 if (r.lastStartId < 1) {
10633 r.lastStartId = 1;
10634 }
10635 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10636 }
10637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010638 sendServiceArgsLocked(r, true);
10639 }
10640
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010641 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10642 boolean allowCancel) {
10643 boolean canceled = false;
10644
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010645 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010646 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010647 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010648
10649 // Any delivered but not yet finished starts should be put back
10650 // on the pending list.
10651 final int N = r.deliveredStarts.size();
10652 if (N > 0) {
10653 for (int i=N-1; i>=0; i--) {
10654 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10655 if (si.intent == null) {
10656 // We'll generate this again if needed.
10657 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10658 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10659 r.pendingStarts.add(0, si);
10660 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10661 dur *= 2;
10662 if (minDuration < dur) minDuration = dur;
10663 if (resetTime < dur) resetTime = dur;
10664 } else {
10665 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10666 + r.name);
10667 canceled = true;
10668 }
10669 }
10670 r.deliveredStarts.clear();
10671 }
10672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010673 r.totalRestartCount++;
10674 if (r.restartDelay == 0) {
10675 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010676 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010677 } else {
10678 // If it has been a "reasonably long time" since the service
10679 // was started, then reset our restart duration back to
10680 // the beginning, so we don't infinitely increase the duration
10681 // on a service that just occasionally gets killed (which is
10682 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010683 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010684 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010685 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010686 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010687 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010688 if (r.restartDelay < minDuration) {
10689 r.restartDelay = minDuration;
10690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010691 }
10692 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010693
10694 r.nextRestartTime = now + r.restartDelay;
10695
10696 // Make sure that we don't end up restarting a bunch of services
10697 // all at the same time.
10698 boolean repeat;
10699 do {
10700 repeat = false;
10701 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10702 ServiceRecord r2 = mRestartingServices.get(i);
10703 if (r2 != r && r.nextRestartTime
10704 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10705 && r.nextRestartTime
10706 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10707 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10708 r.restartDelay = r.nextRestartTime - now;
10709 repeat = true;
10710 break;
10711 }
10712 }
10713 } while (repeat);
10714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010715 if (!mRestartingServices.contains(r)) {
10716 mRestartingServices.add(r);
10717 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010718
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010719 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010721 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010722 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010723 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10724 Log.w(TAG, "Scheduling restart of crashed service "
10725 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010726 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010727 r.shortName, r.restartDelay);
10728
10729 Message msg = Message.obtain();
10730 msg.what = SERVICE_ERROR_MSG;
10731 msg.obj = r;
10732 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010733
10734 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010735 }
10736
10737 final void performServiceRestartLocked(ServiceRecord r) {
10738 if (!mRestartingServices.contains(r)) {
10739 return;
10740 }
10741 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10742 }
10743
10744 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10745 if (r.restartDelay == 0) {
10746 return false;
10747 }
10748 r.resetRestartCounter();
10749 mRestartingServices.remove(r);
10750 mHandler.removeCallbacks(r.restarter);
10751 return true;
10752 }
10753
10754 private final boolean bringUpServiceLocked(ServiceRecord r,
10755 int intentFlags, boolean whileRestarting) {
10756 //Log.i(TAG, "Bring up service:");
10757 //r.dump(" ");
10758
Dianne Hackborn36124872009-10-08 16:22:03 -070010759 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010760 sendServiceArgsLocked(r, false);
10761 return true;
10762 }
10763
10764 if (!whileRestarting && r.restartDelay > 0) {
10765 // If waiting for a restart, then do nothing.
10766 return true;
10767 }
10768
10769 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10770 + " " + r.intent);
10771
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010772 // We are now bringing the service up, so no longer in the
10773 // restarting state.
10774 mRestartingServices.remove(r);
10775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010776 final String appName = r.processName;
10777 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10778 if (app != null && app.thread != null) {
10779 try {
10780 realStartServiceLocked(r, app);
10781 return true;
10782 } catch (RemoteException e) {
10783 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10784 }
10785
10786 // If a dead object exception was thrown -- fall through to
10787 // restart the application.
10788 }
10789
Dianne Hackborn36124872009-10-08 16:22:03 -070010790 // Not running -- get it started, and enqueue this service record
10791 // to be executed when the app comes up.
10792 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10793 "service", r.name, false) == null) {
10794 Log.w(TAG, "Unable to launch app "
10795 + r.appInfo.packageName + "/"
10796 + r.appInfo.uid + " for service "
10797 + r.intent.getIntent() + ": process is bad");
10798 bringDownServiceLocked(r, true);
10799 return false;
10800 }
10801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010802 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010803 mPendingServices.add(r);
10804 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010806 return true;
10807 }
10808
10809 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10810 //Log.i(TAG, "Bring down service:");
10811 //r.dump(" ");
10812
10813 // Does it still need to run?
10814 if (!force && r.startRequested) {
10815 return;
10816 }
10817 if (r.connections.size() > 0) {
10818 if (!force) {
10819 // XXX should probably keep a count of the number of auto-create
10820 // connections directly in the service.
10821 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10822 while (it.hasNext()) {
10823 ConnectionRecord cr = it.next();
10824 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10825 return;
10826 }
10827 }
10828 }
10829
10830 // Report to all of the connections that the service is no longer
10831 // available.
10832 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10833 while (it.hasNext()) {
10834 ConnectionRecord c = it.next();
10835 try {
10836 // todo: shouldn't be a synchronous call!
10837 c.conn.connected(r.name, null);
10838 } catch (Exception e) {
10839 Log.w(TAG, "Failure disconnecting service " + r.name +
10840 " to connection " + c.conn.asBinder() +
10841 " (in " + c.binding.client.processName + ")", e);
10842 }
10843 }
10844 }
10845
10846 // Tell the service that it has been unbound.
10847 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10848 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10849 while (it.hasNext()) {
10850 IntentBindRecord ibr = it.next();
10851 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10852 + ": hasBound=" + ibr.hasBound);
10853 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10854 try {
10855 bumpServiceExecutingLocked(r);
10856 updateOomAdjLocked(r.app);
10857 ibr.hasBound = false;
10858 r.app.thread.scheduleUnbindService(r,
10859 ibr.intent.getIntent());
10860 } catch (Exception e) {
10861 Log.w(TAG, "Exception when unbinding service "
10862 + r.shortName, e);
10863 serviceDoneExecutingLocked(r, true);
10864 }
10865 }
10866 }
10867 }
10868
10869 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10870 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010871 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010872 System.identityHashCode(r), r.shortName,
10873 (r.app != null) ? r.app.pid : -1);
10874
10875 mServices.remove(r.name);
10876 mServicesByIntent.remove(r.intent);
10877 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10878 r.totalRestartCount = 0;
10879 unscheduleServiceRestartLocked(r);
10880
10881 // Also make sure it is not on the pending list.
10882 int N = mPendingServices.size();
10883 for (int i=0; i<N; i++) {
10884 if (mPendingServices.get(i) == r) {
10885 mPendingServices.remove(i);
10886 if (DEBUG_SERVICE) Log.v(
10887 TAG, "Removed pending service: " + r.shortName);
10888 i--;
10889 N--;
10890 }
10891 }
10892
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010893 r.cancelNotification();
10894 r.isForeground = false;
10895 r.foregroundId = 0;
10896 r.foregroundNoti = null;
10897
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010898 // Clear start entries.
10899 r.deliveredStarts.clear();
10900 r.pendingStarts.clear();
10901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010902 if (r.app != null) {
10903 synchronized (r.stats.getBatteryStats()) {
10904 r.stats.stopLaunchedLocked();
10905 }
10906 r.app.services.remove(r);
10907 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010908 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010909 if (DEBUG_SERVICE) Log.v(TAG,
10910 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010911 bumpServiceExecutingLocked(r);
10912 mStoppingServices.add(r);
10913 updateOomAdjLocked(r.app);
10914 r.app.thread.scheduleStopService(r);
10915 } catch (Exception e) {
10916 Log.w(TAG, "Exception when stopping service "
10917 + r.shortName, e);
10918 serviceDoneExecutingLocked(r, true);
10919 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010920 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010921 } else {
10922 if (DEBUG_SERVICE) Log.v(
10923 TAG, "Removed service that has no process: " + r.shortName);
10924 }
10925 } else {
10926 if (DEBUG_SERVICE) Log.v(
10927 TAG, "Removed service that is not running: " + r.shortName);
10928 }
10929 }
10930
10931 ComponentName startServiceLocked(IApplicationThread caller,
10932 Intent service, String resolvedType,
10933 int callingPid, int callingUid) {
10934 synchronized(this) {
10935 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10936 + " type=" + resolvedType + " args=" + service.getExtras());
10937
10938 if (caller != null) {
10939 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10940 if (callerApp == null) {
10941 throw new SecurityException(
10942 "Unable to find app for caller " + caller
10943 + " (pid=" + Binder.getCallingPid()
10944 + ") when starting service " + service);
10945 }
10946 }
10947
10948 ServiceLookupResult res =
10949 retrieveServiceLocked(service, resolvedType,
10950 callingPid, callingUid);
10951 if (res == null) {
10952 return null;
10953 }
10954 if (res.record == null) {
10955 return new ComponentName("!", res.permission != null
10956 ? res.permission : "private to package");
10957 }
10958 ServiceRecord r = res.record;
10959 if (unscheduleServiceRestartLocked(r)) {
10960 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10961 + r.shortName);
10962 }
10963 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010964 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010965 r.lastStartId++;
10966 if (r.lastStartId < 1) {
10967 r.lastStartId = 1;
10968 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010969 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010970 r.lastActivity = SystemClock.uptimeMillis();
10971 synchronized (r.stats.getBatteryStats()) {
10972 r.stats.startRunningLocked();
10973 }
10974 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10975 return new ComponentName("!", "Service process is bad");
10976 }
10977 return r.name;
10978 }
10979 }
10980
10981 public ComponentName startService(IApplicationThread caller, Intent service,
10982 String resolvedType) {
10983 // Refuse possible leaked file descriptors
10984 if (service != null && service.hasFileDescriptors() == true) {
10985 throw new IllegalArgumentException("File descriptors passed in Intent");
10986 }
10987
10988 synchronized(this) {
10989 final int callingPid = Binder.getCallingPid();
10990 final int callingUid = Binder.getCallingUid();
10991 final long origId = Binder.clearCallingIdentity();
10992 ComponentName res = startServiceLocked(caller, service,
10993 resolvedType, callingPid, callingUid);
10994 Binder.restoreCallingIdentity(origId);
10995 return res;
10996 }
10997 }
10998
10999 ComponentName startServiceInPackage(int uid,
11000 Intent service, String resolvedType) {
11001 synchronized(this) {
11002 final long origId = Binder.clearCallingIdentity();
11003 ComponentName res = startServiceLocked(null, service,
11004 resolvedType, -1, uid);
11005 Binder.restoreCallingIdentity(origId);
11006 return res;
11007 }
11008 }
11009
11010 public int stopService(IApplicationThread caller, Intent service,
11011 String resolvedType) {
11012 // Refuse possible leaked file descriptors
11013 if (service != null && service.hasFileDescriptors() == true) {
11014 throw new IllegalArgumentException("File descriptors passed in Intent");
11015 }
11016
11017 synchronized(this) {
11018 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11019 + " type=" + resolvedType);
11020
11021 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11022 if (caller != null && callerApp == null) {
11023 throw new SecurityException(
11024 "Unable to find app for caller " + caller
11025 + " (pid=" + Binder.getCallingPid()
11026 + ") when stopping service " + service);
11027 }
11028
11029 // If this service is active, make sure it is stopped.
11030 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11031 if (r != null) {
11032 if (r.record != null) {
11033 synchronized (r.record.stats.getBatteryStats()) {
11034 r.record.stats.stopRunningLocked();
11035 }
11036 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011037 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011038 final long origId = Binder.clearCallingIdentity();
11039 bringDownServiceLocked(r.record, false);
11040 Binder.restoreCallingIdentity(origId);
11041 return 1;
11042 }
11043 return -1;
11044 }
11045 }
11046
11047 return 0;
11048 }
11049
11050 public IBinder peekService(Intent service, String resolvedType) {
11051 // Refuse possible leaked file descriptors
11052 if (service != null && service.hasFileDescriptors() == true) {
11053 throw new IllegalArgumentException("File descriptors passed in Intent");
11054 }
11055
11056 IBinder ret = null;
11057
11058 synchronized(this) {
11059 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11060
11061 if (r != null) {
11062 // r.record is null if findServiceLocked() failed the caller permission check
11063 if (r.record == null) {
11064 throw new SecurityException(
11065 "Permission Denial: Accessing service " + r.record.name
11066 + " from pid=" + Binder.getCallingPid()
11067 + ", uid=" + Binder.getCallingUid()
11068 + " requires " + r.permission);
11069 }
11070 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11071 if (ib != null) {
11072 ret = ib.binder;
11073 }
11074 }
11075 }
11076
11077 return ret;
11078 }
11079
11080 public boolean stopServiceToken(ComponentName className, IBinder token,
11081 int startId) {
11082 synchronized(this) {
11083 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11084 + " " + token + " startId=" + startId);
11085 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011086 if (r != null) {
11087 if (startId >= 0) {
11088 // Asked to only stop if done with all work. Note that
11089 // to avoid leaks, we will take this as dropping all
11090 // start items up to and including this one.
11091 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11092 if (si != null) {
11093 while (r.deliveredStarts.size() > 0) {
11094 if (r.deliveredStarts.remove(0) == si) {
11095 break;
11096 }
11097 }
11098 }
11099
11100 if (r.lastStartId != startId) {
11101 return false;
11102 }
11103
11104 if (r.deliveredStarts.size() > 0) {
11105 Log.w(TAG, "stopServiceToken startId " + startId
11106 + " is last, but have " + r.deliveredStarts.size()
11107 + " remaining args");
11108 }
11109 }
11110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011111 synchronized (r.stats.getBatteryStats()) {
11112 r.stats.stopRunningLocked();
11113 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011114 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011115 }
11116 final long origId = Binder.clearCallingIdentity();
11117 bringDownServiceLocked(r, false);
11118 Binder.restoreCallingIdentity(origId);
11119 return true;
11120 }
11121 }
11122 return false;
11123 }
11124
11125 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011126 int id, Notification notification, boolean removeNotification) {
11127 final long origId = Binder.clearCallingIdentity();
11128 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011129 synchronized(this) {
11130 ServiceRecord r = findServiceLocked(className, token);
11131 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011132 if (id != 0) {
11133 if (notification == null) {
11134 throw new IllegalArgumentException("null notification");
11135 }
11136 if (r.foregroundId != id) {
11137 r.cancelNotification();
11138 r.foregroundId = id;
11139 }
11140 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11141 r.foregroundNoti = notification;
11142 r.isForeground = true;
11143 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011144 if (r.app != null) {
11145 updateServiceForegroundLocked(r.app, true);
11146 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011147 } else {
11148 if (r.isForeground) {
11149 r.isForeground = false;
11150 if (r.app != null) {
11151 updateServiceForegroundLocked(r.app, true);
11152 }
11153 }
11154 if (removeNotification) {
11155 r.cancelNotification();
11156 r.foregroundId = 0;
11157 r.foregroundNoti = null;
11158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011159 }
11160 }
11161 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011162 } finally {
11163 Binder.restoreCallingIdentity(origId);
11164 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011165 }
11166
11167 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11168 boolean anyForeground = false;
11169 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11170 if (sr.isForeground) {
11171 anyForeground = true;
11172 break;
11173 }
11174 }
11175 if (anyForeground != proc.foregroundServices) {
11176 proc.foregroundServices = anyForeground;
11177 if (oomAdj) {
11178 updateOomAdjLocked();
11179 }
11180 }
11181 }
11182
11183 public int bindService(IApplicationThread caller, IBinder token,
11184 Intent service, String resolvedType,
11185 IServiceConnection connection, int flags) {
11186 // Refuse possible leaked file descriptors
11187 if (service != null && service.hasFileDescriptors() == true) {
11188 throw new IllegalArgumentException("File descriptors passed in Intent");
11189 }
11190
11191 synchronized(this) {
11192 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11193 + " type=" + resolvedType + " conn=" + connection.asBinder()
11194 + " flags=0x" + Integer.toHexString(flags));
11195 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11196 if (callerApp == null) {
11197 throw new SecurityException(
11198 "Unable to find app for caller " + caller
11199 + " (pid=" + Binder.getCallingPid()
11200 + ") when binding service " + service);
11201 }
11202
11203 HistoryRecord activity = null;
11204 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011205 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011206 if (aindex < 0) {
11207 Log.w(TAG, "Binding with unknown activity: " + token);
11208 return 0;
11209 }
11210 activity = (HistoryRecord)mHistory.get(aindex);
11211 }
11212
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011213 int clientLabel = 0;
11214 PendingIntent clientIntent = null;
11215
11216 if (callerApp.info.uid == Process.SYSTEM_UID) {
11217 // Hacky kind of thing -- allow system stuff to tell us
11218 // what they are, so we can report this elsewhere for
11219 // others to know why certain services are running.
11220 try {
11221 clientIntent = (PendingIntent)service.getParcelableExtra(
11222 Intent.EXTRA_CLIENT_INTENT);
11223 } catch (RuntimeException e) {
11224 }
11225 if (clientIntent != null) {
11226 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11227 if (clientLabel != 0) {
11228 // There are no useful extras in the intent, trash them.
11229 // System code calling with this stuff just needs to know
11230 // this will happen.
11231 service = service.cloneFilter();
11232 }
11233 }
11234 }
11235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011236 ServiceLookupResult res =
11237 retrieveServiceLocked(service, resolvedType,
11238 Binder.getCallingPid(), Binder.getCallingUid());
11239 if (res == null) {
11240 return 0;
11241 }
11242 if (res.record == null) {
11243 return -1;
11244 }
11245 ServiceRecord s = res.record;
11246
11247 final long origId = Binder.clearCallingIdentity();
11248
11249 if (unscheduleServiceRestartLocked(s)) {
11250 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11251 + s.shortName);
11252 }
11253
11254 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11255 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011256 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011257
11258 IBinder binder = connection.asBinder();
11259 s.connections.put(binder, c);
11260 b.connections.add(c);
11261 if (activity != null) {
11262 if (activity.connections == null) {
11263 activity.connections = new HashSet<ConnectionRecord>();
11264 }
11265 activity.connections.add(c);
11266 }
11267 b.client.connections.add(c);
11268 mServiceConnections.put(binder, c);
11269
11270 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11271 s.lastActivity = SystemClock.uptimeMillis();
11272 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11273 return 0;
11274 }
11275 }
11276
11277 if (s.app != null) {
11278 // This could have made the service more important.
11279 updateOomAdjLocked(s.app);
11280 }
11281
11282 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11283 + ": received=" + b.intent.received
11284 + " apps=" + b.intent.apps.size()
11285 + " doRebind=" + b.intent.doRebind);
11286
11287 if (s.app != null && b.intent.received) {
11288 // Service is already running, so we can immediately
11289 // publish the connection.
11290 try {
11291 c.conn.connected(s.name, b.intent.binder);
11292 } catch (Exception e) {
11293 Log.w(TAG, "Failure sending service " + s.shortName
11294 + " to connection " + c.conn.asBinder()
11295 + " (in " + c.binding.client.processName + ")", e);
11296 }
11297
11298 // If this is the first app connected back to this binding,
11299 // and the service had previously asked to be told when
11300 // rebound, then do so.
11301 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11302 requestServiceBindingLocked(s, b.intent, true);
11303 }
11304 } else if (!b.intent.requested) {
11305 requestServiceBindingLocked(s, b.intent, false);
11306 }
11307
11308 Binder.restoreCallingIdentity(origId);
11309 }
11310
11311 return 1;
11312 }
11313
11314 private void removeConnectionLocked(
11315 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11316 IBinder binder = c.conn.asBinder();
11317 AppBindRecord b = c.binding;
11318 ServiceRecord s = b.service;
11319 s.connections.remove(binder);
11320 b.connections.remove(c);
11321 if (c.activity != null && c.activity != skipAct) {
11322 if (c.activity.connections != null) {
11323 c.activity.connections.remove(c);
11324 }
11325 }
11326 if (b.client != skipApp) {
11327 b.client.connections.remove(c);
11328 }
11329 mServiceConnections.remove(binder);
11330
11331 if (b.connections.size() == 0) {
11332 b.intent.apps.remove(b.client);
11333 }
11334
11335 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11336 + ": shouldUnbind=" + b.intent.hasBound);
11337 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11338 && b.intent.hasBound) {
11339 try {
11340 bumpServiceExecutingLocked(s);
11341 updateOomAdjLocked(s.app);
11342 b.intent.hasBound = false;
11343 // Assume the client doesn't want to know about a rebind;
11344 // we will deal with that later if it asks for one.
11345 b.intent.doRebind = false;
11346 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11347 } catch (Exception e) {
11348 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11349 serviceDoneExecutingLocked(s, true);
11350 }
11351 }
11352
11353 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11354 bringDownServiceLocked(s, false);
11355 }
11356 }
11357
11358 public boolean unbindService(IServiceConnection connection) {
11359 synchronized (this) {
11360 IBinder binder = connection.asBinder();
11361 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11362 ConnectionRecord r = mServiceConnections.get(binder);
11363 if (r == null) {
11364 Log.w(TAG, "Unbind failed: could not find connection for "
11365 + connection.asBinder());
11366 return false;
11367 }
11368
11369 final long origId = Binder.clearCallingIdentity();
11370
11371 removeConnectionLocked(r, null, null);
11372
11373 if (r.binding.service.app != null) {
11374 // This could have made the service less important.
11375 updateOomAdjLocked(r.binding.service.app);
11376 }
11377
11378 Binder.restoreCallingIdentity(origId);
11379 }
11380
11381 return true;
11382 }
11383
11384 public void publishService(IBinder token, Intent intent, IBinder service) {
11385 // Refuse possible leaked file descriptors
11386 if (intent != null && intent.hasFileDescriptors() == true) {
11387 throw new IllegalArgumentException("File descriptors passed in Intent");
11388 }
11389
11390 synchronized(this) {
11391 if (!(token instanceof ServiceRecord)) {
11392 throw new IllegalArgumentException("Invalid service token");
11393 }
11394 ServiceRecord r = (ServiceRecord)token;
11395
11396 final long origId = Binder.clearCallingIdentity();
11397
11398 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11399 + " " + intent + ": " + service);
11400 if (r != null) {
11401 Intent.FilterComparison filter
11402 = new Intent.FilterComparison(intent);
11403 IntentBindRecord b = r.bindings.get(filter);
11404 if (b != null && !b.received) {
11405 b.binder = service;
11406 b.requested = true;
11407 b.received = true;
11408 if (r.connections.size() > 0) {
11409 Iterator<ConnectionRecord> it
11410 = r.connections.values().iterator();
11411 while (it.hasNext()) {
11412 ConnectionRecord c = it.next();
11413 if (!filter.equals(c.binding.intent.intent)) {
11414 if (DEBUG_SERVICE) Log.v(
11415 TAG, "Not publishing to: " + c);
11416 if (DEBUG_SERVICE) Log.v(
11417 TAG, "Bound intent: " + c.binding.intent.intent);
11418 if (DEBUG_SERVICE) Log.v(
11419 TAG, "Published intent: " + intent);
11420 continue;
11421 }
11422 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11423 try {
11424 c.conn.connected(r.name, service);
11425 } catch (Exception e) {
11426 Log.w(TAG, "Failure sending service " + r.name +
11427 " to connection " + c.conn.asBinder() +
11428 " (in " + c.binding.client.processName + ")", e);
11429 }
11430 }
11431 }
11432 }
11433
11434 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11435
11436 Binder.restoreCallingIdentity(origId);
11437 }
11438 }
11439 }
11440
11441 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11442 // Refuse possible leaked file descriptors
11443 if (intent != null && intent.hasFileDescriptors() == true) {
11444 throw new IllegalArgumentException("File descriptors passed in Intent");
11445 }
11446
11447 synchronized(this) {
11448 if (!(token instanceof ServiceRecord)) {
11449 throw new IllegalArgumentException("Invalid service token");
11450 }
11451 ServiceRecord r = (ServiceRecord)token;
11452
11453 final long origId = Binder.clearCallingIdentity();
11454
11455 if (r != null) {
11456 Intent.FilterComparison filter
11457 = new Intent.FilterComparison(intent);
11458 IntentBindRecord b = r.bindings.get(filter);
11459 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11460 + " at " + b + ": apps="
11461 + (b != null ? b.apps.size() : 0));
11462 if (b != null) {
11463 if (b.apps.size() > 0) {
11464 // Applications have already bound since the last
11465 // unbind, so just rebind right here.
11466 requestServiceBindingLocked(r, b, true);
11467 } else {
11468 // Note to tell the service the next time there is
11469 // a new client.
11470 b.doRebind = true;
11471 }
11472 }
11473
11474 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11475
11476 Binder.restoreCallingIdentity(origId);
11477 }
11478 }
11479 }
11480
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011481 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011482 synchronized(this) {
11483 if (!(token instanceof ServiceRecord)) {
11484 throw new IllegalArgumentException("Invalid service token");
11485 }
11486 ServiceRecord r = (ServiceRecord)token;
11487 boolean inStopping = mStoppingServices.contains(token);
11488 if (r != null) {
11489 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11490 + ": nesting=" + r.executeNesting
11491 + ", inStopping=" + inStopping);
11492 if (r != token) {
11493 Log.w(TAG, "Done executing service " + r.name
11494 + " with incorrect token: given " + token
11495 + ", expected " + r);
11496 return;
11497 }
11498
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011499 if (type == 1) {
11500 // This is a call from a service start... take care of
11501 // book-keeping.
11502 r.callStart = true;
11503 switch (res) {
11504 case Service.START_STICKY_COMPATIBILITY:
11505 case Service.START_STICKY: {
11506 // We are done with the associated start arguments.
11507 r.findDeliveredStart(startId, true);
11508 // Don't stop if killed.
11509 r.stopIfKilled = false;
11510 break;
11511 }
11512 case Service.START_NOT_STICKY: {
11513 // We are done with the associated start arguments.
11514 r.findDeliveredStart(startId, true);
11515 if (r.lastStartId == startId) {
11516 // There is no more work, and this service
11517 // doesn't want to hang around if killed.
11518 r.stopIfKilled = true;
11519 }
11520 break;
11521 }
11522 case Service.START_REDELIVER_INTENT: {
11523 // We'll keep this item until they explicitly
11524 // call stop for it, but keep track of the fact
11525 // that it was delivered.
11526 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11527 if (si != null) {
11528 si.deliveryCount = 0;
11529 si.doneExecutingCount++;
11530 // Don't stop if killed.
11531 r.stopIfKilled = true;
11532 }
11533 break;
11534 }
11535 default:
11536 throw new IllegalArgumentException(
11537 "Unknown service start result: " + res);
11538 }
11539 if (res == Service.START_STICKY_COMPATIBILITY) {
11540 r.callStart = false;
11541 }
11542 }
11543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011544 final long origId = Binder.clearCallingIdentity();
11545 serviceDoneExecutingLocked(r, inStopping);
11546 Binder.restoreCallingIdentity(origId);
11547 } else {
11548 Log.w(TAG, "Done executing unknown service " + r.name
11549 + " with token " + token);
11550 }
11551 }
11552 }
11553
11554 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11555 r.executeNesting--;
11556 if (r.executeNesting <= 0 && r.app != null) {
11557 r.app.executingServices.remove(r);
11558 if (r.app.executingServices.size() == 0) {
11559 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11560 }
11561 if (inStopping) {
11562 mStoppingServices.remove(r);
11563 }
11564 updateOomAdjLocked(r.app);
11565 }
11566 }
11567
11568 void serviceTimeout(ProcessRecord proc) {
11569 synchronized(this) {
11570 if (proc.executingServices.size() == 0 || proc.thread == null) {
11571 return;
11572 }
11573 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11574 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11575 ServiceRecord timeout = null;
11576 long nextTime = 0;
11577 while (it.hasNext()) {
11578 ServiceRecord sr = it.next();
11579 if (sr.executingStart < maxTime) {
11580 timeout = sr;
11581 break;
11582 }
11583 if (sr.executingStart > nextTime) {
11584 nextTime = sr.executingStart;
11585 }
11586 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011587 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011588 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnor42471dd2010-01-07 17:25:22 -080011589 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011590 } else {
11591 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11592 msg.obj = proc;
11593 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11594 }
11595 }
11596 }
11597
11598 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011599 // BACKUP AND RESTORE
11600 // =========================================================
11601
11602 // Cause the target app to be launched if necessary and its backup agent
11603 // instantiated. The backup agent will invoke backupAgentCreated() on the
11604 // activity manager to announce its creation.
11605 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11606 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11607 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11608
11609 synchronized(this) {
11610 // !!! TODO: currently no check here that we're already bound
11611 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11612 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11613 synchronized (stats) {
11614 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11615 }
11616
11617 BackupRecord r = new BackupRecord(ss, app, backupMode);
11618 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11619 // startProcessLocked() returns existing proc's record if it's already running
11620 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011621 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011622 if (proc == null) {
11623 Log.e(TAG, "Unable to start backup agent process " + r);
11624 return false;
11625 }
11626
11627 r.app = proc;
11628 mBackupTarget = r;
11629 mBackupAppName = app.packageName;
11630
Christopher Tate6fa95972009-06-05 18:43:55 -070011631 // Try not to kill the process during backup
11632 updateOomAdjLocked(proc);
11633
Christopher Tate181fafa2009-05-14 11:12:14 -070011634 // If the process is already attached, schedule the creation of the backup agent now.
11635 // If it is not yet live, this will be done when it attaches to the framework.
11636 if (proc.thread != null) {
11637 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11638 try {
11639 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11640 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011641 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011642 }
11643 } else {
11644 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11645 }
11646 // Invariants: at this point, the target app process exists and the application
11647 // is either already running or in the process of coming up. mBackupTarget and
11648 // mBackupAppName describe the app, so that when it binds back to the AM we
11649 // know that it's scheduled for a backup-agent operation.
11650 }
11651
11652 return true;
11653 }
11654
11655 // A backup agent has just come up
11656 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11657 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11658 + " = " + agent);
11659
11660 synchronized(this) {
11661 if (!agentPackageName.equals(mBackupAppName)) {
11662 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11663 return;
11664 }
11665
Christopher Tate043dadc2009-06-02 16:11:00 -070011666 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011667 try {
11668 IBackupManager bm = IBackupManager.Stub.asInterface(
11669 ServiceManager.getService(Context.BACKUP_SERVICE));
11670 bm.agentConnected(agentPackageName, agent);
11671 } catch (RemoteException e) {
11672 // can't happen; the backup manager service is local
11673 } catch (Exception e) {
11674 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11675 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011676 } finally {
11677 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011678 }
11679 }
11680 }
11681
11682 // done with this agent
11683 public void unbindBackupAgent(ApplicationInfo appInfo) {
11684 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011685 if (appInfo == null) {
11686 Log.w(TAG, "unbind backup agent for null app");
11687 return;
11688 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011689
11690 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011691 if (mBackupAppName == null) {
11692 Log.w(TAG, "Unbinding backup agent with no active backup");
11693 return;
11694 }
11695
Christopher Tate181fafa2009-05-14 11:12:14 -070011696 if (!mBackupAppName.equals(appInfo.packageName)) {
11697 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11698 return;
11699 }
11700
Christopher Tate6fa95972009-06-05 18:43:55 -070011701 ProcessRecord proc = mBackupTarget.app;
11702 mBackupTarget = null;
11703 mBackupAppName = null;
11704
11705 // Not backing this app up any more; reset its OOM adjustment
11706 updateOomAdjLocked(proc);
11707
Christopher Tatec7b31e32009-06-10 15:49:30 -070011708 // If the app crashed during backup, 'thread' will be null here
11709 if (proc.thread != null) {
11710 try {
11711 proc.thread.scheduleDestroyBackupAgent(appInfo);
11712 } catch (Exception e) {
11713 Log.e(TAG, "Exception when unbinding backup agent:");
11714 e.printStackTrace();
11715 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011716 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011717 }
11718 }
11719 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011720 // BROADCASTS
11721 // =========================================================
11722
11723 private final List getStickies(String action, IntentFilter filter,
11724 List cur) {
11725 final ContentResolver resolver = mContext.getContentResolver();
11726 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11727 if (list == null) {
11728 return cur;
11729 }
11730 int N = list.size();
11731 for (int i=0; i<N; i++) {
11732 Intent intent = list.get(i);
11733 if (filter.match(resolver, intent, true, TAG) >= 0) {
11734 if (cur == null) {
11735 cur = new ArrayList<Intent>();
11736 }
11737 cur.add(intent);
11738 }
11739 }
11740 return cur;
11741 }
11742
11743 private final void scheduleBroadcastsLocked() {
11744 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11745 + mBroadcastsScheduled);
11746
11747 if (mBroadcastsScheduled) {
11748 return;
11749 }
11750 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11751 mBroadcastsScheduled = true;
11752 }
11753
11754 public Intent registerReceiver(IApplicationThread caller,
11755 IIntentReceiver receiver, IntentFilter filter, String permission) {
11756 synchronized(this) {
11757 ProcessRecord callerApp = null;
11758 if (caller != null) {
11759 callerApp = getRecordForAppLocked(caller);
11760 if (callerApp == null) {
11761 throw new SecurityException(
11762 "Unable to find app for caller " + caller
11763 + " (pid=" + Binder.getCallingPid()
11764 + ") when registering receiver " + receiver);
11765 }
11766 }
11767
11768 List allSticky = null;
11769
11770 // Look for any matching sticky broadcasts...
11771 Iterator actions = filter.actionsIterator();
11772 if (actions != null) {
11773 while (actions.hasNext()) {
11774 String action = (String)actions.next();
11775 allSticky = getStickies(action, filter, allSticky);
11776 }
11777 } else {
11778 allSticky = getStickies(null, filter, allSticky);
11779 }
11780
11781 // The first sticky in the list is returned directly back to
11782 // the client.
11783 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11784
11785 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11786 + ": " + sticky);
11787
11788 if (receiver == null) {
11789 return sticky;
11790 }
11791
11792 ReceiverList rl
11793 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11794 if (rl == null) {
11795 rl = new ReceiverList(this, callerApp,
11796 Binder.getCallingPid(),
11797 Binder.getCallingUid(), receiver);
11798 if (rl.app != null) {
11799 rl.app.receivers.add(rl);
11800 } else {
11801 try {
11802 receiver.asBinder().linkToDeath(rl, 0);
11803 } catch (RemoteException e) {
11804 return sticky;
11805 }
11806 rl.linkedToDeath = true;
11807 }
11808 mRegisteredReceivers.put(receiver.asBinder(), rl);
11809 }
11810 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11811 rl.add(bf);
11812 if (!bf.debugCheck()) {
11813 Log.w(TAG, "==> For Dynamic broadast");
11814 }
11815 mReceiverResolver.addFilter(bf);
11816
11817 // Enqueue broadcasts for all existing stickies that match
11818 // this filter.
11819 if (allSticky != null) {
11820 ArrayList receivers = new ArrayList();
11821 receivers.add(bf);
11822
11823 int N = allSticky.size();
11824 for (int i=0; i<N; i++) {
11825 Intent intent = (Intent)allSticky.get(i);
11826 BroadcastRecord r = new BroadcastRecord(intent, null,
11827 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011828 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011829 if (mParallelBroadcasts.size() == 0) {
11830 scheduleBroadcastsLocked();
11831 }
11832 mParallelBroadcasts.add(r);
11833 }
11834 }
11835
11836 return sticky;
11837 }
11838 }
11839
11840 public void unregisterReceiver(IIntentReceiver receiver) {
11841 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11842
11843 boolean doNext = false;
11844
11845 synchronized(this) {
11846 ReceiverList rl
11847 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11848 if (rl != null) {
11849 if (rl.curBroadcast != null) {
11850 BroadcastRecord r = rl.curBroadcast;
11851 doNext = finishReceiverLocked(
11852 receiver.asBinder(), r.resultCode, r.resultData,
11853 r.resultExtras, r.resultAbort, true);
11854 }
11855
11856 if (rl.app != null) {
11857 rl.app.receivers.remove(rl);
11858 }
11859 removeReceiverLocked(rl);
11860 if (rl.linkedToDeath) {
11861 rl.linkedToDeath = false;
11862 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11863 }
11864 }
11865 }
11866
11867 if (!doNext) {
11868 return;
11869 }
11870
11871 final long origId = Binder.clearCallingIdentity();
11872 processNextBroadcast(false);
11873 trimApplications();
11874 Binder.restoreCallingIdentity(origId);
11875 }
11876
11877 void removeReceiverLocked(ReceiverList rl) {
11878 mRegisteredReceivers.remove(rl.receiver.asBinder());
11879 int N = rl.size();
11880 for (int i=0; i<N; i++) {
11881 mReceiverResolver.removeFilter(rl.get(i));
11882 }
11883 }
11884
11885 private final int broadcastIntentLocked(ProcessRecord callerApp,
11886 String callerPackage, Intent intent, String resolvedType,
11887 IIntentReceiver resultTo, int resultCode, String resultData,
11888 Bundle map, String requiredPermission,
11889 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11890 intent = new Intent(intent);
11891
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011892 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011893 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11894 + " ordered=" + ordered);
11895 if ((resultTo != null) && !ordered) {
11896 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11897 }
11898
11899 // Handle special intents: if this broadcast is from the package
11900 // manager about a package being removed, we need to remove all of
11901 // its activities from the history stack.
11902 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11903 intent.getAction());
11904 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11905 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11906 || uidRemoved) {
11907 if (checkComponentPermission(
11908 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11909 callingPid, callingUid, -1)
11910 == PackageManager.PERMISSION_GRANTED) {
11911 if (uidRemoved) {
11912 final Bundle intentExtras = intent.getExtras();
11913 final int uid = intentExtras != null
11914 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11915 if (uid >= 0) {
11916 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11917 synchronized (bs) {
11918 bs.removeUidStatsLocked(uid);
11919 }
11920 }
11921 } else {
11922 Uri data = intent.getData();
11923 String ssp;
11924 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11925 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -080011926 forceStopPackageLocked(ssp,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011927 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011928 AttributeCache ac = AttributeCache.instance();
11929 if (ac != null) {
11930 ac.removePackage(ssp);
11931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011932 }
11933 }
11934 }
11935 } else {
11936 String msg = "Permission Denial: " + intent.getAction()
11937 + " broadcast from " + callerPackage + " (pid=" + callingPid
11938 + ", uid=" + callingUid + ")"
11939 + " requires "
11940 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11941 Log.w(TAG, msg);
11942 throw new SecurityException(msg);
11943 }
11944 }
11945
11946 /*
11947 * If this is the time zone changed action, queue up a message that will reset the timezone
11948 * of all currently running processes. This message will get queued up before the broadcast
11949 * happens.
11950 */
11951 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11952 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11953 }
11954
Dianne Hackborn854060af2009-07-09 18:14:31 -070011955 /*
11956 * Prevent non-system code (defined here to be non-persistent
11957 * processes) from sending protected broadcasts.
11958 */
11959 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11960 || callingUid == Process.SHELL_UID || callingUid == 0) {
11961 // Always okay.
11962 } else if (callerApp == null || !callerApp.persistent) {
11963 try {
11964 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11965 intent.getAction())) {
11966 String msg = "Permission Denial: not allowed to send broadcast "
11967 + intent.getAction() + " from pid="
11968 + callingPid + ", uid=" + callingUid;
11969 Log.w(TAG, msg);
11970 throw new SecurityException(msg);
11971 }
11972 } catch (RemoteException e) {
11973 Log.w(TAG, "Remote exception", e);
11974 return BROADCAST_SUCCESS;
11975 }
11976 }
11977
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011978 // Add to the sticky list if requested.
11979 if (sticky) {
11980 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11981 callingPid, callingUid)
11982 != PackageManager.PERMISSION_GRANTED) {
11983 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11984 + callingPid + ", uid=" + callingUid
11985 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11986 Log.w(TAG, msg);
11987 throw new SecurityException(msg);
11988 }
11989 if (requiredPermission != null) {
11990 Log.w(TAG, "Can't broadcast sticky intent " + intent
11991 + " and enforce permission " + requiredPermission);
11992 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11993 }
11994 if (intent.getComponent() != null) {
11995 throw new SecurityException(
11996 "Sticky broadcasts can't target a specific component");
11997 }
11998 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11999 if (list == null) {
12000 list = new ArrayList<Intent>();
12001 mStickyBroadcasts.put(intent.getAction(), list);
12002 }
12003 int N = list.size();
12004 int i;
12005 for (i=0; i<N; i++) {
12006 if (intent.filterEquals(list.get(i))) {
12007 // This sticky already exists, replace it.
12008 list.set(i, new Intent(intent));
12009 break;
12010 }
12011 }
12012 if (i >= N) {
12013 list.add(new Intent(intent));
12014 }
12015 }
12016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012017 // Figure out who all will receive this broadcast.
12018 List receivers = null;
12019 List<BroadcastFilter> registeredReceivers = null;
12020 try {
12021 if (intent.getComponent() != null) {
12022 // Broadcast is going to one specific receiver class...
12023 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012024 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012025 if (ai != null) {
12026 receivers = new ArrayList();
12027 ResolveInfo ri = new ResolveInfo();
12028 ri.activityInfo = ai;
12029 receivers.add(ri);
12030 }
12031 } else {
12032 // Need to resolve the intent to interested receivers...
12033 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12034 == 0) {
12035 receivers =
12036 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012037 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012038 }
Mihai Preda074edef2009-05-18 17:13:31 +020012039 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012040 }
12041 } catch (RemoteException ex) {
12042 // pm is in same process, this will never happen.
12043 }
12044
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012045 final boolean replacePending =
12046 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12047
12048 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12049 + " replacePending=" + replacePending);
12050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012051 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12052 if (!ordered && NR > 0) {
12053 // If we are not serializing this broadcast, then send the
12054 // registered receivers separately so they don't wait for the
12055 // components to be launched.
12056 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12057 callerPackage, callingPid, callingUid, requiredPermission,
12058 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012059 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012060 if (DEBUG_BROADCAST) Log.v(
12061 TAG, "Enqueueing parallel broadcast " + r
12062 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012063 boolean replaced = false;
12064 if (replacePending) {
12065 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12066 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12067 if (DEBUG_BROADCAST) Log.v(TAG,
12068 "***** DROPPING PARALLEL: " + intent);
12069 mParallelBroadcasts.set(i, r);
12070 replaced = true;
12071 break;
12072 }
12073 }
12074 }
12075 if (!replaced) {
12076 mParallelBroadcasts.add(r);
12077 scheduleBroadcastsLocked();
12078 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012079 registeredReceivers = null;
12080 NR = 0;
12081 }
12082
12083 // Merge into one list.
12084 int ir = 0;
12085 if (receivers != null) {
12086 // A special case for PACKAGE_ADDED: do not allow the package
12087 // being added to see this broadcast. This prevents them from
12088 // using this as a back door to get run as soon as they are
12089 // installed. Maybe in the future we want to have a special install
12090 // broadcast or such for apps, but we'd like to deliberately make
12091 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070012092 boolean skip = false;
12093 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070012094 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070012095 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
12096 skip = true;
12097 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12098 skip = true;
12099 }
12100 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012101 ? intent.getData().getSchemeSpecificPart()
12102 : null;
12103 if (skipPackage != null && receivers != null) {
12104 int NT = receivers.size();
12105 for (int it=0; it<NT; it++) {
12106 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12107 if (curt.activityInfo.packageName.equals(skipPackage)) {
12108 receivers.remove(it);
12109 it--;
12110 NT--;
12111 }
12112 }
12113 }
12114
12115 int NT = receivers != null ? receivers.size() : 0;
12116 int it = 0;
12117 ResolveInfo curt = null;
12118 BroadcastFilter curr = null;
12119 while (it < NT && ir < NR) {
12120 if (curt == null) {
12121 curt = (ResolveInfo)receivers.get(it);
12122 }
12123 if (curr == null) {
12124 curr = registeredReceivers.get(ir);
12125 }
12126 if (curr.getPriority() >= curt.priority) {
12127 // Insert this broadcast record into the final list.
12128 receivers.add(it, curr);
12129 ir++;
12130 curr = null;
12131 it++;
12132 NT++;
12133 } else {
12134 // Skip to the next ResolveInfo in the final list.
12135 it++;
12136 curt = null;
12137 }
12138 }
12139 }
12140 while (ir < NR) {
12141 if (receivers == null) {
12142 receivers = new ArrayList();
12143 }
12144 receivers.add(registeredReceivers.get(ir));
12145 ir++;
12146 }
12147
12148 if ((receivers != null && receivers.size() > 0)
12149 || resultTo != null) {
12150 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12151 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012152 receivers, resultTo, resultCode, resultData, map, ordered,
12153 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012154 if (DEBUG_BROADCAST) Log.v(
12155 TAG, "Enqueueing ordered broadcast " + r
12156 + ": prev had " + mOrderedBroadcasts.size());
12157 if (DEBUG_BROADCAST) {
12158 int seq = r.intent.getIntExtra("seq", -1);
12159 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12160 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012161 boolean replaced = false;
12162 if (replacePending) {
12163 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12164 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12165 if (DEBUG_BROADCAST) Log.v(TAG,
12166 "***** DROPPING ORDERED: " + intent);
12167 mOrderedBroadcasts.set(i, r);
12168 replaced = true;
12169 break;
12170 }
12171 }
12172 }
12173 if (!replaced) {
12174 mOrderedBroadcasts.add(r);
12175 scheduleBroadcastsLocked();
12176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012177 }
12178
12179 return BROADCAST_SUCCESS;
12180 }
12181
12182 public final int broadcastIntent(IApplicationThread caller,
12183 Intent intent, String resolvedType, IIntentReceiver resultTo,
12184 int resultCode, String resultData, Bundle map,
12185 String requiredPermission, boolean serialized, boolean sticky) {
12186 // Refuse possible leaked file descriptors
12187 if (intent != null && intent.hasFileDescriptors() == true) {
12188 throw new IllegalArgumentException("File descriptors passed in Intent");
12189 }
12190
12191 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012192 int flags = intent.getFlags();
12193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012194 if (!mSystemReady) {
12195 // if the caller really truly claims to know what they're doing, go
12196 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012197 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12198 intent = new Intent(intent);
12199 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12200 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12201 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12202 + " before boot completion");
12203 throw new IllegalStateException("Cannot broadcast before boot completed");
12204 }
12205 }
12206
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012207 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12208 throw new IllegalArgumentException(
12209 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12210 }
12211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012212 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12213 final int callingPid = Binder.getCallingPid();
12214 final int callingUid = Binder.getCallingUid();
12215 final long origId = Binder.clearCallingIdentity();
12216 int res = broadcastIntentLocked(callerApp,
12217 callerApp != null ? callerApp.info.packageName : null,
12218 intent, resolvedType, resultTo,
12219 resultCode, resultData, map, requiredPermission, serialized,
12220 sticky, callingPid, callingUid);
12221 Binder.restoreCallingIdentity(origId);
12222 return res;
12223 }
12224 }
12225
12226 int broadcastIntentInPackage(String packageName, int uid,
12227 Intent intent, String resolvedType, IIntentReceiver resultTo,
12228 int resultCode, String resultData, Bundle map,
12229 String requiredPermission, boolean serialized, boolean sticky) {
12230 synchronized(this) {
12231 final long origId = Binder.clearCallingIdentity();
12232 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12233 resultTo, resultCode, resultData, map, requiredPermission,
12234 serialized, sticky, -1, uid);
12235 Binder.restoreCallingIdentity(origId);
12236 return res;
12237 }
12238 }
12239
12240 public final void unbroadcastIntent(IApplicationThread caller,
12241 Intent intent) {
12242 // Refuse possible leaked file descriptors
12243 if (intent != null && intent.hasFileDescriptors() == true) {
12244 throw new IllegalArgumentException("File descriptors passed in Intent");
12245 }
12246
12247 synchronized(this) {
12248 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12249 != PackageManager.PERMISSION_GRANTED) {
12250 String msg = "Permission Denial: unbroadcastIntent() from pid="
12251 + Binder.getCallingPid()
12252 + ", uid=" + Binder.getCallingUid()
12253 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12254 Log.w(TAG, msg);
12255 throw new SecurityException(msg);
12256 }
12257 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12258 if (list != null) {
12259 int N = list.size();
12260 int i;
12261 for (i=0; i<N; i++) {
12262 if (intent.filterEquals(list.get(i))) {
12263 list.remove(i);
12264 break;
12265 }
12266 }
12267 }
12268 }
12269 }
12270
12271 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12272 String resultData, Bundle resultExtras, boolean resultAbort,
12273 boolean explicit) {
12274 if (mOrderedBroadcasts.size() == 0) {
12275 if (explicit) {
12276 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12277 }
12278 return false;
12279 }
12280 BroadcastRecord r = mOrderedBroadcasts.get(0);
12281 if (r.receiver == null) {
12282 if (explicit) {
12283 Log.w(TAG, "finishReceiver called but none active");
12284 }
12285 return false;
12286 }
12287 if (r.receiver != receiver) {
12288 Log.w(TAG, "finishReceiver called but active receiver is different");
12289 return false;
12290 }
12291 int state = r.state;
12292 r.state = r.IDLE;
12293 if (state == r.IDLE) {
12294 if (explicit) {
12295 Log.w(TAG, "finishReceiver called but state is IDLE");
12296 }
12297 }
12298 r.receiver = null;
12299 r.intent.setComponent(null);
12300 if (r.curApp != null) {
12301 r.curApp.curReceiver = null;
12302 }
12303 if (r.curFilter != null) {
12304 r.curFilter.receiverList.curBroadcast = null;
12305 }
12306 r.curFilter = null;
12307 r.curApp = null;
12308 r.curComponent = null;
12309 r.curReceiver = null;
12310 mPendingBroadcast = null;
12311
12312 r.resultCode = resultCode;
12313 r.resultData = resultData;
12314 r.resultExtras = resultExtras;
12315 r.resultAbort = resultAbort;
12316
12317 // We will process the next receiver right now if this is finishing
12318 // an app receiver (which is always asynchronous) or after we have
12319 // come back from calling a receiver.
12320 return state == BroadcastRecord.APP_RECEIVE
12321 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12322 }
12323
12324 public void finishReceiver(IBinder who, int resultCode, String resultData,
12325 Bundle resultExtras, boolean resultAbort) {
12326 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12327
12328 // Refuse possible leaked file descriptors
12329 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12330 throw new IllegalArgumentException("File descriptors passed in Bundle");
12331 }
12332
12333 boolean doNext;
12334
12335 final long origId = Binder.clearCallingIdentity();
12336
12337 synchronized(this) {
12338 doNext = finishReceiverLocked(
12339 who, resultCode, resultData, resultExtras, resultAbort, true);
12340 }
12341
12342 if (doNext) {
12343 processNextBroadcast(false);
12344 }
12345 trimApplications();
12346
12347 Binder.restoreCallingIdentity(origId);
12348 }
12349
12350 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12351 if (r.nextReceiver > 0) {
12352 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12353 if (curReceiver instanceof BroadcastFilter) {
12354 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012355 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012356 System.identityHashCode(r),
12357 r.intent.getAction(),
12358 r.nextReceiver - 1,
12359 System.identityHashCode(bf));
12360 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012361 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012362 System.identityHashCode(r),
12363 r.intent.getAction(),
12364 r.nextReceiver - 1,
12365 ((ResolveInfo)curReceiver).toString());
12366 }
12367 } else {
12368 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12369 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012370 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012371 System.identityHashCode(r),
12372 r.intent.getAction(),
12373 r.nextReceiver,
12374 "NONE");
12375 }
12376 }
12377
12378 private final void broadcastTimeout() {
12379 synchronized (this) {
12380 if (mOrderedBroadcasts.size() == 0) {
12381 return;
12382 }
12383 long now = SystemClock.uptimeMillis();
12384 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012385 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012386 if (DEBUG_BROADCAST) Log.v(TAG,
12387 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012388 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012389 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012390 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012391 return;
12392 }
12393
12394 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012395 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012396 r.anrCount++;
12397
12398 // Current receiver has passed its expiration date.
12399 if (r.nextReceiver <= 0) {
12400 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12401 return;
12402 }
12403
12404 ProcessRecord app = null;
12405
12406 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12407 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12408 logBroadcastReceiverDiscard(r);
12409 if (curReceiver instanceof BroadcastFilter) {
12410 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12411 if (bf.receiverList.pid != 0
12412 && bf.receiverList.pid != MY_PID) {
12413 synchronized (this.mPidsSelfLocked) {
12414 app = this.mPidsSelfLocked.get(
12415 bf.receiverList.pid);
12416 }
12417 }
12418 } else {
12419 app = r.curApp;
12420 }
12421
12422 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012423 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012424 }
12425
12426 if (mPendingBroadcast == r) {
12427 mPendingBroadcast = null;
12428 }
12429
12430 // Move on to the next receiver.
12431 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12432 r.resultExtras, r.resultAbort, true);
12433 scheduleBroadcastsLocked();
12434 }
12435 }
12436
12437 private final void processCurBroadcastLocked(BroadcastRecord r,
12438 ProcessRecord app) throws RemoteException {
12439 if (app.thread == null) {
12440 throw new RemoteException();
12441 }
12442 r.receiver = app.thread.asBinder();
12443 r.curApp = app;
12444 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012445 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012446
12447 // Tell the application to launch this receiver.
12448 r.intent.setComponent(r.curComponent);
12449
12450 boolean started = false;
12451 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012452 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012453 "Delivering to component " + r.curComponent
12454 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012455 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012456 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12457 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12458 started = true;
12459 } finally {
12460 if (!started) {
12461 r.receiver = null;
12462 r.curApp = null;
12463 app.curReceiver = null;
12464 }
12465 }
12466
12467 }
12468
12469 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012470 Intent intent, int resultCode, String data, Bundle extras,
12471 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012472 if (app != null && app.thread != null) {
12473 // If we have an app thread, do the call through that so it is
12474 // correctly ordered with other one-way calls.
12475 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012476 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012477 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012478 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012479 }
12480 }
12481
12482 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12483 BroadcastFilter filter, boolean ordered) {
12484 boolean skip = false;
12485 if (filter.requiredPermission != null) {
12486 int perm = checkComponentPermission(filter.requiredPermission,
12487 r.callingPid, r.callingUid, -1);
12488 if (perm != PackageManager.PERMISSION_GRANTED) {
12489 Log.w(TAG, "Permission Denial: broadcasting "
12490 + r.intent.toString()
12491 + " from " + r.callerPackage + " (pid="
12492 + r.callingPid + ", uid=" + r.callingUid + ")"
12493 + " requires " + filter.requiredPermission
12494 + " due to registered receiver " + filter);
12495 skip = true;
12496 }
12497 }
12498 if (r.requiredPermission != null) {
12499 int perm = checkComponentPermission(r.requiredPermission,
12500 filter.receiverList.pid, filter.receiverList.uid, -1);
12501 if (perm != PackageManager.PERMISSION_GRANTED) {
12502 Log.w(TAG, "Permission Denial: receiving "
12503 + r.intent.toString()
12504 + " to " + filter.receiverList.app
12505 + " (pid=" + filter.receiverList.pid
12506 + ", uid=" + filter.receiverList.uid + ")"
12507 + " requires " + r.requiredPermission
12508 + " due to sender " + r.callerPackage
12509 + " (uid " + r.callingUid + ")");
12510 skip = true;
12511 }
12512 }
12513
12514 if (!skip) {
12515 // If this is not being sent as an ordered broadcast, then we
12516 // don't want to touch the fields that keep track of the current
12517 // state of ordered broadcasts.
12518 if (ordered) {
12519 r.receiver = filter.receiverList.receiver.asBinder();
12520 r.curFilter = filter;
12521 filter.receiverList.curBroadcast = r;
12522 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012523 if (filter.receiverList.app != null) {
12524 // Bump hosting application to no longer be in background
12525 // scheduling class. Note that we can't do that if there
12526 // isn't an app... but we can only be in that case for
12527 // things that directly call the IActivityManager API, which
12528 // are already core system stuff so don't matter for this.
12529 r.curApp = filter.receiverList.app;
12530 filter.receiverList.app.curReceiver = r;
12531 updateOomAdjLocked();
12532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012533 }
12534 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012535 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012536 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012537 Log.i(TAG, "Delivering to " + filter.receiverList.app
12538 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012539 }
12540 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12541 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012542 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012543 if (ordered) {
12544 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12545 }
12546 } catch (RemoteException e) {
12547 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12548 if (ordered) {
12549 r.receiver = null;
12550 r.curFilter = null;
12551 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012552 if (filter.receiverList.app != null) {
12553 filter.receiverList.app.curReceiver = null;
12554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012555 }
12556 }
12557 }
12558 }
12559
Dianne Hackborn12527f92009-11-11 17:39:50 -080012560 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12561 if (r.callingUid < 0) {
12562 // This was from a registerReceiver() call; ignore it.
12563 return;
12564 }
12565 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12566 MAX_BROADCAST_HISTORY-1);
12567 r.finishTime = SystemClock.uptimeMillis();
12568 mBroadcastHistory[0] = r;
12569 }
12570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012571 private final void processNextBroadcast(boolean fromMsg) {
12572 synchronized(this) {
12573 BroadcastRecord r;
12574
12575 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12576 + mParallelBroadcasts.size() + " broadcasts, "
12577 + mOrderedBroadcasts.size() + " serialized broadcasts");
12578
12579 updateCpuStats();
12580
12581 if (fromMsg) {
12582 mBroadcastsScheduled = false;
12583 }
12584
12585 // First, deliver any non-serialized broadcasts right away.
12586 while (mParallelBroadcasts.size() > 0) {
12587 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012588 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012589 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012590 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12591 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012592 for (int i=0; i<N; i++) {
12593 Object target = r.receivers.get(i);
12594 if (DEBUG_BROADCAST) Log.v(TAG,
12595 "Delivering non-serialized to registered "
12596 + target + ": " + r);
12597 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12598 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012599 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012600 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12601 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012602 }
12603
12604 // Now take care of the next serialized one...
12605
12606 // If we are waiting for a process to come up to handle the next
12607 // broadcast, then do nothing at this point. Just in case, we
12608 // check that the process we're waiting for still exists.
12609 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012610 if (DEBUG_BROADCAST_LIGHT) {
12611 Log.v(TAG, "processNextBroadcast: waiting for "
12612 + mPendingBroadcast.curApp);
12613 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012614
12615 boolean isDead;
12616 synchronized (mPidsSelfLocked) {
12617 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12618 }
12619 if (!isDead) {
12620 // It's still alive, so keep waiting
12621 return;
12622 } else {
12623 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12624 + " died before responding to broadcast");
12625 mPendingBroadcast = null;
12626 }
12627 }
12628
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012629 boolean looped = false;
12630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012631 do {
12632 if (mOrderedBroadcasts.size() == 0) {
12633 // No more broadcasts pending, so all done!
12634 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012635 if (looped) {
12636 // If we had finished the last ordered broadcast, then
12637 // make sure all processes have correct oom and sched
12638 // adjustments.
12639 updateOomAdjLocked();
12640 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012641 return;
12642 }
12643 r = mOrderedBroadcasts.get(0);
12644 boolean forceReceive = false;
12645
12646 // Ensure that even if something goes awry with the timeout
12647 // detection, we catch "hung" broadcasts here, discard them,
12648 // and continue to make progress.
12649 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12650 long now = SystemClock.uptimeMillis();
12651 if (r.dispatchTime > 0) {
12652 if ((numReceivers > 0) &&
12653 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12654 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12655 + " now=" + now
12656 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012657 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012658 + " intent=" + r.intent
12659 + " numReceivers=" + numReceivers
12660 + " nextReceiver=" + r.nextReceiver
12661 + " state=" + r.state);
12662 broadcastTimeout(); // forcibly finish this broadcast
12663 forceReceive = true;
12664 r.state = BroadcastRecord.IDLE;
12665 }
12666 }
12667
12668 if (r.state != BroadcastRecord.IDLE) {
12669 if (DEBUG_BROADCAST) Log.d(TAG,
12670 "processNextBroadcast() called when not idle (state="
12671 + r.state + ")");
12672 return;
12673 }
12674
12675 if (r.receivers == null || r.nextReceiver >= numReceivers
12676 || r.resultAbort || forceReceive) {
12677 // No more receivers for this broadcast! Send the final
12678 // result if requested...
12679 if (r.resultTo != null) {
12680 try {
12681 if (DEBUG_BROADCAST) {
12682 int seq = r.intent.getIntExtra("seq", -1);
12683 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12684 + " seq=" + seq + " app=" + r.callerApp);
12685 }
12686 performReceive(r.callerApp, r.resultTo,
12687 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012688 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012689 } catch (RemoteException e) {
12690 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12691 }
12692 }
12693
12694 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12695 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12696
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012697 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12698 + r);
12699
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012700 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012701 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012702 mOrderedBroadcasts.remove(0);
12703 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012704 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012705 continue;
12706 }
12707 } while (r == null);
12708
12709 // Get the next receiver...
12710 int recIdx = r.nextReceiver++;
12711
12712 // Keep track of when this receiver started, and make sure there
12713 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012714 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012715 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012716 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012717
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012718 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12719 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012720 if (DEBUG_BROADCAST) Log.v(TAG,
12721 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012722 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012723 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012724 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012725 }
12726
12727 Object nextReceiver = r.receivers.get(recIdx);
12728 if (nextReceiver instanceof BroadcastFilter) {
12729 // Simple case: this is a registered receiver who gets
12730 // a direct call.
12731 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12732 if (DEBUG_BROADCAST) Log.v(TAG,
12733 "Delivering serialized to registered "
12734 + filter + ": " + r);
12735 deliverToRegisteredReceiver(r, filter, r.ordered);
12736 if (r.receiver == null || !r.ordered) {
12737 // The receiver has already finished, so schedule to
12738 // process the next one.
12739 r.state = BroadcastRecord.IDLE;
12740 scheduleBroadcastsLocked();
12741 }
12742 return;
12743 }
12744
12745 // Hard case: need to instantiate the receiver, possibly
12746 // starting its application process to host it.
12747
12748 ResolveInfo info =
12749 (ResolveInfo)nextReceiver;
12750
12751 boolean skip = false;
12752 int perm = checkComponentPermission(info.activityInfo.permission,
12753 r.callingPid, r.callingUid,
12754 info.activityInfo.exported
12755 ? -1 : info.activityInfo.applicationInfo.uid);
12756 if (perm != PackageManager.PERMISSION_GRANTED) {
12757 Log.w(TAG, "Permission Denial: broadcasting "
12758 + r.intent.toString()
12759 + " from " + r.callerPackage + " (pid=" + r.callingPid
12760 + ", uid=" + r.callingUid + ")"
12761 + " requires " + info.activityInfo.permission
12762 + " due to receiver " + info.activityInfo.packageName
12763 + "/" + info.activityInfo.name);
12764 skip = true;
12765 }
12766 if (r.callingUid != Process.SYSTEM_UID &&
12767 r.requiredPermission != null) {
12768 try {
12769 perm = ActivityThread.getPackageManager().
12770 checkPermission(r.requiredPermission,
12771 info.activityInfo.applicationInfo.packageName);
12772 } catch (RemoteException e) {
12773 perm = PackageManager.PERMISSION_DENIED;
12774 }
12775 if (perm != PackageManager.PERMISSION_GRANTED) {
12776 Log.w(TAG, "Permission Denial: receiving "
12777 + r.intent + " to "
12778 + info.activityInfo.applicationInfo.packageName
12779 + " requires " + r.requiredPermission
12780 + " due to sender " + r.callerPackage
12781 + " (uid " + r.callingUid + ")");
12782 skip = true;
12783 }
12784 }
12785 if (r.curApp != null && r.curApp.crashing) {
12786 // If the target process is crashing, just skip it.
12787 skip = true;
12788 }
12789
12790 if (skip) {
12791 r.receiver = null;
12792 r.curFilter = null;
12793 r.state = BroadcastRecord.IDLE;
12794 scheduleBroadcastsLocked();
12795 return;
12796 }
12797
12798 r.state = BroadcastRecord.APP_RECEIVE;
12799 String targetProcess = info.activityInfo.processName;
12800 r.curComponent = new ComponentName(
12801 info.activityInfo.applicationInfo.packageName,
12802 info.activityInfo.name);
12803 r.curReceiver = info.activityInfo;
12804
12805 // Is this receiver's application already running?
12806 ProcessRecord app = getProcessRecordLocked(targetProcess,
12807 info.activityInfo.applicationInfo.uid);
12808 if (app != null && app.thread != null) {
12809 try {
12810 processCurBroadcastLocked(r, app);
12811 return;
12812 } catch (RemoteException e) {
12813 Log.w(TAG, "Exception when sending broadcast to "
12814 + r.curComponent, e);
12815 }
12816
12817 // If a dead object exception was thrown -- fall through to
12818 // restart the application.
12819 }
12820
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012821 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012822 if ((r.curApp=startProcessLocked(targetProcess,
12823 info.activityInfo.applicationInfo, true,
12824 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012825 "broadcast", r.curComponent,
12826 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12827 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012828 // Ah, this recipient is unavailable. Finish it if necessary,
12829 // and mark the broadcast record as ready for the next.
12830 Log.w(TAG, "Unable to launch app "
12831 + info.activityInfo.applicationInfo.packageName + "/"
12832 + info.activityInfo.applicationInfo.uid + " for broadcast "
12833 + r.intent + ": process is bad");
12834 logBroadcastReceiverDiscard(r);
12835 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12836 r.resultExtras, r.resultAbort, true);
12837 scheduleBroadcastsLocked();
12838 r.state = BroadcastRecord.IDLE;
12839 return;
12840 }
12841
12842 mPendingBroadcast = r;
12843 }
12844 }
12845
12846 // =========================================================
12847 // INSTRUMENTATION
12848 // =========================================================
12849
12850 public boolean startInstrumentation(ComponentName className,
12851 String profileFile, int flags, Bundle arguments,
12852 IInstrumentationWatcher watcher) {
12853 // Refuse possible leaked file descriptors
12854 if (arguments != null && arguments.hasFileDescriptors()) {
12855 throw new IllegalArgumentException("File descriptors passed in Bundle");
12856 }
12857
12858 synchronized(this) {
12859 InstrumentationInfo ii = null;
12860 ApplicationInfo ai = null;
12861 try {
12862 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012863 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012864 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012865 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012866 } catch (PackageManager.NameNotFoundException e) {
12867 }
12868 if (ii == null) {
12869 reportStartInstrumentationFailure(watcher, className,
12870 "Unable to find instrumentation info for: " + className);
12871 return false;
12872 }
12873 if (ai == null) {
12874 reportStartInstrumentationFailure(watcher, className,
12875 "Unable to find instrumentation target package: " + ii.targetPackage);
12876 return false;
12877 }
12878
12879 int match = mContext.getPackageManager().checkSignatures(
12880 ii.targetPackage, ii.packageName);
12881 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12882 String msg = "Permission Denial: starting instrumentation "
12883 + className + " from pid="
12884 + Binder.getCallingPid()
12885 + ", uid=" + Binder.getCallingPid()
12886 + " not allowed because package " + ii.packageName
12887 + " does not have a signature matching the target "
12888 + ii.targetPackage;
12889 reportStartInstrumentationFailure(watcher, className, msg);
12890 throw new SecurityException(msg);
12891 }
12892
12893 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn03abb812010-01-04 18:43:19 -080012894 forceStopPackageLocked(ii.targetPackage, -1, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012895 ProcessRecord app = addAppLocked(ai);
12896 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012897 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012898 app.instrumentationProfileFile = profileFile;
12899 app.instrumentationArguments = arguments;
12900 app.instrumentationWatcher = watcher;
12901 app.instrumentationResultClass = className;
12902 Binder.restoreCallingIdentity(origId);
12903 }
12904
12905 return true;
12906 }
12907
12908 /**
12909 * Report errors that occur while attempting to start Instrumentation. Always writes the
12910 * error to the logs, but if somebody is watching, send the report there too. This enables
12911 * the "am" command to report errors with more information.
12912 *
12913 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12914 * @param cn The component name of the instrumentation.
12915 * @param report The error report.
12916 */
12917 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12918 ComponentName cn, String report) {
12919 Log.w(TAG, report);
12920 try {
12921 if (watcher != null) {
12922 Bundle results = new Bundle();
12923 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12924 results.putString("Error", report);
12925 watcher.instrumentationStatus(cn, -1, results);
12926 }
12927 } catch (RemoteException e) {
12928 Log.w(TAG, e);
12929 }
12930 }
12931
12932 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12933 if (app.instrumentationWatcher != null) {
12934 try {
12935 // NOTE: IInstrumentationWatcher *must* be oneway here
12936 app.instrumentationWatcher.instrumentationFinished(
12937 app.instrumentationClass,
12938 resultCode,
12939 results);
12940 } catch (RemoteException e) {
12941 }
12942 }
12943 app.instrumentationWatcher = null;
12944 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012945 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012946 app.instrumentationProfileFile = null;
12947 app.instrumentationArguments = null;
12948
Dianne Hackborn03abb812010-01-04 18:43:19 -080012949 forceStopPackageLocked(app.processName, -1, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012950 }
12951
12952 public void finishInstrumentation(IApplicationThread target,
12953 int resultCode, Bundle results) {
12954 // Refuse possible leaked file descriptors
12955 if (results != null && results.hasFileDescriptors()) {
12956 throw new IllegalArgumentException("File descriptors passed in Intent");
12957 }
12958
12959 synchronized(this) {
12960 ProcessRecord app = getRecordForAppLocked(target);
12961 if (app == null) {
12962 Log.w(TAG, "finishInstrumentation: no app for " + target);
12963 return;
12964 }
12965 final long origId = Binder.clearCallingIdentity();
12966 finishInstrumentationLocked(app, resultCode, results);
12967 Binder.restoreCallingIdentity(origId);
12968 }
12969 }
12970
12971 // =========================================================
12972 // CONFIGURATION
12973 // =========================================================
12974
12975 public ConfigurationInfo getDeviceConfigurationInfo() {
12976 ConfigurationInfo config = new ConfigurationInfo();
12977 synchronized (this) {
12978 config.reqTouchScreen = mConfiguration.touchscreen;
12979 config.reqKeyboardType = mConfiguration.keyboard;
12980 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012981 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12982 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012983 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12984 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012985 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12986 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012987 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12988 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012989 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012990 }
12991 return config;
12992 }
12993
12994 public Configuration getConfiguration() {
12995 Configuration ci;
12996 synchronized(this) {
12997 ci = new Configuration(mConfiguration);
12998 }
12999 return ci;
13000 }
13001
13002 public void updateConfiguration(Configuration values) {
13003 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13004 "updateConfiguration()");
13005
13006 synchronized(this) {
13007 if (values == null && mWindowManager != null) {
13008 // sentinel: fetch the current configuration from the window manager
13009 values = mWindowManager.computeNewConfiguration();
13010 }
13011
13012 final long origId = Binder.clearCallingIdentity();
13013 updateConfigurationLocked(values, null);
13014 Binder.restoreCallingIdentity(origId);
13015 }
13016 }
13017
13018 /**
13019 * Do either or both things: (1) change the current configuration, and (2)
13020 * make sure the given activity is running with the (now) current
13021 * configuration. Returns true if the activity has been left running, or
13022 * false if <var>starting</var> is being destroyed to match the new
13023 * configuration.
13024 */
13025 public boolean updateConfigurationLocked(Configuration values,
13026 HistoryRecord starting) {
13027 int changes = 0;
13028
13029 boolean kept = true;
13030
13031 if (values != null) {
13032 Configuration newConfig = new Configuration(mConfiguration);
13033 changes = newConfig.updateFrom(values);
13034 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013035 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013036 Log.i(TAG, "Updating configuration to: " + values);
13037 }
13038
Doug Zongker2bec3d42009-12-04 12:52:44 -080013039 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013040
13041 if (values.locale != null) {
13042 saveLocaleLocked(values.locale,
13043 !values.locale.equals(mConfiguration.locale),
13044 values.userSetLocale);
13045 }
13046
13047 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013048 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013049
13050 AttributeCache ac = AttributeCache.instance();
13051 if (ac != null) {
13052 ac.updateConfiguration(mConfiguration);
13053 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013054
13055 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13056 msg.obj = new Configuration(mConfiguration);
13057 mHandler.sendMessage(msg);
13058
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013059 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13060 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013061 try {
13062 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013063 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13064 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013065 app.thread.scheduleConfigurationChanged(mConfiguration);
13066 }
13067 } catch (Exception e) {
13068 }
13069 }
13070 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013071 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13072 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013073 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13074 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013075 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13076 broadcastIntentLocked(null, null,
13077 new Intent(Intent.ACTION_LOCALE_CHANGED),
13078 null, null, 0, null, null,
13079 null, false, false, MY_PID, Process.SYSTEM_UID);
13080 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013081 }
13082 }
13083
13084 if (changes != 0 && starting == null) {
13085 // If the configuration changed, and the caller is not already
13086 // in the process of starting an activity, then find the top
13087 // activity to check if its configuration needs to change.
13088 starting = topRunningActivityLocked(null);
13089 }
13090
13091 if (starting != null) {
13092 kept = ensureActivityConfigurationLocked(starting, changes);
13093 if (kept) {
13094 // If this didn't result in the starting activity being
13095 // destroyed, then we need to make sure at this point that all
13096 // other activities are made visible.
13097 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13098 + ", ensuring others are correct.");
13099 ensureActivitiesVisibleLocked(starting, changes);
13100 }
13101 }
13102
13103 return kept;
13104 }
13105
13106 private final boolean relaunchActivityLocked(HistoryRecord r,
13107 int changes, boolean andResume) {
13108 List<ResultInfo> results = null;
13109 List<Intent> newIntents = null;
13110 if (andResume) {
13111 results = r.results;
13112 newIntents = r.newIntents;
13113 }
13114 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13115 + " with results=" + results + " newIntents=" + newIntents
13116 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013117 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13118 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013119 r.task.taskId, r.shortComponentName);
13120
13121 r.startFreezingScreenLocked(r.app, 0);
13122
13123 try {
13124 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13125 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013126 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013127 // Note: don't need to call pauseIfSleepingLocked() here, because
13128 // the caller will only pass in 'andResume' if this activity is
13129 // currently resumed, which implies we aren't sleeping.
13130 } catch (RemoteException e) {
13131 return false;
13132 }
13133
13134 if (andResume) {
13135 r.results = null;
13136 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013137 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013138 }
13139
13140 return true;
13141 }
13142
13143 /**
13144 * Make sure the given activity matches the current configuration. Returns
13145 * false if the activity had to be destroyed. Returns true if the
13146 * configuration is the same, or the activity will remain running as-is
13147 * for whatever reason. Ensures the HistoryRecord is updated with the
13148 * correct configuration and all other bookkeeping is handled.
13149 */
13150 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13151 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013152 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13153 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013154
13155 // Short circuit: if the two configurations are the exact same
13156 // object (the common case), then there is nothing to do.
13157 Configuration newConfig = mConfiguration;
13158 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013159 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13160 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013161 return true;
13162 }
13163
13164 // We don't worry about activities that are finishing.
13165 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013166 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013167 "Configuration doesn't matter in finishing " + r);
13168 r.stopFreezingScreenLocked(false);
13169 return true;
13170 }
13171
13172 // Okay we now are going to make this activity have the new config.
13173 // But then we need to figure out how it needs to deal with that.
13174 Configuration oldConfig = r.configuration;
13175 r.configuration = newConfig;
13176
13177 // If the activity isn't currently running, just leave the new
13178 // configuration and it will pick that up next time it starts.
13179 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013180 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013181 "Configuration doesn't matter not running " + r);
13182 r.stopFreezingScreenLocked(false);
13183 return true;
13184 }
13185
13186 // If the activity isn't persistent, there is a chance we will
13187 // need to restart it.
13188 if (!r.persistent) {
13189
13190 // Figure out what has changed between the two configurations.
13191 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013192 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13193 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013194 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013195 + Integer.toHexString(r.info.configChanges)
13196 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013197 }
13198 if ((changes&(~r.info.configChanges)) != 0) {
13199 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13200 r.configChangeFlags |= changes;
13201 r.startFreezingScreenLocked(r.app, globalChanges);
13202 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013203 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13204 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013205 destroyActivityLocked(r, true);
13206 } else if (r.state == ActivityState.PAUSING) {
13207 // A little annoying: we are waiting for this activity to
13208 // finish pausing. Let's not do anything now, but just
13209 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013210 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13211 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013212 r.configDestroy = true;
13213 return true;
13214 } else if (r.state == ActivityState.RESUMED) {
13215 // Try to optimize this case: the configuration is changing
13216 // and we need to restart the top, resumed activity.
13217 // Instead of doing the normal handshaking, just say
13218 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013219 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13220 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013221 relaunchActivityLocked(r, r.configChangeFlags, true);
13222 r.configChangeFlags = 0;
13223 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013224 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13225 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013226 relaunchActivityLocked(r, r.configChangeFlags, false);
13227 r.configChangeFlags = 0;
13228 }
13229
13230 // All done... tell the caller we weren't able to keep this
13231 // activity around.
13232 return false;
13233 }
13234 }
13235
13236 // Default case: the activity can handle this new configuration, so
13237 // hand it over. Note that we don't need to give it the new
13238 // configuration, since we always send configuration changes to all
13239 // process when they happen so it can just use whatever configuration
13240 // it last got.
13241 if (r.app != null && r.app.thread != null) {
13242 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013243 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013244 r.app.thread.scheduleActivityConfigurationChanged(r);
13245 } catch (RemoteException e) {
13246 // If process died, whatever.
13247 }
13248 }
13249 r.stopFreezingScreenLocked(false);
13250
13251 return true;
13252 }
13253
13254 /**
13255 * Save the locale. You must be inside a synchronized (this) block.
13256 */
13257 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13258 if(isDiff) {
13259 SystemProperties.set("user.language", l.getLanguage());
13260 SystemProperties.set("user.region", l.getCountry());
13261 }
13262
13263 if(isPersist) {
13264 SystemProperties.set("persist.sys.language", l.getLanguage());
13265 SystemProperties.set("persist.sys.country", l.getCountry());
13266 SystemProperties.set("persist.sys.localevar", l.getVariant());
13267 }
13268 }
13269
13270 // =========================================================
13271 // LIFETIME MANAGEMENT
13272 // =========================================================
13273
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013274 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13275 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013276 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013277 // This adjustment has already been computed. If we are calling
13278 // from the top, we may have already computed our adjustment with
13279 // an earlier hidden adjustment that isn't really for us... if
13280 // so, use the new hidden adjustment.
13281 if (!recursed && app.hidden) {
13282 app.curAdj = hiddenAdj;
13283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013284 return app.curAdj;
13285 }
13286
13287 if (app.thread == null) {
13288 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013289 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013290 return (app.curAdj=EMPTY_APP_ADJ);
13291 }
13292
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013293 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13294 // The max adjustment doesn't allow this app to be anything
13295 // below foreground, so it is not worth doing work for it.
13296 app.adjType = "fixed";
13297 app.adjSeq = mAdjSeq;
13298 app.curRawAdj = app.maxAdj;
13299 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13300 return (app.curAdj=app.maxAdj);
13301 }
13302
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013303 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013304 app.adjSource = null;
13305 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013306 app.empty = false;
13307 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013308
The Android Open Source Project4df24232009-03-05 14:34:35 -080013309 // Determine the importance of the process, starting with most
13310 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013311 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013312 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013313 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013314 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013315 // The last app on the list is the foreground app.
13316 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013317 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013318 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013319 } else if (app.instrumentationClass != null) {
13320 // Don't want to kill running instrumentation.
13321 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013322 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013323 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013324 } else if (app.persistentActivities > 0) {
13325 // Special persistent activities... shouldn't be used these days.
13326 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013327 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013328 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013329 } else if (app.curReceiver != null ||
13330 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13331 // An app that is currently receiving a broadcast also
13332 // counts as being in the foreground.
13333 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013334 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013335 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013336 } else if (app.executingServices.size() > 0) {
13337 // An app that is currently executing a service callback also
13338 // counts as being in the foreground.
13339 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013340 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013341 app.adjType = "exec-service";
13342 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013343 // The user is aware of this app, so make it visible.
13344 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013345 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013346 app.adjType = "foreground-service";
13347 } else if (app.forcingToForeground != null) {
13348 // The user is aware of this app, so make it visible.
13349 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013350 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013351 app.adjType = "force-foreground";
13352 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013353 } else if (app == mHomeProcess) {
13354 // This process is hosting what we currently consider to be the
13355 // home app, so we don't want to let it go into the background.
13356 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013357 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013358 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013359 } else if ((N=app.activities.size()) != 0) {
13360 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013361 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013362 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013363 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013364 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013365 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013366 for (int j=0; j<N; j++) {
13367 if (((HistoryRecord)app.activities.get(j)).visible) {
13368 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013369 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013370 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013371 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013372 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013373 break;
13374 }
13375 }
13376 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013377 // A very not-needed process. If this is lower in the lru list,
13378 // we will push it in to the empty bucket.
13379 app.hidden = true;
13380 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013381 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013382 adj = hiddenAdj;
13383 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013384 }
13385
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013386 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13387
The Android Open Source Project4df24232009-03-05 14:34:35 -080013388 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013389 // there are applications dependent on our services or providers, but
13390 // this gives us a baseline and makes sure we don't get into an
13391 // infinite recursion.
13392 app.adjSeq = mAdjSeq;
13393 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013394
Christopher Tate6fa95972009-06-05 18:43:55 -070013395 if (mBackupTarget != null && app == mBackupTarget.app) {
13396 // If possible we want to avoid killing apps while they're being backed up
13397 if (adj > BACKUP_APP_ADJ) {
13398 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13399 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013400 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013401 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013402 }
13403 }
13404
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013405 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13406 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013407 final long now = SystemClock.uptimeMillis();
13408 // This process is more important if the top activity is
13409 // bound to the service.
13410 Iterator jt = app.services.iterator();
13411 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13412 ServiceRecord s = (ServiceRecord)jt.next();
13413 if (s.startRequested) {
13414 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13415 // This service has seen some activity within
13416 // recent memory, so we will keep its process ahead
13417 // of the background processes.
13418 if (adj > SECONDARY_SERVER_ADJ) {
13419 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013420 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013421 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013422 }
13423 }
13424 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013425 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13426 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013427 Iterator<ConnectionRecord> kt
13428 = s.connections.values().iterator();
13429 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13430 // XXX should compute this based on the max of
13431 // all connected clients.
13432 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013433 if (cr.binding.client == app) {
13434 // Binding to ourself is not interesting.
13435 continue;
13436 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013437 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13438 ProcessRecord client = cr.binding.client;
13439 int myHiddenAdj = hiddenAdj;
13440 if (myHiddenAdj > client.hiddenAdj) {
13441 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13442 myHiddenAdj = client.hiddenAdj;
13443 } else {
13444 myHiddenAdj = VISIBLE_APP_ADJ;
13445 }
13446 }
13447 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013448 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013449 if (adj > clientAdj) {
13450 adj = clientAdj > VISIBLE_APP_ADJ
13451 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013452 if (!client.hidden) {
13453 app.hidden = false;
13454 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013455 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013456 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13457 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013458 app.adjSource = cr.binding.client;
13459 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013460 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013461 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13462 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13463 schedGroup = Process.THREAD_GROUP_DEFAULT;
13464 }
13465 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013466 }
13467 HistoryRecord a = cr.activity;
13468 //if (a != null) {
13469 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13470 //}
13471 if (a != null && adj > FOREGROUND_APP_ADJ &&
13472 (a.state == ActivityState.RESUMED
13473 || a.state == ActivityState.PAUSING)) {
13474 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013475 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013476 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013477 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013478 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13479 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013480 app.adjSource = a;
13481 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013482 }
13483 }
13484 }
13485 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013486
13487 // Finally, f this process has active services running in it, we
13488 // would like to avoid killing it unless it would prevent the current
13489 // application from running. By default we put the process in
13490 // with the rest of the background processes; as we scan through
13491 // its services we may bump it up from there.
13492 if (adj > hiddenAdj) {
13493 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013494 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013495 app.adjType = "bg-services";
13496 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013497 }
13498
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013499 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13500 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013501 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013502 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13503 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013504 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13505 if (cpr.clients.size() != 0) {
13506 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13507 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13508 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013509 if (client == app) {
13510 // Being our own client is not interesting.
13511 continue;
13512 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013513 int myHiddenAdj = hiddenAdj;
13514 if (myHiddenAdj > client.hiddenAdj) {
13515 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13516 myHiddenAdj = client.hiddenAdj;
13517 } else {
13518 myHiddenAdj = FOREGROUND_APP_ADJ;
13519 }
13520 }
13521 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013522 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013523 if (adj > clientAdj) {
13524 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013525 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013526 if (!client.hidden) {
13527 app.hidden = false;
13528 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013529 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013530 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13531 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013532 app.adjSource = client;
13533 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013534 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013535 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13536 schedGroup = Process.THREAD_GROUP_DEFAULT;
13537 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013538 }
13539 }
13540 // If the provider has external (non-framework) process
13541 // dependencies, ensure that its adjustment is at least
13542 // FOREGROUND_APP_ADJ.
13543 if (cpr.externals != 0) {
13544 if (adj > FOREGROUND_APP_ADJ) {
13545 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013546 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013547 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013548 app.adjType = "provider";
13549 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013550 }
13551 }
13552 }
13553 }
13554
13555 app.curRawAdj = adj;
13556
13557 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13558 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13559 if (adj > app.maxAdj) {
13560 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013561 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13562 schedGroup = Process.THREAD_GROUP_DEFAULT;
13563 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013564 }
13565
13566 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013567 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013569 return adj;
13570 }
13571
13572 /**
13573 * Ask a given process to GC right now.
13574 */
13575 final void performAppGcLocked(ProcessRecord app) {
13576 try {
13577 app.lastRequestedGc = SystemClock.uptimeMillis();
13578 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013579 if (app.reportLowMemory) {
13580 app.reportLowMemory = false;
13581 app.thread.scheduleLowMemory();
13582 } else {
13583 app.thread.processInBackground();
13584 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013585 }
13586 } catch (Exception e) {
13587 // whatever.
13588 }
13589 }
13590
13591 /**
13592 * Returns true if things are idle enough to perform GCs.
13593 */
13594 private final boolean canGcNow() {
13595 return mParallelBroadcasts.size() == 0
13596 && mOrderedBroadcasts.size() == 0
13597 && (mSleeping || (mResumedActivity != null &&
13598 mResumedActivity.idle));
13599 }
13600
13601 /**
13602 * Perform GCs on all processes that are waiting for it, but only
13603 * if things are idle.
13604 */
13605 final void performAppGcsLocked() {
13606 final int N = mProcessesToGc.size();
13607 if (N <= 0) {
13608 return;
13609 }
13610 if (canGcNow()) {
13611 while (mProcessesToGc.size() > 0) {
13612 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013613 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13614 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13615 <= SystemClock.uptimeMillis()) {
13616 // To avoid spamming the system, we will GC processes one
13617 // at a time, waiting a few seconds between each.
13618 performAppGcLocked(proc);
13619 scheduleAppGcsLocked();
13620 return;
13621 } else {
13622 // It hasn't been long enough since we last GCed this
13623 // process... put it in the list to wait for its time.
13624 addProcessToGcListLocked(proc);
13625 break;
13626 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013627 }
13628 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013629
13630 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013631 }
13632 }
13633
13634 /**
13635 * If all looks good, perform GCs on all processes waiting for them.
13636 */
13637 final void performAppGcsIfAppropriateLocked() {
13638 if (canGcNow()) {
13639 performAppGcsLocked();
13640 return;
13641 }
13642 // Still not idle, wait some more.
13643 scheduleAppGcsLocked();
13644 }
13645
13646 /**
13647 * Schedule the execution of all pending app GCs.
13648 */
13649 final void scheduleAppGcsLocked() {
13650 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013651
13652 if (mProcessesToGc.size() > 0) {
13653 // Schedule a GC for the time to the next process.
13654 ProcessRecord proc = mProcessesToGc.get(0);
13655 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13656
13657 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13658 long now = SystemClock.uptimeMillis();
13659 if (when < (now+GC_TIMEOUT)) {
13660 when = now + GC_TIMEOUT;
13661 }
13662 mHandler.sendMessageAtTime(msg, when);
13663 }
13664 }
13665
13666 /**
13667 * Add a process to the array of processes waiting to be GCed. Keeps the
13668 * list in sorted order by the last GC time. The process can't already be
13669 * on the list.
13670 */
13671 final void addProcessToGcListLocked(ProcessRecord proc) {
13672 boolean added = false;
13673 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13674 if (mProcessesToGc.get(i).lastRequestedGc <
13675 proc.lastRequestedGc) {
13676 added = true;
13677 mProcessesToGc.add(i+1, proc);
13678 break;
13679 }
13680 }
13681 if (!added) {
13682 mProcessesToGc.add(0, proc);
13683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013684 }
13685
13686 /**
13687 * Set up to ask a process to GC itself. This will either do it
13688 * immediately, or put it on the list of processes to gc the next
13689 * time things are idle.
13690 */
13691 final void scheduleAppGcLocked(ProcessRecord app) {
13692 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013693 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013694 return;
13695 }
13696 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013697 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013698 scheduleAppGcsLocked();
13699 }
13700 }
13701
13702 private final boolean updateOomAdjLocked(
13703 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13704 app.hiddenAdj = hiddenAdj;
13705
13706 if (app.thread == null) {
13707 return true;
13708 }
13709
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013710 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013711
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013712 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013713 if (app.curRawAdj != app.setRawAdj) {
13714 if (app.curRawAdj > FOREGROUND_APP_ADJ
13715 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13716 // If this app is transitioning from foreground to
13717 // non-foreground, have it do a gc.
13718 scheduleAppGcLocked(app);
13719 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13720 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13721 // Likewise do a gc when an app is moving in to the
13722 // background (such as a service stopping).
13723 scheduleAppGcLocked(app);
13724 }
13725 app.setRawAdj = app.curRawAdj;
13726 }
13727 if (adj != app.setAdj) {
13728 if (Process.setOomAdj(app.pid, adj)) {
13729 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13730 TAG, "Set app " + app.processName +
13731 " oom adj to " + adj);
13732 app.setAdj = adj;
13733 } else {
13734 return false;
13735 }
13736 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013737 if (app.setSchedGroup != app.curSchedGroup) {
13738 app.setSchedGroup = app.curSchedGroup;
13739 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13740 "Setting process group of " + app.processName
13741 + " to " + app.curSchedGroup);
13742 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013743 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013744 try {
13745 Process.setProcessGroup(app.pid, app.curSchedGroup);
13746 } catch (Exception e) {
13747 Log.w(TAG, "Failed setting process group of " + app.pid
13748 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013749 e.printStackTrace();
13750 } finally {
13751 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013752 }
13753 }
13754 if (false) {
13755 if (app.thread != null) {
13756 try {
13757 app.thread.setSchedulingGroup(app.curSchedGroup);
13758 } catch (RemoteException e) {
13759 }
13760 }
13761 }
13762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013763 }
13764
13765 return true;
13766 }
13767
13768 private final HistoryRecord resumedAppLocked() {
13769 HistoryRecord resumedActivity = mResumedActivity;
13770 if (resumedActivity == null || resumedActivity.app == null) {
13771 resumedActivity = mPausingActivity;
13772 if (resumedActivity == null || resumedActivity.app == null) {
13773 resumedActivity = topRunningActivityLocked(null);
13774 }
13775 }
13776 return resumedActivity;
13777 }
13778
13779 private final boolean updateOomAdjLocked(ProcessRecord app) {
13780 final HistoryRecord TOP_ACT = resumedAppLocked();
13781 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13782 int curAdj = app.curAdj;
13783 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13784 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13785
13786 mAdjSeq++;
13787
13788 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13789 if (res) {
13790 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13791 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13792 if (nowHidden != wasHidden) {
13793 // Changed to/from hidden state, so apps after it in the LRU
13794 // list may also be changed.
13795 updateOomAdjLocked();
13796 }
13797 }
13798 return res;
13799 }
13800
13801 private final boolean updateOomAdjLocked() {
13802 boolean didOomAdj = true;
13803 final HistoryRecord TOP_ACT = resumedAppLocked();
13804 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13805
13806 if (false) {
13807 RuntimeException e = new RuntimeException();
13808 e.fillInStackTrace();
13809 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13810 }
13811
13812 mAdjSeq++;
13813
13814 // First try updating the OOM adjustment for each of the
13815 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013816 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013817 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13818 while (i > 0) {
13819 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013820 ProcessRecord app = mLruProcesses.get(i);
13821 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013822 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013823 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013824 && app.curAdj == curHiddenAdj) {
13825 curHiddenAdj++;
13826 }
13827 } else {
13828 didOomAdj = false;
13829 }
13830 }
13831
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013832 // If we return false, we will fall back on killing processes to
13833 // have a fixed limit. Do this if a limit has been requested; else
13834 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013835 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13836 }
13837
13838 private final void trimApplications() {
13839 synchronized (this) {
13840 int i;
13841
13842 // First remove any unused application processes whose package
13843 // has been removed.
13844 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13845 final ProcessRecord app = mRemovedProcesses.get(i);
13846 if (app.activities.size() == 0
13847 && app.curReceiver == null && app.services.size() == 0) {
13848 Log.i(
13849 TAG, "Exiting empty application process "
13850 + app.processName + " ("
13851 + (app.thread != null ? app.thread.asBinder() : null)
13852 + ")\n");
13853 if (app.pid > 0 && app.pid != MY_PID) {
13854 Process.killProcess(app.pid);
13855 } else {
13856 try {
13857 app.thread.scheduleExit();
13858 } catch (Exception e) {
13859 // Ignore exceptions.
13860 }
13861 }
13862 cleanUpApplicationRecordLocked(app, false, -1);
13863 mRemovedProcesses.remove(i);
13864
13865 if (app.persistent) {
13866 if (app.persistent) {
13867 addAppLocked(app.info);
13868 }
13869 }
13870 }
13871 }
13872
13873 // Now try updating the OOM adjustment for each of the
13874 // application processes based on their current state.
13875 // If the setOomAdj() API is not supported, then go with our
13876 // back-up plan...
13877 if (!updateOomAdjLocked()) {
13878
13879 // Count how many processes are running services.
13880 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013881 for (i=mLruProcesses.size()-1; i>=0; i--) {
13882 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013883
13884 if (app.persistent || app.services.size() != 0
13885 || app.curReceiver != null
13886 || app.persistentActivities > 0) {
13887 // Don't count processes holding services against our
13888 // maximum process count.
13889 if (localLOGV) Log.v(
13890 TAG, "Not trimming app " + app + " with services: "
13891 + app.services);
13892 numServiceProcs++;
13893 }
13894 }
13895
13896 int curMaxProcs = mProcessLimit;
13897 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13898 if (mAlwaysFinishActivities) {
13899 curMaxProcs = 1;
13900 }
13901 curMaxProcs += numServiceProcs;
13902
13903 // Quit as many processes as we can to get down to the desired
13904 // process count. First remove any processes that no longer
13905 // have activites running in them.
13906 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013907 i<mLruProcesses.size()
13908 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013909 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013910 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013911 // Quit an application only if it is not currently
13912 // running any activities.
13913 if (!app.persistent && app.activities.size() == 0
13914 && app.curReceiver == null && app.services.size() == 0) {
13915 Log.i(
13916 TAG, "Exiting empty application process "
13917 + app.processName + " ("
13918 + (app.thread != null ? app.thread.asBinder() : null)
13919 + ")\n");
13920 if (app.pid > 0 && app.pid != MY_PID) {
13921 Process.killProcess(app.pid);
13922 } else {
13923 try {
13924 app.thread.scheduleExit();
13925 } catch (Exception e) {
13926 // Ignore exceptions.
13927 }
13928 }
13929 // todo: For now we assume the application is not buggy
13930 // or evil, and will quit as a result of our request.
13931 // Eventually we need to drive this off of the death
13932 // notification, and kill the process if it takes too long.
13933 cleanUpApplicationRecordLocked(app, false, i);
13934 i--;
13935 }
13936 }
13937
13938 // If we still have too many processes, now from the least
13939 // recently used process we start finishing activities.
13940 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013941 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013942 " of " + curMaxProcs + " processes");
13943 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013944 i<mLruProcesses.size()
13945 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013946 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013947 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013948 // Quit the application only if we have a state saved for
13949 // all of its activities.
13950 boolean canQuit = !app.persistent && app.curReceiver == null
13951 && app.services.size() == 0
13952 && app.persistentActivities == 0;
13953 int NUMA = app.activities.size();
13954 int j;
13955 if (Config.LOGV) Log.v(
13956 TAG, "Looking to quit " + app.processName);
13957 for (j=0; j<NUMA && canQuit; j++) {
13958 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13959 if (Config.LOGV) Log.v(
13960 TAG, " " + r.intent.getComponent().flattenToShortString()
13961 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13962 canQuit = (r.haveState || !r.stateNotNeeded)
13963 && !r.visible && r.stopped;
13964 }
13965 if (canQuit) {
13966 // Finish all of the activities, and then the app itself.
13967 for (j=0; j<NUMA; j++) {
13968 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13969 if (!r.finishing) {
13970 destroyActivityLocked(r, false);
13971 }
13972 r.resultTo = null;
13973 }
13974 Log.i(TAG, "Exiting application process "
13975 + app.processName + " ("
13976 + (app.thread != null ? app.thread.asBinder() : null)
13977 + ")\n");
13978 if (app.pid > 0 && app.pid != MY_PID) {
13979 Process.killProcess(app.pid);
13980 } else {
13981 try {
13982 app.thread.scheduleExit();
13983 } catch (Exception e) {
13984 // Ignore exceptions.
13985 }
13986 }
13987 // todo: For now we assume the application is not buggy
13988 // or evil, and will quit as a result of our request.
13989 // Eventually we need to drive this off of the death
13990 // notification, and kill the process if it takes too long.
13991 cleanUpApplicationRecordLocked(app, false, i);
13992 i--;
13993 //dump();
13994 }
13995 }
13996
13997 }
13998
13999 int curMaxActivities = MAX_ACTIVITIES;
14000 if (mAlwaysFinishActivities) {
14001 curMaxActivities = 1;
14002 }
14003
14004 // Finally, if there are too many activities now running, try to
14005 // finish as many as we can to get back down to the limit.
14006 for ( i=0;
14007 i<mLRUActivities.size()
14008 && mLRUActivities.size() > curMaxActivities;
14009 i++) {
14010 final HistoryRecord r
14011 = (HistoryRecord)mLRUActivities.get(i);
14012
14013 // We can finish this one if we have its icicle saved and
14014 // it is not persistent.
14015 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14016 && r.stopped && !r.persistent && !r.finishing) {
14017 final int origSize = mLRUActivities.size();
14018 destroyActivityLocked(r, true);
14019
14020 // This will remove it from the LRU list, so keep
14021 // our index at the same value. Note that this check to
14022 // see if the size changes is just paranoia -- if
14023 // something unexpected happens, we don't want to end up
14024 // in an infinite loop.
14025 if (origSize > mLRUActivities.size()) {
14026 i--;
14027 }
14028 }
14029 }
14030 }
14031 }
14032
14033 /** This method sends the specified signal to each of the persistent apps */
14034 public void signalPersistentProcesses(int sig) throws RemoteException {
14035 if (sig != Process.SIGNAL_USR1) {
14036 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14037 }
14038
14039 synchronized (this) {
14040 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14041 != PackageManager.PERMISSION_GRANTED) {
14042 throw new SecurityException("Requires permission "
14043 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14044 }
14045
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014046 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14047 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014048 if (r.thread != null && r.persistent) {
14049 Process.sendSignal(r.pid, sig);
14050 }
14051 }
14052 }
14053 }
14054
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014055 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014056 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014057
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014058 try {
14059 synchronized (this) {
14060 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14061 // its own permission.
14062 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14063 != PackageManager.PERMISSION_GRANTED) {
14064 throw new SecurityException("Requires permission "
14065 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014066 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014067
14068 if (start && fd == null) {
14069 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014070 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014071
14072 ProcessRecord proc = null;
14073 try {
14074 int pid = Integer.parseInt(process);
14075 synchronized (mPidsSelfLocked) {
14076 proc = mPidsSelfLocked.get(pid);
14077 }
14078 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014079 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014080
14081 if (proc == null) {
14082 HashMap<String, SparseArray<ProcessRecord>> all
14083 = mProcessNames.getMap();
14084 SparseArray<ProcessRecord> procs = all.get(process);
14085 if (procs != null && procs.size() > 0) {
14086 proc = procs.valueAt(0);
14087 }
14088 }
14089
14090 if (proc == null || proc.thread == null) {
14091 throw new IllegalArgumentException("Unknown process: " + process);
14092 }
14093
14094 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14095 if (isSecure) {
14096 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14097 throw new SecurityException("Process not debuggable: " + proc);
14098 }
14099 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014100
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014101 proc.thread.profilerControl(start, path, fd);
14102 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014103 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014104 }
14105 } catch (RemoteException e) {
14106 throw new IllegalStateException("Process disappeared");
14107 } finally {
14108 if (fd != null) {
14109 try {
14110 fd.close();
14111 } catch (IOException e) {
14112 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014113 }
14114 }
14115 }
14116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014117 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14118 public void monitor() {
14119 synchronized (this) { }
14120 }
14121}