blob: 3612a9b361d8af4d16fa3cf47b48dcc9ee6811e6 [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
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070055import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.server.data.CrashData;
92import android.server.data.StackTraceElementData;
93import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.text.TextUtils;
95import android.util.Config;
96import android.util.EventLog;
97import android.util.Log;
98import android.util.PrintWriterPrinter;
99import android.util.SparseArray;
100import android.view.Gravity;
101import android.view.LayoutInflater;
102import android.view.View;
103import android.view.WindowManager;
104import android.view.WindowManagerPolicy;
105
106import dalvik.system.Zygote;
107
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.ByteArrayInputStream;
109import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200114import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.PrintWriter;
116import java.lang.IllegalStateException;
117import java.lang.ref.WeakReference;
118import java.util.ArrayList;
119import java.util.HashMap;
120import java.util.HashSet;
121import java.util.Iterator;
122import java.util.List;
123import java.util.Locale;
124import java.util.Map;
125
126public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
127 static final String TAG = "ActivityManager";
128 static final boolean DEBUG = false;
129 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
130 static final boolean DEBUG_SWITCH = localLOGV || false;
131 static final boolean DEBUG_TASKS = localLOGV || false;
132 static final boolean DEBUG_PAUSE = localLOGV || false;
133 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
134 static final boolean DEBUG_TRANSITION = localLOGV || false;
135 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700136 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean DEBUG_SERVICE = localLOGV || false;
138 static final boolean DEBUG_VISBILITY = localLOGV || false;
139 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700140 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700142 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700143 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700144 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 static final boolean VALIDATE_TOKENS = false;
146 static final boolean SHOW_ACTIVITY_START_TIME = true;
147
148 // Control over CPU and battery monitoring.
149 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
150 static final boolean MONITOR_CPU_USAGE = true;
151 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
152 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
153 static final boolean MONITOR_THREAD_CPU_USAGE = false;
154
155 // Event log tags
156 static final int LOG_CONFIGURATION_CHANGED = 2719;
157 static final int LOG_CPU = 2721;
158 static final int LOG_AM_FINISH_ACTIVITY = 30001;
159 static final int LOG_TASK_TO_FRONT = 30002;
160 static final int LOG_AM_NEW_INTENT = 30003;
161 static final int LOG_AM_CREATE_TASK = 30004;
162 static final int LOG_AM_CREATE_ACTIVITY = 30005;
163 static final int LOG_AM_RESTART_ACTIVITY = 30006;
164 static final int LOG_AM_RESUME_ACTIVITY = 30007;
165 static final int LOG_ANR = 30008;
166 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
167 static final int LOG_AM_PROCESS_BOUND = 30010;
168 static final int LOG_AM_PROCESS_DIED = 30011;
169 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
170 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
171 static final int LOG_AM_PROCESS_START = 30014;
172 static final int LOG_AM_PROCESS_BAD = 30015;
173 static final int LOG_AM_PROCESS_GOOD = 30016;
174 static final int LOG_AM_LOW_MEMORY = 30017;
175 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
176 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
177 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
178 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
179 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
180 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
181 static final int LOG_AM_CREATE_SERVICE = 30030;
182 static final int LOG_AM_DESTROY_SERVICE = 30031;
183 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
184 static final int LOG_AM_DROP_PROCESS = 30033;
185 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
186 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
187 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
Dianne Hackbornf670ef72009-11-16 13:59:16 -0800188 static final int LOG_AM_PROCESS_START_TIMEOUT = 30037;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
190 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
191 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
192
Dianne Hackborn1655be42009-05-08 14:29:01 -0700193 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700194 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 private static final String SYSTEM_SECURE = "ro.secure";
197
198 // This is the maximum number of application processes we would like
199 // to have running. Due to the asynchronous nature of things, we can
200 // temporarily go beyond this limit.
201 static final int MAX_PROCESSES = 2;
202
203 // Set to false to leave processes running indefinitely, relying on
204 // the kernel killing them as resources are required.
205 static final boolean ENFORCE_PROCESS_LIMIT = false;
206
207 // This is the maximum number of activities that we would like to have
208 // running at a given time.
209 static final int MAX_ACTIVITIES = 20;
210
211 // Maximum number of recent tasks that we can remember.
212 static final int MAX_RECENT_TASKS = 20;
213
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700214 // Amount of time after a call to stopAppSwitches() during which we will
215 // prevent further untrusted switches from happening.
216 static final long APP_SWITCH_DELAY_TIME = 5*1000;
217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 // How long until we reset a task when the user returns to it. Currently
219 // 30 minutes.
220 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
221
222 // Set to true to disable the icon that is shown while a new activity
223 // is being started.
224 static final boolean SHOW_APP_STARTING_ICON = true;
225
226 // How long we wait until giving up on the last activity to pause. This
227 // is short because it directly impacts the responsiveness of starting the
228 // next activity.
229 static final int PAUSE_TIMEOUT = 500;
230
231 /**
232 * How long we can hold the launch wake lock before giving up.
233 */
234 static final int LAUNCH_TIMEOUT = 10*1000;
235
236 // How long we wait for a launched process to attach to the activity manager
237 // before we decide it's never going to come up for real.
238 static final int PROC_START_TIMEOUT = 10*1000;
239
240 // How long we wait until giving up on the last activity telling us it
241 // is idle.
242 static final int IDLE_TIMEOUT = 10*1000;
243
244 // How long to wait after going idle before forcing apps to GC.
245 static final int GC_TIMEOUT = 5*1000;
246
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700247 // The minimum amount of time between successive GC requests for a process.
248 static final int GC_MIN_INTERVAL = 60*1000;
249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 // How long we wait until giving up on an activity telling us it has
251 // finished destroying itself.
252 static final int DESTROY_TIMEOUT = 10*1000;
253
254 // How long we allow a receiver to run before giving up on it.
255 static final int BROADCAST_TIMEOUT = 10*1000;
256
257 // How long we wait for a service to finish executing.
258 static final int SERVICE_TIMEOUT = 20*1000;
259
260 // How long a service needs to be running until restarting its process
261 // is no longer considered to be a relaunch of the service.
262 static final int SERVICE_RESTART_DURATION = 5*1000;
263
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700264 // How long a service needs to be running until it will start back at
265 // SERVICE_RESTART_DURATION after being killed.
266 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
267
268 // Multiplying factor to increase restart duration time by, for each time
269 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
270 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
271
272 // The minimum amount of time between restarting services that we allow.
273 // That is, when multiple services are restarting, we won't allow each
274 // to restart less than this amount of time from the last one.
275 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 // Maximum amount of time for there to be no activity on a service before
278 // we consider it non-essential and allow its process to go on the
279 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700280 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281
282 // How long we wait until we timeout on key dispatching.
283 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
284
285 // The minimum time we allow between crashes, for us to consider this
286 // application to be bad and stop and its services and reject broadcasts.
287 static final int MIN_CRASH_INTERVAL = 60*1000;
288
289 // How long we wait until we timeout on key dispatching during instrumentation.
290 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
291
292 // OOM adjustments for processes in various states:
293
294 // This is a process without anything currently running in it. Definitely
295 // the first to go! Value set in system/rootdir/init.rc on startup.
296 // This value is initalized in the constructor, careful when refering to
297 // this static variable externally.
298 static int EMPTY_APP_ADJ;
299
300 // This is a process with a content provider that does not have any clients
301 // attached to it. If it did have any clients, its adjustment would be the
302 // one for the highest-priority of those processes.
303 static int CONTENT_PROVIDER_ADJ;
304
305 // This is a process only hosting activities that are not visible,
306 // so it can be killed without any disruption. Value set in
307 // system/rootdir/init.rc on startup.
308 final int HIDDEN_APP_MAX_ADJ;
309 static int HIDDEN_APP_MIN_ADJ;
310
The Android Open Source Project4df24232009-03-05 14:34:35 -0800311 // This is a process holding the home application -- we want to try
312 // avoiding killing it, even if it would normally be in the background,
313 // because the user interacts with it so much.
314 final int HOME_APP_ADJ;
315
Christopher Tate6fa95972009-06-05 18:43:55 -0700316 // This is a process currently hosting a backup operation. Killing it
317 // is not entirely fatal but is generally a bad idea.
318 final int BACKUP_APP_ADJ;
319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 // This is a process holding a secondary server -- killing it will not
321 // have much of an impact as far as the user is concerned. Value set in
322 // system/rootdir/init.rc on startup.
323 final int SECONDARY_SERVER_ADJ;
324
325 // This is a process only hosting activities that are visible to the
326 // user, so we'd prefer they don't disappear. Value set in
327 // system/rootdir/init.rc on startup.
328 final int VISIBLE_APP_ADJ;
329
330 // This is the process running the current foreground app. We'd really
331 // rather not kill it! Value set in system/rootdir/init.rc on startup.
332 final int FOREGROUND_APP_ADJ;
333
334 // This is a process running a core server, such as telephony. Definitely
335 // don't want to kill it, but doing so is not completely fatal.
336 static final int CORE_SERVER_ADJ = -12;
337
338 // The system process runs at the default adjustment.
339 static final int SYSTEM_ADJ = -16;
340
341 // Memory pages are 4K.
342 static final int PAGE_SIZE = 4*1024;
343
Jacek Surazski82a73df2009-06-17 14:33:18 +0200344 // System property defining error report receiver for system apps
345 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
346
347 // System property defining default error report receiver
348 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 // Corresponding memory levels for above adjustments.
351 final int EMPTY_APP_MEM;
352 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800353 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700354 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 final int SECONDARY_SERVER_MEM;
356 final int VISIBLE_APP_MEM;
357 final int FOREGROUND_APP_MEM;
358
359 final int MY_PID;
360
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 */
571 final ArrayList<ProcessRecord> mLRUProcesses
572 = 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;
985 byte[] crashData = (byte[])data.get("crashData");
986 if (crashData != null) {
987 // This needs to be *un*synchronized to avoid deadlock.
988 ContentResolver resolver = mContext.getContentResolver();
989 Checkin.reportCrash(resolver, crashData);
990 }
991 synchronized (ActivityManagerService.this) {
992 ProcessRecord proc = (ProcessRecord)data.get("app");
993 if (proc != null && proc.crashDialog != null) {
994 Log.e(TAG, "App already has crash dialog: " + proc);
995 return;
996 }
997 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700998 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 Dialog d = new AppErrorDialog(
1000 mContext, res, proc,
1001 (Integer)data.get("flags"),
1002 (String)data.get("shortMsg"),
1003 (String)data.get("longMsg"));
1004 d.show();
1005 proc.crashDialog = d;
1006 } else {
1007 // The device is asleep, so just pretend that the user
1008 // saw a crash dialog and hit "force quit".
1009 res.set(0);
1010 }
1011 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001012
1013 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 } break;
1015 case SHOW_NOT_RESPONDING_MSG: {
1016 synchronized (ActivityManagerService.this) {
1017 HashMap data = (HashMap) msg.obj;
1018 ProcessRecord proc = (ProcessRecord)data.get("app");
1019 if (proc != null && proc.anrDialog != null) {
1020 Log.e(TAG, "App already has anr dialog: " + proc);
1021 return;
1022 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001023
1024 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1025 null, null, 0, null, null, null,
1026 false, false, MY_PID, Process.SYSTEM_UID);
1027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1029 mContext, proc, (HistoryRecord)data.get("activity"));
1030 d.show();
1031 proc.anrDialog = d;
1032 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001033
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001034 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 } break;
1036 case SHOW_FACTORY_ERROR_MSG: {
1037 Dialog d = new FactoryErrorDialog(
1038 mContext, msg.getData().getCharSequence("msg"));
1039 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001040 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 } break;
1042 case UPDATE_CONFIGURATION_MSG: {
1043 final ContentResolver resolver = mContext.getContentResolver();
1044 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1045 } break;
1046 case GC_BACKGROUND_PROCESSES_MSG: {
1047 synchronized (ActivityManagerService.this) {
1048 performAppGcsIfAppropriateLocked();
1049 }
1050 } break;
1051 case WAIT_FOR_DEBUGGER_MSG: {
1052 synchronized (ActivityManagerService.this) {
1053 ProcessRecord app = (ProcessRecord)msg.obj;
1054 if (msg.arg1 != 0) {
1055 if (!app.waitedForDebugger) {
1056 Dialog d = new AppWaitingForDebuggerDialog(
1057 ActivityManagerService.this,
1058 mContext, app);
1059 app.waitDialog = d;
1060 app.waitedForDebugger = true;
1061 d.show();
1062 }
1063 } else {
1064 if (app.waitDialog != null) {
1065 app.waitDialog.dismiss();
1066 app.waitDialog = null;
1067 }
1068 }
1069 }
1070 } break;
1071 case BROADCAST_INTENT_MSG: {
1072 if (DEBUG_BROADCAST) Log.v(
1073 TAG, "Received BROADCAST_INTENT_MSG");
1074 processNextBroadcast(true);
1075 } break;
1076 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001077 if (mDidDexOpt) {
1078 mDidDexOpt = false;
1079 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1080 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1081 return;
1082 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 broadcastTimeout();
1084 } break;
1085 case PAUSE_TIMEOUT_MSG: {
1086 IBinder token = (IBinder)msg.obj;
1087 // We don't at this point know if the activity is fullscreen,
1088 // so we need to be conservative and assume it isn't.
1089 Log.w(TAG, "Activity pause timeout for " + token);
1090 activityPaused(token, null, true);
1091 } break;
1092 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001093 if (mDidDexOpt) {
1094 mDidDexOpt = false;
1095 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1096 nmsg.obj = msg.obj;
1097 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1098 return;
1099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 // We don't at this point know if the activity is fullscreen,
1101 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001102 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001104 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 } break;
1106 case DESTROY_TIMEOUT_MSG: {
1107 IBinder token = (IBinder)msg.obj;
1108 // We don't at this point know if the activity is fullscreen,
1109 // so we need to be conservative and assume it isn't.
1110 Log.w(TAG, "Activity destroy timeout for " + token);
1111 activityDestroyed(token);
1112 } break;
1113 case IDLE_NOW_MSG: {
1114 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001115 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 } break;
1117 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001118 if (mDidDexOpt) {
1119 mDidDexOpt = false;
1120 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1121 nmsg.obj = msg.obj;
1122 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1123 return;
1124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 serviceTimeout((ProcessRecord)msg.obj);
1126 } break;
1127 case UPDATE_TIME_ZONE: {
1128 synchronized (ActivityManagerService.this) {
1129 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1130 ProcessRecord r = mLRUProcesses.get(i);
1131 if (r.thread != null) {
1132 try {
1133 r.thread.updateTimeZone();
1134 } catch (RemoteException ex) {
1135 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1136 }
1137 }
1138 }
1139 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001140 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 case SHOW_UID_ERROR_MSG: {
1142 // XXX This is a temporary dialog, no need to localize.
1143 AlertDialog d = new BaseErrorDialog(mContext);
1144 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1145 d.setCancelable(false);
1146 d.setTitle("System UIDs Inconsistent");
1147 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1148 d.setButton("I'm Feeling Lucky",
1149 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1150 mUidAlert = d;
1151 d.show();
1152 } break;
1153 case IM_FEELING_LUCKY_MSG: {
1154 if (mUidAlert != null) {
1155 mUidAlert.dismiss();
1156 mUidAlert = null;
1157 }
1158 } break;
1159 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001160 if (mDidDexOpt) {
1161 mDidDexOpt = false;
1162 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1163 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1164 return;
1165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 synchronized (ActivityManagerService.this) {
1167 if (mLaunchingActivity.isHeld()) {
1168 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1169 mLaunchingActivity.release();
1170 }
1171 }
1172 } break;
1173 case SERVICE_ERROR_MSG: {
1174 ServiceRecord srv = (ServiceRecord)msg.obj;
1175 // This needs to be *un*synchronized to avoid deadlock.
1176 Checkin.logEvent(mContext.getContentResolver(),
1177 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1178 srv.name.toShortString());
1179 } break;
1180 case RESUME_TOP_ACTIVITY_MSG: {
1181 synchronized (ActivityManagerService.this) {
1182 resumeTopActivityLocked(null);
1183 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001184 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001186 if (mDidDexOpt) {
1187 mDidDexOpt = false;
1188 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1189 nmsg.obj = msg.obj;
1190 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1191 return;
1192 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 ProcessRecord app = (ProcessRecord)msg.obj;
1194 synchronized (ActivityManagerService.this) {
1195 processStartTimedOutLocked(app);
1196 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001197 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001198 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1199 synchronized (ActivityManagerService.this) {
1200 doPendingActivityLaunchesLocked(true);
1201 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001202 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001203 case KILL_APPLICATION_MSG: {
1204 synchronized (ActivityManagerService.this) {
1205 int uid = msg.arg1;
1206 boolean restart = (msg.arg2 == 1);
1207 String pkg = (String) msg.obj;
1208 uninstallPackageLocked(pkg, uid, restart);
1209 }
1210 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 }
1212 }
1213 };
1214
1215 public static void setSystemProcess() {
1216 try {
1217 ActivityManagerService m = mSelf;
1218
1219 ServiceManager.addService("activity", m);
1220 ServiceManager.addService("meminfo", new MemBinder(m));
1221 if (MONITOR_CPU_USAGE) {
1222 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1223 }
1224 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1225 ServiceManager.addService("activity.services", new ServicesBinder(m));
1226 ServiceManager.addService("activity.senders", new SendersBinder(m));
1227 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1228 ServiceManager.addService("permission", new PermissionController(m));
1229
1230 ApplicationInfo info =
1231 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001232 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001233 mSystemThread.installSystemApplicationInfo(info);
1234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 synchronized (mSelf) {
1236 ProcessRecord app = mSelf.newProcessRecordLocked(
1237 mSystemThread.getApplicationThread(), info,
1238 info.processName);
1239 app.persistent = true;
1240 app.pid = Process.myPid();
1241 app.maxAdj = SYSTEM_ADJ;
1242 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1243 synchronized (mSelf.mPidsSelfLocked) {
1244 mSelf.mPidsSelfLocked.put(app.pid, app);
1245 }
1246 mSelf.updateLRUListLocked(app, true);
1247 }
1248 } catch (PackageManager.NameNotFoundException e) {
1249 throw new RuntimeException(
1250 "Unable to find android system package", e);
1251 }
1252 }
1253
1254 public void setWindowManager(WindowManagerService wm) {
1255 mWindowManager = wm;
1256 }
1257
1258 public static final Context main(int factoryTest) {
1259 AThread thr = new AThread();
1260 thr.start();
1261
1262 synchronized (thr) {
1263 while (thr.mService == null) {
1264 try {
1265 thr.wait();
1266 } catch (InterruptedException e) {
1267 }
1268 }
1269 }
1270
1271 ActivityManagerService m = thr.mService;
1272 mSelf = m;
1273 ActivityThread at = ActivityThread.systemMain();
1274 mSystemThread = at;
1275 Context context = at.getSystemContext();
1276 m.mContext = context;
1277 m.mFactoryTest = factoryTest;
1278 PowerManager pm =
1279 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1280 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1281 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1282 m.mLaunchingActivity.setReferenceCounted(false);
1283
1284 m.mBatteryStatsService.publish(context);
1285 m.mUsageStatsService.publish(context);
1286
1287 synchronized (thr) {
1288 thr.mReady = true;
1289 thr.notifyAll();
1290 }
1291
1292 m.startRunning(null, null, null, null);
1293
1294 return context;
1295 }
1296
1297 public static ActivityManagerService self() {
1298 return mSelf;
1299 }
1300
1301 static class AThread extends Thread {
1302 ActivityManagerService mService;
1303 boolean mReady = false;
1304
1305 public AThread() {
1306 super("ActivityManager");
1307 }
1308
1309 public void run() {
1310 Looper.prepare();
1311
1312 android.os.Process.setThreadPriority(
1313 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1314
1315 ActivityManagerService m = new ActivityManagerService();
1316
1317 synchronized (this) {
1318 mService = m;
1319 notifyAll();
1320 }
1321
1322 synchronized (this) {
1323 while (!mReady) {
1324 try {
1325 wait();
1326 } catch (InterruptedException e) {
1327 }
1328 }
1329 }
1330
1331 Looper.loop();
1332 }
1333 }
1334
1335 static class BroadcastsBinder extends Binder {
1336 ActivityManagerService mActivityManagerService;
1337 BroadcastsBinder(ActivityManagerService activityManagerService) {
1338 mActivityManagerService = activityManagerService;
1339 }
1340
1341 @Override
1342 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1343 mActivityManagerService.dumpBroadcasts(pw);
1344 }
1345 }
1346
1347 static class ServicesBinder extends Binder {
1348 ActivityManagerService mActivityManagerService;
1349 ServicesBinder(ActivityManagerService activityManagerService) {
1350 mActivityManagerService = activityManagerService;
1351 }
1352
1353 @Override
1354 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1355 mActivityManagerService.dumpServices(pw);
1356 }
1357 }
1358
1359 static class SendersBinder extends Binder {
1360 ActivityManagerService mActivityManagerService;
1361 SendersBinder(ActivityManagerService activityManagerService) {
1362 mActivityManagerService = activityManagerService;
1363 }
1364
1365 @Override
1366 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1367 mActivityManagerService.dumpSenders(pw);
1368 }
1369 }
1370
1371 static class ProvidersBinder extends Binder {
1372 ActivityManagerService mActivityManagerService;
1373 ProvidersBinder(ActivityManagerService activityManagerService) {
1374 mActivityManagerService = activityManagerService;
1375 }
1376
1377 @Override
1378 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1379 mActivityManagerService.dumpProviders(pw);
1380 }
1381 }
1382
1383 static class MemBinder extends Binder {
1384 ActivityManagerService mActivityManagerService;
1385 MemBinder(ActivityManagerService activityManagerService) {
1386 mActivityManagerService = activityManagerService;
1387 }
1388
1389 @Override
1390 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1391 ActivityManagerService service = mActivityManagerService;
1392 ArrayList<ProcessRecord> procs;
1393 synchronized (mActivityManagerService) {
1394 if (args != null && args.length > 0
1395 && args[0].charAt(0) != '-') {
1396 procs = new ArrayList<ProcessRecord>();
1397 int pid = -1;
1398 try {
1399 pid = Integer.parseInt(args[0]);
1400 } catch (NumberFormatException e) {
1401
1402 }
1403 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1404 ProcessRecord proc = service.mLRUProcesses.get(i);
1405 if (proc.pid == pid) {
1406 procs.add(proc);
1407 } else if (proc.processName.equals(args[0])) {
1408 procs.add(proc);
1409 }
1410 }
1411 if (procs.size() <= 0) {
1412 pw.println("No process found for: " + args[0]);
1413 return;
1414 }
1415 } else {
1416 procs = service.mLRUProcesses;
1417 }
1418 }
1419 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1420 }
1421 }
1422
1423 static class CpuBinder extends Binder {
1424 ActivityManagerService mActivityManagerService;
1425 CpuBinder(ActivityManagerService activityManagerService) {
1426 mActivityManagerService = activityManagerService;
1427 }
1428
1429 @Override
1430 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1431 synchronized (mActivityManagerService.mProcessStatsThread) {
1432 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1433 }
1434 }
1435 }
1436
1437 private ActivityManagerService() {
1438 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1439 if (v != null && Integer.getInteger(v) != 0) {
1440 mSimpleProcessManagement = true;
1441 }
1442 v = System.getenv("ANDROID_DEBUG_APP");
1443 if (v != null) {
1444 mSimpleProcessManagement = true;
1445 }
1446
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001447 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 MY_PID = Process.myPid();
1450
1451 File dataDir = Environment.getDataDirectory();
1452 File systemDir = new File(dataDir, "system");
1453 systemDir.mkdirs();
1454 mBatteryStatsService = new BatteryStatsService(new File(
1455 systemDir, "batterystats.bin").toString());
1456 mBatteryStatsService.getActiveStatistics().readLocked();
1457 mBatteryStatsService.getActiveStatistics().writeLocked();
1458
1459 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001460 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461
Jack Palevichb90d28c2009-07-22 15:35:24 -07001462 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1463 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 mConfiguration.makeDefault();
1466 mProcessStats.init();
1467
1468 // Add ourself to the Watchdog monitors.
1469 Watchdog.getInstance().addMonitor(this);
1470
1471 // These values are set in system/rootdir/init.rc on startup.
1472 FOREGROUND_APP_ADJ =
1473 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1474 VISIBLE_APP_ADJ =
1475 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1476 SECONDARY_SERVER_ADJ =
1477 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001478 BACKUP_APP_ADJ =
1479 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001480 HOME_APP_ADJ =
1481 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 HIDDEN_APP_MIN_ADJ =
1483 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1484 CONTENT_PROVIDER_ADJ =
1485 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1486 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1487 EMPTY_APP_ADJ =
1488 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1489 FOREGROUND_APP_MEM =
1490 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1491 VISIBLE_APP_MEM =
1492 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1493 SECONDARY_SERVER_MEM =
1494 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001495 BACKUP_APP_MEM =
1496 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001497 HOME_APP_MEM =
1498 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 HIDDEN_APP_MEM =
1500 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1501 EMPTY_APP_MEM =
1502 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1503
1504 mProcessStatsThread = new Thread("ProcessStats") {
1505 public void run() {
1506 while (true) {
1507 try {
1508 try {
1509 synchronized(this) {
1510 final long now = SystemClock.uptimeMillis();
1511 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1512 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1513 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1514 // + ", write delay=" + nextWriteDelay);
1515 if (nextWriteDelay < nextCpuDelay) {
1516 nextCpuDelay = nextWriteDelay;
1517 }
1518 if (nextCpuDelay > 0) {
1519 this.wait(nextCpuDelay);
1520 }
1521 }
1522 } catch (InterruptedException e) {
1523 }
1524
1525 updateCpuStatsNow();
1526 } catch (Exception e) {
1527 Log.e(TAG, "Unexpected exception collecting process stats", e);
1528 }
1529 }
1530 }
1531 };
1532 mProcessStatsThread.start();
1533 }
1534
1535 @Override
1536 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1537 throws RemoteException {
1538 try {
1539 return super.onTransact(code, data, reply, flags);
1540 } catch (RuntimeException e) {
1541 // The activity manager only throws security exceptions, so let's
1542 // log all others.
1543 if (!(e instanceof SecurityException)) {
1544 Log.e(TAG, "Activity Manager Crash", e);
1545 }
1546 throw e;
1547 }
1548 }
1549
1550 void updateCpuStats() {
1551 synchronized (mProcessStatsThread) {
1552 final long now = SystemClock.uptimeMillis();
1553 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1554 mProcessStatsThread.notify();
1555 }
1556 }
1557 }
1558
1559 void updateCpuStatsNow() {
1560 synchronized (mProcessStatsThread) {
1561 final long now = SystemClock.uptimeMillis();
1562 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 if (MONITOR_CPU_USAGE &&
1565 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1566 mLastCpuTime = now;
1567 haveNewCpuStats = true;
1568 mProcessStats.update();
1569 //Log.i(TAG, mProcessStats.printCurrentState());
1570 //Log.i(TAG, "Total CPU usage: "
1571 // + mProcessStats.getTotalCpuPercent() + "%");
1572
1573 // Log the cpu usage if the property is set.
1574 if ("true".equals(SystemProperties.get("events.cpu"))) {
1575 int user = mProcessStats.getLastUserTime();
1576 int system = mProcessStats.getLastSystemTime();
1577 int iowait = mProcessStats.getLastIoWaitTime();
1578 int irq = mProcessStats.getLastIrqTime();
1579 int softIrq = mProcessStats.getLastSoftIrqTime();
1580 int idle = mProcessStats.getLastIdleTime();
1581
1582 int total = user + system + iowait + irq + softIrq + idle;
1583 if (total == 0) total = 1;
1584
1585 EventLog.writeEvent(LOG_CPU,
1586 ((user+system+iowait+irq+softIrq) * 100) / total,
1587 (user * 100) / total,
1588 (system * 100) / total,
1589 (iowait * 100) / total,
1590 (irq * 100) / total,
1591 (softIrq * 100) / total);
1592 }
1593 }
1594
Amith Yamasanie43530a2009-08-21 13:11:37 -07001595 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001596 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001597 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 synchronized(mPidsSelfLocked) {
1599 if (haveNewCpuStats) {
1600 if (mBatteryStatsService.isOnBattery()) {
1601 final int N = mProcessStats.countWorkingStats();
1602 for (int i=0; i<N; i++) {
1603 ProcessStats.Stats st
1604 = mProcessStats.getWorkingStats(i);
1605 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1606 if (pr != null) {
1607 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1608 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001609 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001610 } else {
1611 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001612 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001613 if (ps != null) {
1614 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001615 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001616 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 }
1618 }
1619 }
1620 }
1621 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1624 mLastWriteTime = now;
1625 mBatteryStatsService.getActiveStatistics().writeLocked();
1626 }
1627 }
1628 }
1629 }
1630
1631 /**
1632 * Initialize the application bind args. These are passed to each
1633 * process when the bindApplication() IPC is sent to the process. They're
1634 * lazily setup to make sure the services are running when they're asked for.
1635 */
1636 private HashMap<String, IBinder> getCommonServicesLocked() {
1637 if (mAppBindArgs == null) {
1638 mAppBindArgs = new HashMap<String, IBinder>();
1639
1640 // Setup the application init args
1641 mAppBindArgs.put("package", ServiceManager.getService("package"));
1642 mAppBindArgs.put("window", ServiceManager.getService("window"));
1643 mAppBindArgs.put(Context.ALARM_SERVICE,
1644 ServiceManager.getService(Context.ALARM_SERVICE));
1645 }
1646 return mAppBindArgs;
1647 }
1648
1649 private final void setFocusedActivityLocked(HistoryRecord r) {
1650 if (mFocusedActivity != r) {
1651 mFocusedActivity = r;
1652 mWindowManager.setFocusedApp(r, true);
1653 }
1654 }
1655
1656 private final void updateLRUListLocked(ProcessRecord app,
1657 boolean oomAdj) {
1658 // put it on the LRU to keep track of when it should be exited.
1659 int lrui = mLRUProcesses.indexOf(app);
1660 if (lrui >= 0) mLRUProcesses.remove(lrui);
1661 mLRUProcesses.add(app);
1662 //Log.i(TAG, "Putting proc to front: " + app.processName);
1663 if (oomAdj) {
1664 updateOomAdjLocked();
1665 }
1666 }
1667
1668 private final boolean updateLRUListLocked(HistoryRecord r) {
1669 final boolean hadit = mLRUActivities.remove(r);
1670 mLRUActivities.add(r);
1671 return hadit;
1672 }
1673
1674 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1675 int i = mHistory.size()-1;
1676 while (i >= 0) {
1677 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1678 if (!r.finishing && r != notTop) {
1679 return r;
1680 }
1681 i--;
1682 }
1683 return null;
1684 }
1685
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001686 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1687 int i = mHistory.size()-1;
1688 while (i >= 0) {
1689 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1690 if (!r.finishing && !r.delayedResume && r != notTop) {
1691 return r;
1692 }
1693 i--;
1694 }
1695 return null;
1696 }
1697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 /**
1699 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001700 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 *
1702 * @param token If non-null, any history records matching this token will be skipped.
1703 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1704 *
1705 * @return Returns the HistoryRecord of the next activity on the stack.
1706 */
1707 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1708 int i = mHistory.size()-1;
1709 while (i >= 0) {
1710 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1711 // Note: the taskId check depends on real taskId fields being non-zero
1712 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1713 return r;
1714 }
1715 i--;
1716 }
1717 return null;
1718 }
1719
1720 private final ProcessRecord getProcessRecordLocked(
1721 String processName, int uid) {
1722 if (uid == Process.SYSTEM_UID) {
1723 // The system gets to run in any process. If there are multiple
1724 // processes with the same uid, just pick the first (this
1725 // should never happen).
1726 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1727 processName);
1728 return procs != null ? procs.valueAt(0) : null;
1729 }
1730 ProcessRecord proc = mProcessNames.get(processName, uid);
1731 return proc;
1732 }
1733
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001734 private void ensurePackageDexOpt(String packageName) {
1735 IPackageManager pm = ActivityThread.getPackageManager();
1736 try {
1737 if (pm.performDexOpt(packageName)) {
1738 mDidDexOpt = true;
1739 }
1740 } catch (RemoteException e) {
1741 }
1742 }
1743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 private boolean isNextTransitionForward() {
1745 int transit = mWindowManager.getPendingAppTransition();
1746 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1747 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1748 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1749 }
1750
1751 private final boolean realStartActivityLocked(HistoryRecord r,
1752 ProcessRecord app, boolean andResume, boolean checkConfig)
1753 throws RemoteException {
1754
1755 r.startFreezingScreenLocked(app, 0);
1756 mWindowManager.setAppVisibility(r, true);
1757
1758 // Have the window manager re-evaluate the orientation of
1759 // the screen based on the new activity order. Note that
1760 // as a result of this, it can call back into the activity
1761 // manager with a new orientation. We don't care about that,
1762 // because the activity is not currently running so we are
1763 // just restarting it anyway.
1764 if (checkConfig) {
1765 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001766 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 r.mayFreezeScreenLocked(app) ? r : null);
1768 updateConfigurationLocked(config, r);
1769 }
1770
1771 r.app = app;
1772
1773 if (localLOGV) Log.v(TAG, "Launching: " + r);
1774
1775 int idx = app.activities.indexOf(r);
1776 if (idx < 0) {
1777 app.activities.add(r);
1778 }
1779 updateLRUListLocked(app, true);
1780
1781 try {
1782 if (app.thread == null) {
1783 throw new RemoteException();
1784 }
1785 List<ResultInfo> results = null;
1786 List<Intent> newIntents = null;
1787 if (andResume) {
1788 results = r.results;
1789 newIntents = r.newIntents;
1790 }
1791 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1792 + " icicle=" + r.icicle
1793 + " with results=" + results + " newIntents=" + newIntents
1794 + " andResume=" + andResume);
1795 if (andResume) {
1796 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1797 System.identityHashCode(r),
1798 r.task.taskId, r.shortComponentName);
1799 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001800 if (r.isHomeActivity) {
1801 mHomeProcess = app;
1802 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001803 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001805 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 r.info, r.icicle, results, newIntents, !andResume,
1807 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 } catch (RemoteException e) {
1809 if (r.launchFailed) {
1810 // This is the second time we failed -- finish activity
1811 // and give up.
1812 Log.e(TAG, "Second failure launching "
1813 + r.intent.getComponent().flattenToShortString()
1814 + ", giving up", e);
1815 appDiedLocked(app, app.pid, app.thread);
1816 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1817 "2nd-crash");
1818 return false;
1819 }
1820
1821 // This is the first time we failed -- restart process and
1822 // retry.
1823 app.activities.remove(r);
1824 throw e;
1825 }
1826
1827 r.launchFailed = false;
1828 if (updateLRUListLocked(r)) {
1829 Log.w(TAG, "Activity " + r
1830 + " being launched, but already in LRU list");
1831 }
1832
1833 if (andResume) {
1834 // As part of the process of launching, ActivityThread also performs
1835 // a resume.
1836 r.state = ActivityState.RESUMED;
1837 r.icicle = null;
1838 r.haveState = false;
1839 r.stopped = false;
1840 mResumedActivity = r;
1841 r.task.touchActiveTime();
1842 completeResumeLocked(r);
1843 pauseIfSleepingLocked();
1844 } else {
1845 // This activity is not starting in the resumed state... which
1846 // should look like we asked it to pause+stop (but remain visible),
1847 // and it has done so and reported back the current icicle and
1848 // other state.
1849 r.state = ActivityState.STOPPED;
1850 r.stopped = true;
1851 }
1852
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001853 // Launch the new version setup screen if needed. We do this -after-
1854 // launching the initial activity (that is, home), so that it can have
1855 // a chance to initialize itself while in the background, making the
1856 // switch back to it faster and look better.
1857 startSetupActivityLocked();
1858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 return true;
1860 }
1861
1862 private final void startSpecificActivityLocked(HistoryRecord r,
1863 boolean andResume, boolean checkConfig) {
1864 // Is this activity's application already running?
1865 ProcessRecord app = getProcessRecordLocked(r.processName,
1866 r.info.applicationInfo.uid);
1867
1868 if (r.startTime == 0) {
1869 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001870 if (mInitialStartTime == 0) {
1871 mInitialStartTime = r.startTime;
1872 }
1873 } else if (mInitialStartTime == 0) {
1874 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 }
1876
1877 if (app != null && app.thread != null) {
1878 try {
1879 realStartActivityLocked(r, app, andResume, checkConfig);
1880 return;
1881 } catch (RemoteException e) {
1882 Log.w(TAG, "Exception when starting activity "
1883 + r.intent.getComponent().flattenToShortString(), e);
1884 }
1885
1886 // If a dead object exception was thrown -- fall through to
1887 // restart the application.
1888 }
1889
1890 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001891 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 }
1893
1894 private final ProcessRecord startProcessLocked(String processName,
1895 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001896 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1898 // We don't have to do anything more if:
1899 // (1) There is an existing application record; and
1900 // (2) The caller doesn't think it is dead, OR there is no thread
1901 // object attached to it so we know it couldn't have crashed; and
1902 // (3) There is a pid assigned to it, so it is either starting or
1903 // already running.
1904 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1905 + " app=" + app + " knownToBeDead=" + knownToBeDead
1906 + " thread=" + (app != null ? app.thread : null)
1907 + " pid=" + (app != null ? app.pid : -1));
1908 if (app != null &&
1909 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1910 return app;
1911 }
1912
1913 String hostingNameStr = hostingName != null
1914 ? hostingName.flattenToShortString() : null;
1915
1916 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1917 // If we are in the background, then check to see if this process
1918 // is bad. If so, we will just silently fail.
1919 if (mBadProcesses.get(info.processName, info.uid) != null) {
1920 return null;
1921 }
1922 } else {
1923 // When the user is explicitly starting a process, then clear its
1924 // crash count so that we won't make it bad until they see at
1925 // least one crash dialog again, and make the process good again
1926 // if it had been bad.
1927 mProcessCrashTimes.remove(info.processName, info.uid);
1928 if (mBadProcesses.get(info.processName, info.uid) != null) {
1929 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1930 info.processName);
1931 mBadProcesses.remove(info.processName, info.uid);
1932 if (app != null) {
1933 app.bad = false;
1934 }
1935 }
1936 }
1937
1938 if (app == null) {
1939 app = newProcessRecordLocked(null, info, processName);
1940 mProcessNames.put(processName, info.uid, app);
1941 } else {
1942 // If this is a new package in the process, add the package to the list
1943 app.addPackage(info.packageName);
1944 }
1945
1946 // If the system is not ready yet, then hold off on starting this
1947 // process until it is.
1948 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001949 && !isAllowedWhileBooting(info)
1950 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001951 if (!mProcessesOnHold.contains(app)) {
1952 mProcessesOnHold.add(app);
1953 }
1954 return app;
1955 }
1956
1957 startProcessLocked(app, hostingType, hostingNameStr);
1958 return (app.pid != 0) ? app : null;
1959 }
1960
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001961 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1962 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1963 }
1964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 private final void startProcessLocked(ProcessRecord app,
1966 String hostingType, String hostingNameStr) {
1967 if (app.pid > 0 && app.pid != MY_PID) {
1968 synchronized (mPidsSelfLocked) {
1969 mPidsSelfLocked.remove(app.pid);
1970 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1971 }
1972 app.pid = 0;
1973 }
1974
1975 mProcessesOnHold.remove(app);
1976
1977 updateCpuStats();
1978
1979 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1980 mProcDeaths[0] = 0;
1981
1982 try {
1983 int uid = app.info.uid;
1984 int[] gids = null;
1985 try {
1986 gids = mContext.getPackageManager().getPackageGids(
1987 app.info.packageName);
1988 } catch (PackageManager.NameNotFoundException e) {
1989 Log.w(TAG, "Unable to retrieve gids", e);
1990 }
1991 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1992 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1993 && mTopComponent != null
1994 && app.processName.equals(mTopComponent.getPackageName())) {
1995 uid = 0;
1996 }
1997 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1998 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1999 uid = 0;
2000 }
2001 }
2002 int debugFlags = 0;
2003 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
2004 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
2005 }
2006 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
2007 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
2008 }
2009 if ("1".equals(SystemProperties.get("debug.assert"))) {
2010 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2011 }
2012 int pid = Process.start("android.app.ActivityThread",
2013 mSimpleProcessManagement ? app.processName : null, uid, uid,
2014 gids, debugFlags, null);
2015 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2016 synchronized (bs) {
2017 if (bs.isOnBattery()) {
2018 app.batteryStats.incStartsLocked();
2019 }
2020 }
2021
2022 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2023 app.processName, hostingType,
2024 hostingNameStr != null ? hostingNameStr : "");
2025
2026 if (app.persistent) {
2027 Watchdog.getInstance().processStarted(app, app.processName, pid);
2028 }
2029
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002030 StringBuilder buf = mStringBuilder;
2031 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 buf.append("Start proc ");
2033 buf.append(app.processName);
2034 buf.append(" for ");
2035 buf.append(hostingType);
2036 if (hostingNameStr != null) {
2037 buf.append(" ");
2038 buf.append(hostingNameStr);
2039 }
2040 buf.append(": pid=");
2041 buf.append(pid);
2042 buf.append(" uid=");
2043 buf.append(uid);
2044 buf.append(" gids={");
2045 if (gids != null) {
2046 for (int gi=0; gi<gids.length; gi++) {
2047 if (gi != 0) buf.append(", ");
2048 buf.append(gids[gi]);
2049
2050 }
2051 }
2052 buf.append("}");
2053 Log.i(TAG, buf.toString());
2054 if (pid == 0 || pid == MY_PID) {
2055 // Processes are being emulated with threads.
2056 app.pid = MY_PID;
2057 app.removed = false;
2058 mStartingProcesses.add(app);
2059 } else if (pid > 0) {
2060 app.pid = pid;
2061 app.removed = false;
2062 synchronized (mPidsSelfLocked) {
2063 this.mPidsSelfLocked.put(pid, app);
2064 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2065 msg.obj = app;
2066 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2067 }
2068 } else {
2069 app.pid = 0;
2070 RuntimeException e = new RuntimeException(
2071 "Failure starting process " + app.processName
2072 + ": returned pid=" + pid);
2073 Log.e(TAG, e.getMessage(), e);
2074 }
2075 } catch (RuntimeException e) {
2076 // XXX do better error recovery.
2077 app.pid = 0;
2078 Log.e(TAG, "Failure starting process " + app.processName, e);
2079 }
2080 }
2081
2082 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2083 if (mPausingActivity != null) {
2084 RuntimeException e = new RuntimeException();
2085 Log.e(TAG, "Trying to pause when pause is already pending for "
2086 + mPausingActivity, e);
2087 }
2088 HistoryRecord prev = mResumedActivity;
2089 if (prev == null) {
2090 RuntimeException e = new RuntimeException();
2091 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2092 resumeTopActivityLocked(null);
2093 return;
2094 }
2095 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2096 mResumedActivity = null;
2097 mPausingActivity = prev;
2098 mLastPausedActivity = prev;
2099 prev.state = ActivityState.PAUSING;
2100 prev.task.touchActiveTime();
2101
2102 updateCpuStats();
2103
2104 if (prev.app != null && prev.app.thread != null) {
2105 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2106 try {
2107 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2108 System.identityHashCode(prev),
2109 prev.shortComponentName);
2110 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2111 prev.configChangeFlags);
2112 updateUsageStats(prev, false);
2113 } catch (Exception e) {
2114 // Ignore exception, if process died other code will cleanup.
2115 Log.w(TAG, "Exception thrown during pause", e);
2116 mPausingActivity = null;
2117 mLastPausedActivity = null;
2118 }
2119 } else {
2120 mPausingActivity = null;
2121 mLastPausedActivity = null;
2122 }
2123
2124 // If we are not going to sleep, we want to ensure the device is
2125 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002126 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127 mLaunchingActivity.acquire();
2128 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2129 // To be safe, don't allow the wake lock to be held for too long.
2130 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2131 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2132 }
2133 }
2134
2135
2136 if (mPausingActivity != null) {
2137 // Have the window manager pause its key dispatching until the new
2138 // activity has started. If we're pausing the activity just because
2139 // the screen is being turned off and the UI is sleeping, don't interrupt
2140 // key dispatch; the same activity will pick it up again on wakeup.
2141 if (!uiSleeping) {
2142 prev.pauseKeyDispatchingLocked();
2143 } else {
2144 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2145 }
2146
2147 // Schedule a pause timeout in case the app doesn't respond.
2148 // We don't give it much time because this directly impacts the
2149 // responsiveness seen by the user.
2150 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2151 msg.obj = prev;
2152 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2153 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2154 } else {
2155 // This activity failed to schedule the
2156 // pause, so just treat it as being paused now.
2157 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2158 resumeTopActivityLocked(null);
2159 }
2160 }
2161
2162 private final void completePauseLocked() {
2163 HistoryRecord prev = mPausingActivity;
2164 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2165
2166 if (prev != null) {
2167 if (prev.finishing) {
2168 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2169 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2170 } else if (prev.app != null) {
2171 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2172 if (prev.waitingVisible) {
2173 prev.waitingVisible = false;
2174 mWaitingVisibleActivities.remove(prev);
2175 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2176 TAG, "Complete pause, no longer waiting: " + prev);
2177 }
2178 if (prev.configDestroy) {
2179 // The previous is being paused because the configuration
2180 // is changing, which means it is actually stopping...
2181 // To juggle the fact that we are also starting a new
2182 // instance right now, we need to first completely stop
2183 // the current instance before starting the new one.
2184 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2185 destroyActivityLocked(prev, true);
2186 } else {
2187 mStoppingActivities.add(prev);
2188 if (mStoppingActivities.size() > 3) {
2189 // If we already have a few activities waiting to stop,
2190 // then give up on things going idle and start clearing
2191 // them out.
2192 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2193 Message msg = Message.obtain();
2194 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2195 mHandler.sendMessage(msg);
2196 }
2197 }
2198 } else {
2199 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2200 prev = null;
2201 }
2202 mPausingActivity = null;
2203 }
2204
Dianne Hackborn55280a92009-05-07 15:53:46 -07002205 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002206 resumeTopActivityLocked(prev);
2207 } else {
2208 if (mGoingToSleep.isHeld()) {
2209 mGoingToSleep.release();
2210 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002211 if (mShuttingDown) {
2212 notifyAll();
2213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002214 }
2215
2216 if (prev != null) {
2217 prev.resumeKeyDispatchingLocked();
2218 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002219
2220 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2221 long diff = 0;
2222 synchronized (mProcessStatsThread) {
2223 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2224 }
2225 if (diff > 0) {
2226 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2227 synchronized (bsi) {
2228 BatteryStatsImpl.Uid.Proc ps =
2229 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2230 prev.info.packageName);
2231 if (ps != null) {
2232 ps.addForegroundTimeLocked(diff);
2233 }
2234 }
2235 }
2236 }
2237 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002238 }
2239
2240 /**
2241 * Once we know that we have asked an application to put an activity in
2242 * the resumed state (either by launching it or explicitly telling it),
2243 * this function updates the rest of our state to match that fact.
2244 */
2245 private final void completeResumeLocked(HistoryRecord next) {
2246 next.idle = false;
2247 next.results = null;
2248 next.newIntents = null;
2249
2250 // schedule an idle timeout in case the app doesn't do it for us.
2251 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2252 msg.obj = next;
2253 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2254
2255 if (false) {
2256 // The activity was never told to pause, so just keep
2257 // things going as-is. To maintain our own state,
2258 // we need to emulate it coming back and saying it is
2259 // idle.
2260 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2261 msg.obj = next;
2262 mHandler.sendMessage(msg);
2263 }
2264
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002265 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002267 next.thumbnail = null;
2268 setFocusedActivityLocked(next);
2269 next.resumeKeyDispatchingLocked();
2270 ensureActivitiesVisibleLocked(null, 0);
2271 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002272 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002273
2274 // Mark the point when the activity is resuming
2275 // TODO: To be more accurate, the mark should be before the onCreate,
2276 // not after the onResume. But for subsequent starts, onResume is fine.
2277 if (next.app != null) {
2278 synchronized (mProcessStatsThread) {
2279 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2280 }
2281 } else {
2282 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002284 }
2285
2286 /**
2287 * Make sure that all activities that need to be visible (that is, they
2288 * currently can be seen by the user) actually are.
2289 */
2290 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2291 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2292 if (DEBUG_VISBILITY) Log.v(
2293 TAG, "ensureActivitiesVisible behind " + top
2294 + " configChanges=0x" + Integer.toHexString(configChanges));
2295
2296 // If the top activity is not fullscreen, then we need to
2297 // make sure any activities under it are now visible.
2298 final int count = mHistory.size();
2299 int i = count-1;
2300 while (mHistory.get(i) != top) {
2301 i--;
2302 }
2303 HistoryRecord r;
2304 boolean behindFullscreen = false;
2305 for (; i>=0; i--) {
2306 r = (HistoryRecord)mHistory.get(i);
2307 if (DEBUG_VISBILITY) Log.v(
2308 TAG, "Make visible? " + r + " finishing=" + r.finishing
2309 + " state=" + r.state);
2310 if (r.finishing) {
2311 continue;
2312 }
2313
2314 final boolean doThisProcess = onlyThisProcess == null
2315 || onlyThisProcess.equals(r.processName);
2316
2317 // First: if this is not the current activity being started, make
2318 // sure it matches the current configuration.
2319 if (r != starting && doThisProcess) {
2320 ensureActivityConfigurationLocked(r, 0);
2321 }
2322
2323 if (r.app == null || r.app.thread == null) {
2324 if (onlyThisProcess == null
2325 || onlyThisProcess.equals(r.processName)) {
2326 // This activity needs to be visible, but isn't even
2327 // running... get it started, but don't resume it
2328 // at this point.
2329 if (DEBUG_VISBILITY) Log.v(
2330 TAG, "Start and freeze screen for " + r);
2331 if (r != starting) {
2332 r.startFreezingScreenLocked(r.app, configChanges);
2333 }
2334 if (!r.visible) {
2335 if (DEBUG_VISBILITY) Log.v(
2336 TAG, "Starting and making visible: " + r);
2337 mWindowManager.setAppVisibility(r, true);
2338 }
2339 if (r != starting) {
2340 startSpecificActivityLocked(r, false, false);
2341 }
2342 }
2343
2344 } else if (r.visible) {
2345 // If this activity is already visible, then there is nothing
2346 // else to do here.
2347 if (DEBUG_VISBILITY) Log.v(
2348 TAG, "Skipping: already visible at " + r);
2349 r.stopFreezingScreenLocked(false);
2350
2351 } else if (onlyThisProcess == null) {
2352 // This activity is not currently visible, but is running.
2353 // Tell it to become visible.
2354 r.visible = true;
2355 if (r.state != ActivityState.RESUMED && r != starting) {
2356 // If this activity is paused, tell it
2357 // to now show its window.
2358 if (DEBUG_VISBILITY) Log.v(
2359 TAG, "Making visible and scheduling visibility: " + r);
2360 try {
2361 mWindowManager.setAppVisibility(r, true);
2362 r.app.thread.scheduleWindowVisibility(r, true);
2363 r.stopFreezingScreenLocked(false);
2364 } catch (Exception e) {
2365 // Just skip on any failure; we'll make it
2366 // visible when it next restarts.
2367 Log.w(TAG, "Exception thrown making visibile: "
2368 + r.intent.getComponent(), e);
2369 }
2370 }
2371 }
2372
2373 // Aggregate current change flags.
2374 configChanges |= r.configChangeFlags;
2375
2376 if (r.fullscreen) {
2377 // At this point, nothing else needs to be shown
2378 if (DEBUG_VISBILITY) Log.v(
2379 TAG, "Stopping: fullscreen at " + r);
2380 behindFullscreen = true;
2381 i--;
2382 break;
2383 }
2384 }
2385
2386 // Now for any activities that aren't visible to the user, make
2387 // sure they no longer are keeping the screen frozen.
2388 while (i >= 0) {
2389 r = (HistoryRecord)mHistory.get(i);
2390 if (DEBUG_VISBILITY) Log.v(
2391 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2392 + " state=" + r.state
2393 + " behindFullscreen=" + behindFullscreen);
2394 if (!r.finishing) {
2395 if (behindFullscreen) {
2396 if (r.visible) {
2397 if (DEBUG_VISBILITY) Log.v(
2398 TAG, "Making invisible: " + r);
2399 r.visible = false;
2400 try {
2401 mWindowManager.setAppVisibility(r, false);
2402 if ((r.state == ActivityState.STOPPING
2403 || r.state == ActivityState.STOPPED)
2404 && r.app != null && r.app.thread != null) {
2405 if (DEBUG_VISBILITY) Log.v(
2406 TAG, "Scheduling invisibility: " + r);
2407 r.app.thread.scheduleWindowVisibility(r, false);
2408 }
2409 } catch (Exception e) {
2410 // Just skip on any failure; we'll make it
2411 // visible when it next restarts.
2412 Log.w(TAG, "Exception thrown making hidden: "
2413 + r.intent.getComponent(), e);
2414 }
2415 } else {
2416 if (DEBUG_VISBILITY) Log.v(
2417 TAG, "Already invisible: " + r);
2418 }
2419 } else if (r.fullscreen) {
2420 if (DEBUG_VISBILITY) Log.v(
2421 TAG, "Now behindFullscreen: " + r);
2422 behindFullscreen = true;
2423 }
2424 }
2425 i--;
2426 }
2427 }
2428
2429 /**
2430 * Version of ensureActivitiesVisible that can easily be called anywhere.
2431 */
2432 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2433 int configChanges) {
2434 HistoryRecord r = topRunningActivityLocked(null);
2435 if (r != null) {
2436 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2437 }
2438 }
2439
2440 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2441 if (resumed) {
2442 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2443 } else {
2444 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2445 }
2446 }
2447
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002448 private boolean startHomeActivityLocked() {
2449 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2450 && mTopAction == null) {
2451 // We are running in factory test mode, but unable to find
2452 // the factory test app, so just sit around displaying the
2453 // error message and don't try to start anything.
2454 return false;
2455 }
2456 Intent intent = new Intent(
2457 mTopAction,
2458 mTopData != null ? Uri.parse(mTopData) : null);
2459 intent.setComponent(mTopComponent);
2460 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2461 intent.addCategory(Intent.CATEGORY_HOME);
2462 }
2463 ActivityInfo aInfo =
2464 intent.resolveActivityInfo(mContext.getPackageManager(),
2465 STOCK_PM_FLAGS);
2466 if (aInfo != null) {
2467 intent.setComponent(new ComponentName(
2468 aInfo.applicationInfo.packageName, aInfo.name));
2469 // Don't do this if the home app is currently being
2470 // instrumented.
2471 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2472 aInfo.applicationInfo.uid);
2473 if (app == null || app.instrumentationClass == null) {
2474 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2475 startActivityLocked(null, intent, null, null, 0, aInfo,
2476 null, null, 0, 0, 0, false, false);
2477 }
2478 }
2479
2480
2481 return true;
2482 }
2483
2484 /**
2485 * Starts the "new version setup screen" if appropriate.
2486 */
2487 private void startSetupActivityLocked() {
2488 // Only do this once per boot.
2489 if (mCheckedForSetup) {
2490 return;
2491 }
2492
2493 // We will show this screen if the current one is a different
2494 // version than the last one shown, and we are not running in
2495 // low-level factory test mode.
2496 final ContentResolver resolver = mContext.getContentResolver();
2497 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2498 Settings.Secure.getInt(resolver,
2499 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2500 mCheckedForSetup = true;
2501
2502 // See if we should be showing the platform update setup UI.
2503 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2504 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2505 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2506
2507 // We don't allow third party apps to replace this.
2508 ResolveInfo ri = null;
2509 for (int i=0; ris != null && i<ris.size(); i++) {
2510 if ((ris.get(i).activityInfo.applicationInfo.flags
2511 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2512 ri = ris.get(i);
2513 break;
2514 }
2515 }
2516
2517 if (ri != null) {
2518 String vers = ri.activityInfo.metaData != null
2519 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2520 : null;
2521 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2522 vers = ri.activityInfo.applicationInfo.metaData.getString(
2523 Intent.METADATA_SETUP_VERSION);
2524 }
2525 String lastVers = Settings.Secure.getString(
2526 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2527 if (vers != null && !vers.equals(lastVers)) {
2528 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2529 intent.setComponent(new ComponentName(
2530 ri.activityInfo.packageName, ri.activityInfo.name));
2531 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2532 null, null, 0, 0, 0, false, false);
2533 }
2534 }
2535 }
2536 }
2537
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002538 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002539 //Log.i(TAG, "**** REPORT RESUME: " + r);
2540
2541 final int identHash = System.identityHashCode(r);
2542 updateUsageStats(r, true);
2543
2544 int i = mWatchers.beginBroadcast();
2545 while (i > 0) {
2546 i--;
2547 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2548 if (w != null) {
2549 try {
2550 w.activityResuming(identHash);
2551 } catch (RemoteException e) {
2552 }
2553 }
2554 }
2555 mWatchers.finishBroadcast();
2556 }
2557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002558 /**
2559 * Ensure that the top activity in the stack is resumed.
2560 *
2561 * @param prev The previously resumed activity, for when in the process
2562 * of pausing; can be null to call from elsewhere.
2563 *
2564 * @return Returns true if something is being resumed, or false if
2565 * nothing happened.
2566 */
2567 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2568 // Find the first activity that is not finishing.
2569 HistoryRecord next = topRunningActivityLocked(null);
2570
2571 // Remember how we'll process this pause/resume situation, and ensure
2572 // that the state is reset however we wind up proceeding.
2573 final boolean userLeaving = mUserLeaving;
2574 mUserLeaving = false;
2575
2576 if (next == null) {
2577 // There are no more activities! Let's just start up the
2578 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002579 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 }
2581
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002582 next.delayedResume = false;
2583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002584 // If the top activity is the resumed one, nothing to do.
2585 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2586 // Make sure we have executed any pending transitions, since there
2587 // should be nothing left to do at this point.
2588 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002589 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002590 return false;
2591 }
2592
2593 // If we are sleeping, and there is no resumed activity, and the top
2594 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002595 if ((mSleeping || mShuttingDown)
2596 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002597 // Make sure we have executed any pending transitions, since there
2598 // should be nothing left to do at this point.
2599 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002600 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002601 return false;
2602 }
2603
2604 // The activity may be waiting for stop, but that is no longer
2605 // appropriate for it.
2606 mStoppingActivities.remove(next);
2607 mWaitingVisibleActivities.remove(next);
2608
2609 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2610
2611 // If we are currently pausing an activity, then don't do anything
2612 // until that is done.
2613 if (mPausingActivity != null) {
2614 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2615 return false;
2616 }
2617
2618 // We need to start pausing the current activity so the top one
2619 // can be resumed...
2620 if (mResumedActivity != null) {
2621 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2622 startPausingLocked(userLeaving, false);
2623 return true;
2624 }
2625
2626 if (prev != null && prev != next) {
2627 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2628 prev.waitingVisible = true;
2629 mWaitingVisibleActivities.add(prev);
2630 if (DEBUG_SWITCH) Log.v(
2631 TAG, "Resuming top, waiting visible to hide: " + prev);
2632 } else {
2633 // The next activity is already visible, so hide the previous
2634 // activity's windows right now so we can show the new one ASAP.
2635 // We only do this if the previous is finishing, which should mean
2636 // it is on top of the one being resumed so hiding it quickly
2637 // is good. Otherwise, we want to do the normal route of allowing
2638 // the resumed activity to be shown so we can decide if the
2639 // previous should actually be hidden depending on whether the
2640 // new one is found to be full-screen or not.
2641 if (prev.finishing) {
2642 mWindowManager.setAppVisibility(prev, false);
2643 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2644 + prev + ", waitingVisible="
2645 + (prev != null ? prev.waitingVisible : null)
2646 + ", nowVisible=" + next.nowVisible);
2647 } else {
2648 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2649 + prev + ", waitingVisible="
2650 + (prev != null ? prev.waitingVisible : null)
2651 + ", nowVisible=" + next.nowVisible);
2652 }
2653 }
2654 }
2655
2656 // We are starting up the next activity, so tell the window manager
2657 // that the previous one will be hidden soon. This way it can know
2658 // to ignore it when computing the desired screen orientation.
2659 if (prev != null) {
2660 if (prev.finishing) {
2661 if (DEBUG_TRANSITION) Log.v(TAG,
2662 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002663 if (mNoAnimActivities.contains(prev)) {
2664 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2665 } else {
2666 mWindowManager.prepareAppTransition(prev.task == next.task
2667 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2668 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2669 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002670 mWindowManager.setAppWillBeHidden(prev);
2671 mWindowManager.setAppVisibility(prev, false);
2672 } else {
2673 if (DEBUG_TRANSITION) Log.v(TAG,
2674 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002675 if (mNoAnimActivities.contains(next)) {
2676 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2677 } else {
2678 mWindowManager.prepareAppTransition(prev.task == next.task
2679 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2680 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002682 }
2683 if (false) {
2684 mWindowManager.setAppWillBeHidden(prev);
2685 mWindowManager.setAppVisibility(prev, false);
2686 }
2687 } else if (mHistory.size() > 1) {
2688 if (DEBUG_TRANSITION) Log.v(TAG,
2689 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002690 if (mNoAnimActivities.contains(next)) {
2691 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2692 } else {
2693 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002695 }
2696
2697 if (next.app != null && next.app.thread != null) {
2698 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2699
2700 // This activity is now becoming visible.
2701 mWindowManager.setAppVisibility(next, true);
2702
2703 HistoryRecord lastResumedActivity = mResumedActivity;
2704 ActivityState lastState = next.state;
2705
2706 updateCpuStats();
2707
2708 next.state = ActivityState.RESUMED;
2709 mResumedActivity = next;
2710 next.task.touchActiveTime();
2711 updateLRUListLocked(next.app, true);
2712 updateLRUListLocked(next);
2713
2714 // Have the window manager re-evaluate the orientation of
2715 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002716 boolean updated;
2717 synchronized (this) {
2718 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2719 mConfiguration,
2720 next.mayFreezeScreenLocked(next.app) ? next : null);
2721 if (config != null) {
2722 /*
2723 * Explicitly restore the locale to the one from the
2724 * old configuration, since the one that comes back from
2725 * the window manager has the default (boot) locale.
2726 *
2727 * It looks like previously the locale picker only worked
2728 * by coincidence: usually it would do its setting of
2729 * the locale after the activity transition, so it didn't
2730 * matter that this lost it. With the synchronized
2731 * block now keeping them from happening at the same time,
2732 * this one always would happen second and undo what the
2733 * locale picker had just done.
2734 */
2735 config.locale = mConfiguration.locale;
2736 next.frozenBeforeDestroy = true;
2737 }
2738 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002739 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002740 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002741 // The configuration update wasn't able to keep the existing
2742 // instance of the activity, and instead started a new one.
2743 // We should be all done, but let's just make sure our activity
2744 // is still at the top and schedule another run if something
2745 // weird happened.
2746 HistoryRecord nextNext = topRunningActivityLocked(null);
2747 if (DEBUG_SWITCH) Log.i(TAG,
2748 "Activity config changed during resume: " + next
2749 + ", new next: " + nextNext);
2750 if (nextNext != next) {
2751 // Do over!
2752 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2753 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002754 setFocusedActivityLocked(next);
2755 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002756 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002757 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002758 return true;
2759 }
2760
2761 try {
2762 // Deliver all pending results.
2763 ArrayList a = next.results;
2764 if (a != null) {
2765 final int N = a.size();
2766 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002767 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002768 TAG, "Delivering results to " + next
2769 + ": " + a);
2770 next.app.thread.scheduleSendResult(next, a);
2771 }
2772 }
2773
2774 if (next.newIntents != null) {
2775 next.app.thread.scheduleNewIntent(next.newIntents, next);
2776 }
2777
2778 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2779 System.identityHashCode(next),
2780 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781
2782 next.app.thread.scheduleResumeActivity(next,
2783 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002785 pauseIfSleepingLocked();
2786
2787 } catch (Exception e) {
2788 // Whoops, need to restart this activity!
2789 next.state = lastState;
2790 mResumedActivity = lastResumedActivity;
2791 if (Config.LOGD) Log.d(TAG,
2792 "Restarting because process died: " + next);
2793 if (!next.hasBeenLaunched) {
2794 next.hasBeenLaunched = true;
2795 } else {
2796 if (SHOW_APP_STARTING_ICON) {
2797 mWindowManager.setAppStartingWindow(
2798 next, next.packageName, next.theme,
2799 next.nonLocalizedLabel,
2800 next.labelRes, next.icon, null, true);
2801 }
2802 }
2803 startSpecificActivityLocked(next, true, false);
2804 return true;
2805 }
2806
2807 // From this point on, if something goes wrong there is no way
2808 // to recover the activity.
2809 try {
2810 next.visible = true;
2811 completeResumeLocked(next);
2812 } catch (Exception e) {
2813 // If any exception gets thrown, toss away this
2814 // activity and try the next one.
2815 Log.w(TAG, "Exception thrown during resume of " + next, e);
2816 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2817 "resume-exception");
2818 return true;
2819 }
2820
2821 // Didn't need to use the icicle, and it is now out of date.
2822 next.icicle = null;
2823 next.haveState = false;
2824 next.stopped = false;
2825
2826 } else {
2827 // Whoops, need to restart this activity!
2828 if (!next.hasBeenLaunched) {
2829 next.hasBeenLaunched = true;
2830 } else {
2831 if (SHOW_APP_STARTING_ICON) {
2832 mWindowManager.setAppStartingWindow(
2833 next, next.packageName, next.theme,
2834 next.nonLocalizedLabel,
2835 next.labelRes, next.icon, null, true);
2836 }
2837 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2838 }
2839 startSpecificActivityLocked(next, true, true);
2840 }
2841
2842 return true;
2843 }
2844
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002845 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2846 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002847 final int NH = mHistory.size();
2848
2849 int addPos = -1;
2850
2851 if (!newTask) {
2852 // If starting in an existing task, find where that is...
2853 HistoryRecord next = null;
2854 boolean startIt = true;
2855 for (int i = NH-1; i >= 0; i--) {
2856 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2857 if (p.finishing) {
2858 continue;
2859 }
2860 if (p.task == r.task) {
2861 // Here it is! Now, if this is not yet visible to the
2862 // user, then just add it without starting; it will
2863 // get started when the user navigates back to it.
2864 addPos = i+1;
2865 if (!startIt) {
2866 mHistory.add(addPos, r);
2867 r.inHistory = true;
2868 r.task.numActivities++;
2869 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2870 r.info.screenOrientation, r.fullscreen);
2871 if (VALIDATE_TOKENS) {
2872 mWindowManager.validateAppTokens(mHistory);
2873 }
2874 return;
2875 }
2876 break;
2877 }
2878 if (p.fullscreen) {
2879 startIt = false;
2880 }
2881 next = p;
2882 }
2883 }
2884
2885 // Place a new activity at top of stack, so it is next to interact
2886 // with the user.
2887 if (addPos < 0) {
2888 addPos = mHistory.size();
2889 }
2890
2891 // If we are not placing the new activity frontmost, we do not want
2892 // to deliver the onUserLeaving callback to the actual frontmost
2893 // activity
2894 if (addPos < NH) {
2895 mUserLeaving = false;
2896 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2897 }
2898
2899 // Slot the activity into the history stack and proceed
2900 mHistory.add(addPos, r);
2901 r.inHistory = true;
2902 r.frontOfTask = newTask;
2903 r.task.numActivities++;
2904 if (NH > 0) {
2905 // We want to show the starting preview window if we are
2906 // switching to a new task, or the next activity's process is
2907 // not currently running.
2908 boolean showStartingIcon = newTask;
2909 ProcessRecord proc = r.app;
2910 if (proc == null) {
2911 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2912 }
2913 if (proc == null || proc.thread == null) {
2914 showStartingIcon = true;
2915 }
2916 if (DEBUG_TRANSITION) Log.v(TAG,
2917 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002918 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2919 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2920 mNoAnimActivities.add(r);
2921 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2922 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2923 mNoAnimActivities.remove(r);
2924 } else {
2925 mWindowManager.prepareAppTransition(newTask
2926 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2927 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2928 mNoAnimActivities.remove(r);
2929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930 mWindowManager.addAppToken(
2931 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2932 boolean doShow = true;
2933 if (newTask) {
2934 // Even though this activity is starting fresh, we still need
2935 // to reset it to make sure we apply affinities to move any
2936 // existing activities from other tasks in to it.
2937 // If the caller has requested that the target task be
2938 // reset, then do so.
2939 if ((r.intent.getFlags()
2940 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2941 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002942 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002943 }
2944 }
2945 if (SHOW_APP_STARTING_ICON && doShow) {
2946 // Figure out if we are transitioning from another activity that is
2947 // "has the same starting icon" as the next one. This allows the
2948 // window manager to keep the previous window it had previously
2949 // created, if it still had one.
2950 HistoryRecord prev = mResumedActivity;
2951 if (prev != null) {
2952 // We don't want to reuse the previous starting preview if:
2953 // (1) The current activity is in a different task.
2954 if (prev.task != r.task) prev = null;
2955 // (2) The current activity is already displayed.
2956 else if (prev.nowVisible) prev = null;
2957 }
2958 mWindowManager.setAppStartingWindow(
2959 r, r.packageName, r.theme, r.nonLocalizedLabel,
2960 r.labelRes, r.icon, prev, showStartingIcon);
2961 }
2962 } else {
2963 // If this is the first activity, don't do any fancy animations,
2964 // because there is nothing for it to animate on top of.
2965 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2966 r.info.screenOrientation, r.fullscreen);
2967 }
2968 if (VALIDATE_TOKENS) {
2969 mWindowManager.validateAppTokens(mHistory);
2970 }
2971
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002972 if (doResume) {
2973 resumeTopActivityLocked(null);
2974 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002975 }
2976
2977 /**
2978 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002979 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2980 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002981 * an instance of that activity in the stack and, if found, finish all
2982 * activities on top of it and return the instance.
2983 *
2984 * @param newR Description of the new activity being started.
2985 * @return Returns the old activity that should be continue to be used,
2986 * or null if none was found.
2987 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002988 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002989 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002990 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002991
2992 // First find the requested task.
2993 while (i > 0) {
2994 i--;
2995 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2996 if (r.task.taskId == taskId) {
2997 i++;
2998 break;
2999 }
3000 }
3001
3002 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003 while (i > 0) {
3004 i--;
3005 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3006 if (r.finishing) {
3007 continue;
3008 }
3009 if (r.task.taskId != taskId) {
3010 return null;
3011 }
3012 if (r.realActivity.equals(newR.realActivity)) {
3013 // Here it is! Now finish everything in front...
3014 HistoryRecord ret = r;
3015 if (doClear) {
3016 while (i < (mHistory.size()-1)) {
3017 i++;
3018 r = (HistoryRecord)mHistory.get(i);
3019 if (r.finishing) {
3020 continue;
3021 }
3022 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
3023 null, "clear")) {
3024 i--;
3025 }
3026 }
3027 }
3028
3029 // Finally, if this is a normal launch mode (that is, not
3030 // expecting onNewIntent()), then we will finish the current
3031 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003032 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3033 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003035 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 if (index >= 0) {
3037 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3038 null, "clear");
3039 }
3040 return null;
3041 }
3042 }
3043
3044 return ret;
3045 }
3046 }
3047
3048 return null;
3049 }
3050
3051 /**
3052 * Find the activity in the history stack within the given task. Returns
3053 * the index within the history at which it's found, or < 0 if not found.
3054 */
3055 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3056 int i = mHistory.size();
3057 while (i > 0) {
3058 i--;
3059 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3060 if (candidate.task.taskId != task) {
3061 break;
3062 }
3063 if (candidate.realActivity.equals(r.realActivity)) {
3064 return i;
3065 }
3066 }
3067
3068 return -1;
3069 }
3070
3071 /**
3072 * Reorder the history stack so that the activity at the given index is
3073 * brought to the front.
3074 */
3075 private final HistoryRecord moveActivityToFrontLocked(int where) {
3076 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3077 int top = mHistory.size();
3078 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3079 mHistory.add(top, newTop);
3080 oldTop.frontOfTask = false;
3081 newTop.frontOfTask = true;
3082 return newTop;
3083 }
3084
3085 /**
3086 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3087 * method will be called at the proper time.
3088 */
3089 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3090 boolean sent = false;
3091 if (r.state == ActivityState.RESUMED
3092 && r.app != null && r.app.thread != null) {
3093 try {
3094 ArrayList<Intent> ar = new ArrayList<Intent>();
3095 ar.add(new Intent(intent));
3096 r.app.thread.scheduleNewIntent(ar, r);
3097 sent = true;
3098 } catch (Exception e) {
3099 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3100 }
3101 }
3102 if (!sent) {
3103 r.addNewIntentLocked(new Intent(intent));
3104 }
3105 }
3106
3107 private final void logStartActivity(int tag, HistoryRecord r,
3108 TaskRecord task) {
3109 EventLog.writeEvent(tag,
3110 System.identityHashCode(r), task.taskId,
3111 r.shortComponentName, r.intent.getAction(),
3112 r.intent.getType(), r.intent.getDataString(),
3113 r.intent.getFlags());
3114 }
3115
3116 private final int startActivityLocked(IApplicationThread caller,
3117 Intent intent, String resolvedType,
3118 Uri[] grantedUriPermissions,
3119 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3120 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003121 int callingPid, int callingUid, boolean onlyIfNeeded,
3122 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003123 Log.i(TAG, "Starting activity: " + intent);
3124
3125 HistoryRecord sourceRecord = null;
3126 HistoryRecord resultRecord = null;
3127 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003128 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003129 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003130 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3131 if (index >= 0) {
3132 sourceRecord = (HistoryRecord)mHistory.get(index);
3133 if (requestCode >= 0 && !sourceRecord.finishing) {
3134 resultRecord = sourceRecord;
3135 }
3136 }
3137 }
3138
3139 int launchFlags = intent.getFlags();
3140
3141 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3142 && sourceRecord != null) {
3143 // Transfer the result target from the source activity to the new
3144 // one being started, including any failures.
3145 if (requestCode >= 0) {
3146 return START_FORWARD_AND_REQUEST_CONFLICT;
3147 }
3148 resultRecord = sourceRecord.resultTo;
3149 resultWho = sourceRecord.resultWho;
3150 requestCode = sourceRecord.requestCode;
3151 sourceRecord.resultTo = null;
3152 if (resultRecord != null) {
3153 resultRecord.removeResultsLocked(
3154 sourceRecord, resultWho, requestCode);
3155 }
3156 }
3157
3158 int err = START_SUCCESS;
3159
3160 if (intent.getComponent() == null) {
3161 // We couldn't find a class that can handle the given Intent.
3162 // That's the end of that!
3163 err = START_INTENT_NOT_RESOLVED;
3164 }
3165
3166 if (err == START_SUCCESS && aInfo == null) {
3167 // We couldn't find the specific class specified in the Intent.
3168 // Also the end of the line.
3169 err = START_CLASS_NOT_FOUND;
3170 }
3171
3172 ProcessRecord callerApp = null;
3173 if (err == START_SUCCESS && caller != null) {
3174 callerApp = getRecordForAppLocked(caller);
3175 if (callerApp != null) {
3176 callingPid = callerApp.pid;
3177 callingUid = callerApp.info.uid;
3178 } else {
3179 Log.w(TAG, "Unable to find app for caller " + caller
3180 + " (pid=" + callingPid + ") when starting: "
3181 + intent.toString());
3182 err = START_PERMISSION_DENIED;
3183 }
3184 }
3185
3186 if (err != START_SUCCESS) {
3187 if (resultRecord != null) {
3188 sendActivityResultLocked(-1,
3189 resultRecord, resultWho, requestCode,
3190 Activity.RESULT_CANCELED, null);
3191 }
3192 return err;
3193 }
3194
3195 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3196 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3197 if (perm != PackageManager.PERMISSION_GRANTED) {
3198 if (resultRecord != null) {
3199 sendActivityResultLocked(-1,
3200 resultRecord, resultWho, requestCode,
3201 Activity.RESULT_CANCELED, null);
3202 }
3203 String msg = "Permission Denial: starting " + intent.toString()
3204 + " from " + callerApp + " (pid=" + callingPid
3205 + ", uid=" + callingUid + ")"
3206 + " requires " + aInfo.permission;
3207 Log.w(TAG, msg);
3208 throw new SecurityException(msg);
3209 }
3210
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003211 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 boolean abort = false;
3213 try {
3214 // The Intent we give to the watcher has the extra data
3215 // stripped off, since it can contain private information.
3216 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003217 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003218 aInfo.applicationInfo.packageName);
3219 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003220 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003221 }
3222
3223 if (abort) {
3224 if (resultRecord != null) {
3225 sendActivityResultLocked(-1,
3226 resultRecord, resultWho, requestCode,
3227 Activity.RESULT_CANCELED, null);
3228 }
3229 // We pretend to the caller that it was really started, but
3230 // they will just get a cancel result.
3231 return START_SUCCESS;
3232 }
3233 }
3234
3235 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3236 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003237 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003239 if (mResumedActivity == null
3240 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3241 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3242 PendingActivityLaunch pal = new PendingActivityLaunch();
3243 pal.r = r;
3244 pal.sourceRecord = sourceRecord;
3245 pal.grantedUriPermissions = grantedUriPermissions;
3246 pal.grantedMode = grantedMode;
3247 pal.onlyIfNeeded = onlyIfNeeded;
3248 mPendingActivityLaunches.add(pal);
3249 return START_SWITCHES_CANCELED;
3250 }
3251 }
3252
3253 if (mDidAppSwitch) {
3254 // This is the second allowed switch since we stopped switches,
3255 // so now just generally allow switches. Use case: user presses
3256 // home (switches disabled, switch to home, mDidAppSwitch now true);
3257 // user taps a home icon (coming from home so allowed, we hit here
3258 // and now allow anyone to switch again).
3259 mAppSwitchesAllowedTime = 0;
3260 } else {
3261 mDidAppSwitch = true;
3262 }
3263
3264 doPendingActivityLaunchesLocked(false);
3265
3266 return startActivityUncheckedLocked(r, sourceRecord,
3267 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3268 }
3269
3270 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3271 final int N = mPendingActivityLaunches.size();
3272 if (N <= 0) {
3273 return;
3274 }
3275 for (int i=0; i<N; i++) {
3276 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3277 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3278 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3279 doResume && i == (N-1));
3280 }
3281 mPendingActivityLaunches.clear();
3282 }
3283
3284 private final int startActivityUncheckedLocked(HistoryRecord r,
3285 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3286 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3287 final Intent intent = r.intent;
3288 final int callingUid = r.launchedFromUid;
3289
3290 int launchFlags = intent.getFlags();
3291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003292 // We'll invoke onUserLeaving before onPause only if the launching
3293 // activity did not explicitly state that this is an automated launch.
3294 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3295 if (DEBUG_USER_LEAVING) Log.v(TAG,
3296 "startActivity() => mUserLeaving=" + mUserLeaving);
3297
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003298 // If the caller has asked not to resume at this point, we make note
3299 // of this in the record so that we can skip it when trying to find
3300 // the top running activity.
3301 if (!doResume) {
3302 r.delayedResume = true;
3303 }
3304
3305 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3306 != 0 ? r : null;
3307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003308 // If the onlyIfNeeded flag is set, then we can do this if the activity
3309 // being launched is the same as the one making the call... or, as
3310 // a special case, if we do not know the caller then we count the
3311 // current top activity as the caller.
3312 if (onlyIfNeeded) {
3313 HistoryRecord checkedCaller = sourceRecord;
3314 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003315 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003316 }
3317 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3318 // Caller is not the same as launcher, so always needed.
3319 onlyIfNeeded = false;
3320 }
3321 }
3322
3323 if (grantedUriPermissions != null && callingUid > 0) {
3324 for (int i=0; i<grantedUriPermissions.length; i++) {
3325 grantUriPermissionLocked(callingUid, r.packageName,
3326 grantedUriPermissions[i], grantedMode, r);
3327 }
3328 }
3329
3330 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3331 intent, r);
3332
3333 if (sourceRecord == null) {
3334 // This activity is not being started from another... in this
3335 // case we -always- start a new task.
3336 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3337 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3338 + intent);
3339 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3340 }
3341 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3342 // The original activity who is starting us is running as a single
3343 // instance... this new activity it is starting must go on its
3344 // own task.
3345 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3346 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3347 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3348 // The activity being started is a single instance... it always
3349 // gets launched into its own task.
3350 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3351 }
3352
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003353 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003354 // For whatever reason this activity is being launched into a new
3355 // task... yet the caller has requested a result back. Well, that
3356 // is pretty messed up, so instead immediately send back a cancel
3357 // and let the new task continue launched as normal without a
3358 // dependency on its originator.
3359 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3360 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003361 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 Activity.RESULT_CANCELED, null);
3363 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 }
3365
3366 boolean addingToTask = false;
3367 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3368 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3369 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3370 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3371 // If bring to front is requested, and no result is requested, and
3372 // we can find a task that was started with this same
3373 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003374 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003375 // See if there is a task to bring to the front. If this is
3376 // a SINGLE_INSTANCE activity, there can be one and only one
3377 // instance of it in the history, and it is always in its own
3378 // unique task, so we do a special search.
3379 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3380 ? findTaskLocked(intent, r.info)
3381 : findActivityLocked(intent, r.info);
3382 if (taskTop != null) {
3383 if (taskTop.task.intent == null) {
3384 // This task was started because of movement of
3385 // the activity based on affinity... now that we
3386 // are actually launching it, we can assign the
3387 // base intent.
3388 taskTop.task.setIntent(intent, r.info);
3389 }
3390 // If the target task is not in the front, then we need
3391 // to bring it to the front... except... well, with
3392 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3393 // to have the same behavior as if a new instance was
3394 // being started, which means not bringing it to the front
3395 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003396 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003397 if (curTop.task != taskTop.task) {
3398 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3399 boolean callerAtFront = sourceRecord == null
3400 || curTop.task == sourceRecord.task;
3401 if (callerAtFront) {
3402 // We really do want to push this one into the
3403 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003404 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003405 }
3406 }
3407 // If the caller has requested that the target task be
3408 // reset, then do so.
3409 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3410 taskTop = resetTaskIfNeededLocked(taskTop, r);
3411 }
3412 if (onlyIfNeeded) {
3413 // We don't need to start a new activity, and
3414 // the client said not to do anything if that
3415 // is the case, so this is it! And for paranoia, make
3416 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003417 if (doResume) {
3418 resumeTopActivityLocked(null);
3419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003420 return START_RETURN_INTENT_TO_CALLER;
3421 }
3422 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3423 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3424 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3425 // In this situation we want to remove all activities
3426 // from the task up to the one being started. In most
3427 // cases this means we are resetting the task to its
3428 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003429 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003430 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431 if (top != null) {
3432 if (top.frontOfTask) {
3433 // Activity aliases may mean we use different
3434 // intents for the top activity, so make sure
3435 // the task now has the identity of the new
3436 // intent.
3437 top.task.setIntent(r.intent, r.info);
3438 }
3439 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3440 deliverNewIntentLocked(top, r.intent);
3441 } else {
3442 // A special case: we need to
3443 // start the activity because it is not currently
3444 // running, and the caller has asked to clear the
3445 // current task to have this activity at the top.
3446 addingToTask = true;
3447 // Now pretend like this activity is being started
3448 // by the top of its task, so it is put in the
3449 // right place.
3450 sourceRecord = taskTop;
3451 }
3452 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3453 // In this case the top activity on the task is the
3454 // same as the one being launched, so we take that
3455 // as a request to bring the task to the foreground.
3456 // If the top activity in the task is the root
3457 // activity, deliver this new intent to it if it
3458 // desires.
3459 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3460 && taskTop.realActivity.equals(r.realActivity)) {
3461 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3462 if (taskTop.frontOfTask) {
3463 taskTop.task.setIntent(r.intent, r.info);
3464 }
3465 deliverNewIntentLocked(taskTop, r.intent);
3466 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3467 // In this case we are launching the root activity
3468 // of the task, but with a different intent. We
3469 // should start a new instance on top.
3470 addingToTask = true;
3471 sourceRecord = taskTop;
3472 }
3473 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3474 // In this case an activity is being launched in to an
3475 // existing task, without resetting that task. This
3476 // is typically the situation of launching an activity
3477 // from a notification or shortcut. We want to place
3478 // the new activity on top of the current task.
3479 addingToTask = true;
3480 sourceRecord = taskTop;
3481 } else if (!taskTop.task.rootWasReset) {
3482 // In this case we are launching in to an existing task
3483 // that has not yet been started from its front door.
3484 // The current task has been brought to the front.
3485 // Ideally, we'd probably like to place this new task
3486 // at the bottom of its stack, but that's a little hard
3487 // to do with the current organization of the code so
3488 // for now we'll just drop it.
3489 taskTop.task.setIntent(r.intent, r.info);
3490 }
3491 if (!addingToTask) {
3492 // We didn't do anything... but it was needed (a.k.a., client
3493 // don't use that intent!) And for paranoia, make
3494 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003495 if (doResume) {
3496 resumeTopActivityLocked(null);
3497 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498 return START_TASK_TO_FRONT;
3499 }
3500 }
3501 }
3502 }
3503
3504 //String uri = r.intent.toURI();
3505 //Intent intent2 = new Intent(uri);
3506 //Log.i(TAG, "Given intent: " + r.intent);
3507 //Log.i(TAG, "URI is: " + uri);
3508 //Log.i(TAG, "To intent: " + intent2);
3509
3510 if (r.packageName != null) {
3511 // If the activity being launched is the same as the one currently
3512 // at the top, then we need to check if it should only be launched
3513 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003514 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3515 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 if (top.realActivity.equals(r.realActivity)) {
3517 if (top.app != null && top.app.thread != null) {
3518 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3519 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3520 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3521 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3522 // For paranoia, make sure we have correctly
3523 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003524 if (doResume) {
3525 resumeTopActivityLocked(null);
3526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 if (onlyIfNeeded) {
3528 // We don't need to start a new activity, and
3529 // the client said not to do anything if that
3530 // is the case, so this is it!
3531 return START_RETURN_INTENT_TO_CALLER;
3532 }
3533 deliverNewIntentLocked(top, r.intent);
3534 return START_DELIVERED_TO_TOP;
3535 }
3536 }
3537 }
3538 }
3539
3540 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003541 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003543 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003544 Activity.RESULT_CANCELED, null);
3545 }
3546 return START_CLASS_NOT_FOUND;
3547 }
3548
3549 boolean newTask = false;
3550
3551 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003552 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003553 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3554 // todo: should do better management of integers.
3555 mCurTask++;
3556 if (mCurTask <= 0) {
3557 mCurTask = 1;
3558 }
3559 r.task = new TaskRecord(mCurTask, r.info, intent,
3560 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3561 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3562 + " in new task " + r.task);
3563 newTask = true;
3564 addRecentTask(r.task);
3565
3566 } else if (sourceRecord != null) {
3567 if (!addingToTask &&
3568 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3569 // In this case, we are adding the activity to an existing
3570 // task, but the caller has asked to clear that task if the
3571 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003572 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003573 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003574 if (top != null) {
3575 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3576 deliverNewIntentLocked(top, r.intent);
3577 // For paranoia, make sure we have correctly
3578 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003579 if (doResume) {
3580 resumeTopActivityLocked(null);
3581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003582 return START_DELIVERED_TO_TOP;
3583 }
3584 } else if (!addingToTask &&
3585 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3586 // In this case, we are launching an activity in our own task
3587 // that may already be running somewhere in the history, and
3588 // we want to shuffle it to the front of the stack if so.
3589 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3590 if (where >= 0) {
3591 HistoryRecord top = moveActivityToFrontLocked(where);
3592 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3593 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003594 if (doResume) {
3595 resumeTopActivityLocked(null);
3596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 return START_DELIVERED_TO_TOP;
3598 }
3599 }
3600 // An existing activity is starting this new activity, so we want
3601 // to keep the new one in the same task as the one that is starting
3602 // it.
3603 r.task = sourceRecord.task;
3604 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3605 + " in existing task " + r.task);
3606
3607 } else {
3608 // This not being started from an existing activity, and not part
3609 // of a new task... just put it in the top task, though these days
3610 // this case should never happen.
3611 final int N = mHistory.size();
3612 HistoryRecord prev =
3613 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3614 r.task = prev != null
3615 ? prev.task
3616 : new TaskRecord(mCurTask, r.info, intent,
3617 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3618 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3619 + " in new guessed " + r.task);
3620 }
3621 if (newTask) {
3622 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3623 }
3624 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003625 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003626 return START_SUCCESS;
3627 }
3628
3629 public final int startActivity(IApplicationThread caller,
3630 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3631 int grantedMode, IBinder resultTo,
3632 String resultWho, int requestCode, boolean onlyIfNeeded,
3633 boolean debug) {
3634 // Refuse possible leaked file descriptors
3635 if (intent != null && intent.hasFileDescriptors()) {
3636 throw new IllegalArgumentException("File descriptors passed in Intent");
3637 }
3638
The Android Open Source Project4df24232009-03-05 14:34:35 -08003639 final boolean componentSpecified = intent.getComponent() != null;
3640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003641 // Don't modify the client's object!
3642 intent = new Intent(intent);
3643
3644 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003645 ActivityInfo aInfo;
3646 try {
3647 ResolveInfo rInfo =
3648 ActivityThread.getPackageManager().resolveIntent(
3649 intent, resolvedType,
3650 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003651 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003652 aInfo = rInfo != null ? rInfo.activityInfo : null;
3653 } catch (RemoteException e) {
3654 aInfo = null;
3655 }
3656
3657 if (aInfo != null) {
3658 // Store the found target back into the intent, because now that
3659 // we have it we never want to do this again. For example, if the
3660 // user navigates back to this point in the history, we should
3661 // always restart the exact same activity.
3662 intent.setComponent(new ComponentName(
3663 aInfo.applicationInfo.packageName, aInfo.name));
3664
3665 // Don't debug things in the system process
3666 if (debug) {
3667 if (!aInfo.processName.equals("system")) {
3668 setDebugApp(aInfo.processName, true, false);
3669 }
3670 }
3671 }
3672
3673 synchronized(this) {
3674 final long origId = Binder.clearCallingIdentity();
3675 int res = startActivityLocked(caller, intent, resolvedType,
3676 grantedUriPermissions, grantedMode, aInfo,
3677 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003678 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003679 Binder.restoreCallingIdentity(origId);
3680 return res;
3681 }
3682 }
3683
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003684 public int startActivityIntentSender(IApplicationThread caller,
3685 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003686 IBinder resultTo, String resultWho, int requestCode,
3687 int flagsMask, int flagsValues) {
3688 // Refuse possible leaked file descriptors
3689 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3690 throw new IllegalArgumentException("File descriptors passed in Intent");
3691 }
3692
3693 IIntentSender sender = intent.getTarget();
3694 if (!(sender instanceof PendingIntentRecord)) {
3695 throw new IllegalArgumentException("Bad PendingIntent object");
3696 }
3697
3698 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003699
3700 synchronized (this) {
3701 // If this is coming from the currently resumed activity, it is
3702 // effectively saying that app switches are allowed at this point.
3703 if (mResumedActivity != null
3704 && mResumedActivity.info.applicationInfo.uid ==
3705 Binder.getCallingUid()) {
3706 mAppSwitchesAllowedTime = 0;
3707 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003708 }
3709
3710 return pir.sendInner(0, fillInIntent, resolvedType,
3711 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3712 }
3713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003714 public boolean startNextMatchingActivity(IBinder callingActivity,
3715 Intent intent) {
3716 // Refuse possible leaked file descriptors
3717 if (intent != null && intent.hasFileDescriptors() == true) {
3718 throw new IllegalArgumentException("File descriptors passed in Intent");
3719 }
3720
3721 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003722 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 if (index < 0) {
3724 return false;
3725 }
3726 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3727 if (r.app == null || r.app.thread == null) {
3728 // The caller is not running... d'oh!
3729 return false;
3730 }
3731 intent = new Intent(intent);
3732 // The caller is not allowed to change the data.
3733 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3734 // And we are resetting to find the next component...
3735 intent.setComponent(null);
3736
3737 ActivityInfo aInfo = null;
3738 try {
3739 List<ResolveInfo> resolves =
3740 ActivityThread.getPackageManager().queryIntentActivities(
3741 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003742 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003743
3744 // Look for the original activity in the list...
3745 final int N = resolves != null ? resolves.size() : 0;
3746 for (int i=0; i<N; i++) {
3747 ResolveInfo rInfo = resolves.get(i);
3748 if (rInfo.activityInfo.packageName.equals(r.packageName)
3749 && rInfo.activityInfo.name.equals(r.info.name)) {
3750 // We found the current one... the next matching is
3751 // after it.
3752 i++;
3753 if (i<N) {
3754 aInfo = resolves.get(i).activityInfo;
3755 }
3756 break;
3757 }
3758 }
3759 } catch (RemoteException e) {
3760 }
3761
3762 if (aInfo == null) {
3763 // Nobody who is next!
3764 return false;
3765 }
3766
3767 intent.setComponent(new ComponentName(
3768 aInfo.applicationInfo.packageName, aInfo.name));
3769 intent.setFlags(intent.getFlags()&~(
3770 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3771 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3772 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3773 Intent.FLAG_ACTIVITY_NEW_TASK));
3774
3775 // Okay now we need to start the new activity, replacing the
3776 // currently running activity. This is a little tricky because
3777 // we want to start the new one as if the current one is finished,
3778 // but not finish the current one first so that there is no flicker.
3779 // And thus...
3780 final boolean wasFinishing = r.finishing;
3781 r.finishing = true;
3782
3783 // Propagate reply information over to the new activity.
3784 final HistoryRecord resultTo = r.resultTo;
3785 final String resultWho = r.resultWho;
3786 final int requestCode = r.requestCode;
3787 r.resultTo = null;
3788 if (resultTo != null) {
3789 resultTo.removeResultsLocked(r, resultWho, requestCode);
3790 }
3791
3792 final long origId = Binder.clearCallingIdentity();
3793 // XXX we are not dealing with propagating grantedUriPermissions...
3794 // those are not yet exposed to user code, so there is no need.
3795 int res = startActivityLocked(r.app.thread, intent,
3796 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003797 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798 Binder.restoreCallingIdentity(origId);
3799
3800 r.finishing = wasFinishing;
3801 if (res != START_SUCCESS) {
3802 return false;
3803 }
3804 return true;
3805 }
3806 }
3807
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003808 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003809 Intent intent, String resolvedType, IBinder resultTo,
3810 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003811
3812 // This is so super not safe, that only the system (or okay root)
3813 // can do it.
3814 final int callingUid = Binder.getCallingUid();
3815 if (callingUid != 0 && callingUid != Process.myUid()) {
3816 throw new SecurityException(
3817 "startActivityInPackage only available to the system");
3818 }
3819
The Android Open Source Project4df24232009-03-05 14:34:35 -08003820 final boolean componentSpecified = intent.getComponent() != null;
3821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822 // Don't modify the client's object!
3823 intent = new Intent(intent);
3824
3825 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003826 ActivityInfo aInfo;
3827 try {
3828 ResolveInfo rInfo =
3829 ActivityThread.getPackageManager().resolveIntent(
3830 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003831 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003832 aInfo = rInfo != null ? rInfo.activityInfo : null;
3833 } catch (RemoteException e) {
3834 aInfo = null;
3835 }
3836
3837 if (aInfo != null) {
3838 // Store the found target back into the intent, because now that
3839 // we have it we never want to do this again. For example, if the
3840 // user navigates back to this point in the history, we should
3841 // always restart the exact same activity.
3842 intent.setComponent(new ComponentName(
3843 aInfo.applicationInfo.packageName, aInfo.name));
3844 }
3845
3846 synchronized(this) {
3847 return startActivityLocked(null, intent, resolvedType,
3848 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003849 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003850 }
3851 }
3852
3853 private final void addRecentTask(TaskRecord task) {
3854 // Remove any existing entries that are the same kind of task.
3855 int N = mRecentTasks.size();
3856 for (int i=0; i<N; i++) {
3857 TaskRecord tr = mRecentTasks.get(i);
3858 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3859 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3860 mRecentTasks.remove(i);
3861 i--;
3862 N--;
3863 if (task.intent == null) {
3864 // If the new recent task we are adding is not fully
3865 // specified, then replace it with the existing recent task.
3866 task = tr;
3867 }
3868 }
3869 }
3870 if (N >= MAX_RECENT_TASKS) {
3871 mRecentTasks.remove(N-1);
3872 }
3873 mRecentTasks.add(0, task);
3874 }
3875
3876 public void setRequestedOrientation(IBinder token,
3877 int requestedOrientation) {
3878 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003879 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003880 if (index < 0) {
3881 return;
3882 }
3883 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3884 final long origId = Binder.clearCallingIdentity();
3885 mWindowManager.setAppOrientation(r, requestedOrientation);
3886 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003887 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003888 r.mayFreezeScreenLocked(r.app) ? r : null);
3889 if (config != null) {
3890 r.frozenBeforeDestroy = true;
3891 if (!updateConfigurationLocked(config, r)) {
3892 resumeTopActivityLocked(null);
3893 }
3894 }
3895 Binder.restoreCallingIdentity(origId);
3896 }
3897 }
3898
3899 public int getRequestedOrientation(IBinder token) {
3900 synchronized (this) {
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 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3904 }
3905 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3906 return mWindowManager.getAppOrientation(r);
3907 }
3908 }
3909
3910 private final void stopActivityLocked(HistoryRecord r) {
3911 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3912 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3913 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3914 if (!r.finishing) {
3915 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3916 "no-history");
3917 }
3918 } else if (r.app != null && r.app.thread != null) {
3919 if (mFocusedActivity == r) {
3920 setFocusedActivityLocked(topRunningActivityLocked(null));
3921 }
3922 r.resumeKeyDispatchingLocked();
3923 try {
3924 r.stopped = false;
3925 r.state = ActivityState.STOPPING;
3926 if (DEBUG_VISBILITY) Log.v(
3927 TAG, "Stopping visible=" + r.visible + " for " + r);
3928 if (!r.visible) {
3929 mWindowManager.setAppVisibility(r, false);
3930 }
3931 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3932 } catch (Exception e) {
3933 // Maybe just ignore exceptions here... if the process
3934 // has crashed, our death notification will clean things
3935 // up.
3936 Log.w(TAG, "Exception thrown during pause", e);
3937 // Just in case, assume it to be stopped.
3938 r.stopped = true;
3939 r.state = ActivityState.STOPPED;
3940 if (r.configDestroy) {
3941 destroyActivityLocked(r, true);
3942 }
3943 }
3944 }
3945 }
3946
3947 /**
3948 * @return Returns true if the activity is being finished, false if for
3949 * some reason it is being left as-is.
3950 */
3951 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3952 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003953 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003954 TAG, "Finishing activity: token=" + token
3955 + ", result=" + resultCode + ", data=" + resultData);
3956
Dianne Hackborn75b03852009-06-12 15:43:26 -07003957 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003958 if (index < 0) {
3959 return false;
3960 }
3961 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3962
3963 // Is this the last activity left?
3964 boolean lastActivity = true;
3965 for (int i=mHistory.size()-1; i>=0; i--) {
3966 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3967 if (!p.finishing && p != r) {
3968 lastActivity = false;
3969 break;
3970 }
3971 }
3972
3973 // If this is the last activity, but it is the home activity, then
3974 // just don't finish it.
3975 if (lastActivity) {
3976 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3977 return false;
3978 }
3979 }
3980
3981 finishActivityLocked(r, index, resultCode, resultData, reason);
3982 return true;
3983 }
3984
3985 /**
3986 * @return Returns true if this activity has been removed from the history
3987 * list, or false if it is still in the list and will be removed later.
3988 */
3989 private final boolean finishActivityLocked(HistoryRecord r, int index,
3990 int resultCode, Intent resultData, String reason) {
3991 if (r.finishing) {
3992 Log.w(TAG, "Duplicate finish request for " + r);
3993 return false;
3994 }
3995
3996 r.finishing = true;
3997 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3998 System.identityHashCode(r),
3999 r.task.taskId, r.shortComponentName, reason);
4000 r.task.numActivities--;
4001 if (r.frontOfTask && index < (mHistory.size()-1)) {
4002 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
4003 if (next.task == r.task) {
4004 next.frontOfTask = true;
4005 }
4006 }
4007
4008 r.pauseKeyDispatchingLocked();
4009 if (mFocusedActivity == r) {
4010 setFocusedActivityLocked(topRunningActivityLocked(null));
4011 }
4012
4013 // send the result
4014 HistoryRecord resultTo = r.resultTo;
4015 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07004016 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
4017 + " who=" + r.resultWho + " req=" + r.requestCode
4018 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004019 if (r.info.applicationInfo.uid > 0) {
4020 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
4021 r.packageName, resultData, r);
4022 }
4023 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
4024 resultData);
4025 r.resultTo = null;
4026 }
Chris Tate8a7dc172009-03-24 20:11:42 -07004027 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004028
4029 // Make sure this HistoryRecord is not holding on to other resources,
4030 // because clients have remote IPC references to this object so we
4031 // can't assume that will go away and want to avoid circular IPC refs.
4032 r.results = null;
4033 r.pendingResults = null;
4034 r.newIntents = null;
4035 r.icicle = null;
4036
4037 if (mPendingThumbnails.size() > 0) {
4038 // There are clients waiting to receive thumbnails so, in case
4039 // this is an activity that someone is waiting for, add it
4040 // to the pending list so we can correctly update the clients.
4041 mCancelledThumbnails.add(r);
4042 }
4043
4044 if (mResumedActivity == r) {
4045 boolean endTask = index <= 0
4046 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4047 if (DEBUG_TRANSITION) Log.v(TAG,
4048 "Prepare close transition: finishing " + r);
4049 mWindowManager.prepareAppTransition(endTask
4050 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4051 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4052
4053 // Tell window manager to prepare for this one to be removed.
4054 mWindowManager.setAppVisibility(r, false);
4055
4056 if (mPausingActivity == null) {
4057 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4058 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4059 startPausingLocked(false, false);
4060 }
4061
4062 } else if (r.state != ActivityState.PAUSING) {
4063 // If the activity is PAUSING, we will complete the finish once
4064 // it is done pausing; else we can just directly finish it here.
4065 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4066 return finishCurrentActivityLocked(r, index,
4067 FINISH_AFTER_PAUSE) == null;
4068 } else {
4069 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4070 }
4071
4072 return false;
4073 }
4074
4075 private static final int FINISH_IMMEDIATELY = 0;
4076 private static final int FINISH_AFTER_PAUSE = 1;
4077 private static final int FINISH_AFTER_VISIBLE = 2;
4078
4079 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4080 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004081 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004082 if (index < 0) {
4083 return null;
4084 }
4085
4086 return finishCurrentActivityLocked(r, index, mode);
4087 }
4088
4089 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4090 int index, int mode) {
4091 // First things first: if this activity is currently visible,
4092 // and the resumed activity is not yet visible, then hold off on
4093 // finishing until the resumed one becomes visible.
4094 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4095 if (!mStoppingActivities.contains(r)) {
4096 mStoppingActivities.add(r);
4097 if (mStoppingActivities.size() > 3) {
4098 // If we already have a few activities waiting to stop,
4099 // then give up on things going idle and start clearing
4100 // them out.
4101 Message msg = Message.obtain();
4102 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4103 mHandler.sendMessage(msg);
4104 }
4105 }
4106 r.state = ActivityState.STOPPING;
4107 updateOomAdjLocked();
4108 return r;
4109 }
4110
4111 // make sure the record is cleaned out of other places.
4112 mStoppingActivities.remove(r);
4113 mWaitingVisibleActivities.remove(r);
4114 if (mResumedActivity == r) {
4115 mResumedActivity = null;
4116 }
4117 final ActivityState prevState = r.state;
4118 r.state = ActivityState.FINISHING;
4119
4120 if (mode == FINISH_IMMEDIATELY
4121 || prevState == ActivityState.STOPPED
4122 || prevState == ActivityState.INITIALIZING) {
4123 // If this activity is already stopped, we can just finish
4124 // it right now.
4125 return destroyActivityLocked(r, true) ? null : r;
4126 } else {
4127 // Need to go through the full pause cycle to get this
4128 // activity into the stopped state and then finish it.
4129 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4130 mFinishingActivities.add(r);
4131 resumeTopActivityLocked(null);
4132 }
4133 return r;
4134 }
4135
4136 /**
4137 * This is the internal entry point for handling Activity.finish().
4138 *
4139 * @param token The Binder token referencing the Activity we want to finish.
4140 * @param resultCode Result code, if any, from this Activity.
4141 * @param resultData Result data (Intent), if any, from this Activity.
4142 *
4143 * @result Returns true if the activity successfully finished, or false if it is still running.
4144 */
4145 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4146 // Refuse possible leaked file descriptors
4147 if (resultData != null && resultData.hasFileDescriptors() == true) {
4148 throw new IllegalArgumentException("File descriptors passed in Intent");
4149 }
4150
4151 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004152 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004153 // Find the first activity that is not finishing.
4154 HistoryRecord next = topRunningActivityLocked(token, 0);
4155 if (next != null) {
4156 // ask watcher if this is allowed
4157 boolean resumeOK = true;
4158 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004159 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004160 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004161 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004162 }
4163
4164 if (!resumeOK) {
4165 return false;
4166 }
4167 }
4168 }
4169 final long origId = Binder.clearCallingIdentity();
4170 boolean res = requestFinishActivityLocked(token, resultCode,
4171 resultData, "app-request");
4172 Binder.restoreCallingIdentity(origId);
4173 return res;
4174 }
4175 }
4176
4177 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4178 String resultWho, int requestCode, int resultCode, Intent data) {
4179
4180 if (callingUid > 0) {
4181 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4182 data, r);
4183 }
4184
The Android Open Source Project10592532009-03-18 17:39:46 -07004185 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4186 + " : who=" + resultWho + " req=" + requestCode
4187 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004188 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4189 try {
4190 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4191 list.add(new ResultInfo(resultWho, requestCode,
4192 resultCode, data));
4193 r.app.thread.scheduleSendResult(r, list);
4194 return;
4195 } catch (Exception e) {
4196 Log.w(TAG, "Exception thrown sending result to " + r, e);
4197 }
4198 }
4199
4200 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4201 }
4202
4203 public final void finishSubActivity(IBinder token, String resultWho,
4204 int requestCode) {
4205 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004206 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004207 if (index < 0) {
4208 return;
4209 }
4210 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4211
4212 final long origId = Binder.clearCallingIdentity();
4213
4214 int i;
4215 for (i=mHistory.size()-1; i>=0; i--) {
4216 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4217 if (r.resultTo == self && r.requestCode == requestCode) {
4218 if ((r.resultWho == null && resultWho == null) ||
4219 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4220 finishActivityLocked(r, i,
4221 Activity.RESULT_CANCELED, null, "request-sub");
4222 }
4223 }
4224 }
4225
4226 Binder.restoreCallingIdentity(origId);
4227 }
4228 }
4229
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004230 public void overridePendingTransition(IBinder token, String packageName,
4231 int enterAnim, int exitAnim) {
4232 synchronized(this) {
4233 int index = indexOfTokenLocked(token);
4234 if (index < 0) {
4235 return;
4236 }
4237 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4238
4239 final long origId = Binder.clearCallingIdentity();
4240
4241 if (self.state == ActivityState.RESUMED
4242 || self.state == ActivityState.PAUSING) {
4243 mWindowManager.overridePendingAppTransition(packageName,
4244 enterAnim, exitAnim);
4245 }
4246
4247 Binder.restoreCallingIdentity(origId);
4248 }
4249 }
4250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004251 /**
4252 * Perform clean-up of service connections in an activity record.
4253 */
4254 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4255 // Throw away any services that have been bound by this activity.
4256 if (r.connections != null) {
4257 Iterator<ConnectionRecord> it = r.connections.iterator();
4258 while (it.hasNext()) {
4259 ConnectionRecord c = it.next();
4260 removeConnectionLocked(c, null, r);
4261 }
4262 r.connections = null;
4263 }
4264 }
4265
4266 /**
4267 * Perform the common clean-up of an activity record. This is called both
4268 * as part of destroyActivityLocked() (when destroying the client-side
4269 * representation) and cleaning things up as a result of its hosting
4270 * processing going away, in which case there is no remaining client-side
4271 * state to destroy so only the cleanup here is needed.
4272 */
4273 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4274 if (mResumedActivity == r) {
4275 mResumedActivity = null;
4276 }
4277 if (mFocusedActivity == r) {
4278 mFocusedActivity = null;
4279 }
4280
4281 r.configDestroy = false;
4282 r.frozenBeforeDestroy = false;
4283
4284 // Make sure this record is no longer in the pending finishes list.
4285 // This could happen, for example, if we are trimming activities
4286 // down to the max limit while they are still waiting to finish.
4287 mFinishingActivities.remove(r);
4288 mWaitingVisibleActivities.remove(r);
4289
4290 // Remove any pending results.
4291 if (r.finishing && r.pendingResults != null) {
4292 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4293 PendingIntentRecord rec = apr.get();
4294 if (rec != null) {
4295 cancelIntentSenderLocked(rec, false);
4296 }
4297 }
4298 r.pendingResults = null;
4299 }
4300
4301 if (cleanServices) {
4302 cleanUpActivityServicesLocked(r);
4303 }
4304
4305 if (mPendingThumbnails.size() > 0) {
4306 // There are clients waiting to receive thumbnails so, in case
4307 // this is an activity that someone is waiting for, add it
4308 // to the pending list so we can correctly update the clients.
4309 mCancelledThumbnails.add(r);
4310 }
4311
4312 // Get rid of any pending idle timeouts.
4313 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4314 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4315 }
4316
4317 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4318 if (r.state != ActivityState.DESTROYED) {
4319 mHistory.remove(r);
4320 r.inHistory = false;
4321 r.state = ActivityState.DESTROYED;
4322 mWindowManager.removeAppToken(r);
4323 if (VALIDATE_TOKENS) {
4324 mWindowManager.validateAppTokens(mHistory);
4325 }
4326 cleanUpActivityServicesLocked(r);
4327 removeActivityUriPermissionsLocked(r);
4328 }
4329 }
4330
4331 /**
4332 * Destroy the current CLIENT SIDE instance of an activity. This may be
4333 * called both when actually finishing an activity, or when performing
4334 * a configuration switch where we destroy the current client-side object
4335 * but then create a new client-side object for this same HistoryRecord.
4336 */
4337 private final boolean destroyActivityLocked(HistoryRecord r,
4338 boolean removeFromApp) {
4339 if (DEBUG_SWITCH) Log.v(
4340 TAG, "Removing activity: token=" + r
4341 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4342 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4343 System.identityHashCode(r),
4344 r.task.taskId, r.shortComponentName);
4345
4346 boolean removedFromHistory = false;
4347
4348 cleanUpActivityLocked(r, false);
4349
4350 if (r.app != null) {
4351 if (removeFromApp) {
4352 int idx = r.app.activities.indexOf(r);
4353 if (idx >= 0) {
4354 r.app.activities.remove(idx);
4355 }
4356 if (r.persistent) {
4357 decPersistentCountLocked(r.app);
4358 }
4359 }
4360
4361 boolean skipDestroy = false;
4362
4363 try {
4364 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4365 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4366 r.configChangeFlags);
4367 } catch (Exception e) {
4368 // We can just ignore exceptions here... if the process
4369 // has crashed, our death notification will clean things
4370 // up.
4371 //Log.w(TAG, "Exception thrown during finish", e);
4372 if (r.finishing) {
4373 removeActivityFromHistoryLocked(r);
4374 removedFromHistory = true;
4375 skipDestroy = true;
4376 }
4377 }
4378
4379 r.app = null;
4380 r.nowVisible = false;
4381
4382 if (r.finishing && !skipDestroy) {
4383 r.state = ActivityState.DESTROYING;
4384 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4385 msg.obj = r;
4386 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4387 } else {
4388 r.state = ActivityState.DESTROYED;
4389 }
4390 } else {
4391 // remove this record from the history.
4392 if (r.finishing) {
4393 removeActivityFromHistoryLocked(r);
4394 removedFromHistory = true;
4395 } else {
4396 r.state = ActivityState.DESTROYED;
4397 }
4398 }
4399
4400 r.configChangeFlags = 0;
4401
4402 if (!mLRUActivities.remove(r)) {
4403 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4404 }
4405
4406 return removedFromHistory;
4407 }
4408
4409 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4410 ProcessRecord app)
4411 {
4412 int i = list.size();
4413 if (localLOGV) Log.v(
4414 TAG, "Removing app " + app + " from list " + list
4415 + " with " + i + " entries");
4416 while (i > 0) {
4417 i--;
4418 HistoryRecord r = (HistoryRecord)list.get(i);
4419 if (localLOGV) Log.v(
4420 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4421 if (r.app == app) {
4422 if (localLOGV) Log.v(TAG, "Removing this entry!");
4423 list.remove(i);
4424 }
4425 }
4426 }
4427
4428 /**
4429 * Main function for removing an existing process from the activity manager
4430 * as a result of that process going away. Clears out all connections
4431 * to the process.
4432 */
4433 private final void handleAppDiedLocked(ProcessRecord app,
4434 boolean restarting) {
4435 cleanUpApplicationRecordLocked(app, restarting, -1);
4436 if (!restarting) {
4437 mLRUProcesses.remove(app);
4438 }
4439
4440 // Just in case...
4441 if (mPausingActivity != null && mPausingActivity.app == app) {
4442 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4443 mPausingActivity = null;
4444 }
4445 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4446 mLastPausedActivity = null;
4447 }
4448
4449 // Remove this application's activities from active lists.
4450 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4451 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4452 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4453 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4454
4455 boolean atTop = true;
4456 boolean hasVisibleActivities = false;
4457
4458 // Clean out the history list.
4459 int i = mHistory.size();
4460 if (localLOGV) Log.v(
4461 TAG, "Removing app " + app + " from history with " + i + " entries");
4462 while (i > 0) {
4463 i--;
4464 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4465 if (localLOGV) Log.v(
4466 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4467 if (r.app == app) {
4468 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4469 if (localLOGV) Log.v(
4470 TAG, "Removing this entry! frozen=" + r.haveState
4471 + " finishing=" + r.finishing);
4472 mHistory.remove(i);
4473
4474 r.inHistory = false;
4475 mWindowManager.removeAppToken(r);
4476 if (VALIDATE_TOKENS) {
4477 mWindowManager.validateAppTokens(mHistory);
4478 }
4479 removeActivityUriPermissionsLocked(r);
4480
4481 } else {
4482 // We have the current state for this activity, so
4483 // it can be restarted later when needed.
4484 if (localLOGV) Log.v(
4485 TAG, "Keeping entry, setting app to null");
4486 if (r.visible) {
4487 hasVisibleActivities = true;
4488 }
4489 r.app = null;
4490 r.nowVisible = false;
4491 if (!r.haveState) {
4492 r.icicle = null;
4493 }
4494 }
4495
4496 cleanUpActivityLocked(r, true);
4497 r.state = ActivityState.STOPPED;
4498 }
4499 atTop = false;
4500 }
4501
4502 app.activities.clear();
4503
4504 if (app.instrumentationClass != null) {
4505 Log.w(TAG, "Crash of app " + app.processName
4506 + " running instrumentation " + app.instrumentationClass);
4507 Bundle info = new Bundle();
4508 info.putString("shortMsg", "Process crashed.");
4509 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4510 }
4511
4512 if (!restarting) {
4513 if (!resumeTopActivityLocked(null)) {
4514 // If there was nothing to resume, and we are not already
4515 // restarting this process, but there is a visible activity that
4516 // is hosted by the process... then make sure all visible
4517 // activities are running, taking care of restarting this
4518 // process.
4519 if (hasVisibleActivities) {
4520 ensureActivitiesVisibleLocked(null, 0);
4521 }
4522 }
4523 }
4524 }
4525
4526 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4527 IBinder threadBinder = thread.asBinder();
4528
4529 // Find the application record.
4530 int count = mLRUProcesses.size();
4531 int i;
4532 for (i=0; i<count; i++) {
4533 ProcessRecord rec = mLRUProcesses.get(i);
4534 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4535 return i;
4536 }
4537 }
4538 return -1;
4539 }
4540
4541 private final ProcessRecord getRecordForAppLocked(
4542 IApplicationThread thread) {
4543 if (thread == null) {
4544 return null;
4545 }
4546
4547 int appIndex = getLRURecordIndexForAppLocked(thread);
4548 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4549 }
4550
4551 private final void appDiedLocked(ProcessRecord app, int pid,
4552 IApplicationThread thread) {
4553
4554 mProcDeaths[0]++;
4555
4556 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4557 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4558 + ") has died.");
4559 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4560 if (localLOGV) Log.v(
4561 TAG, "Dying app: " + app + ", pid: " + pid
4562 + ", thread: " + thread.asBinder());
4563 boolean doLowMem = app.instrumentationClass == null;
4564 handleAppDiedLocked(app, false);
4565
4566 if (doLowMem) {
4567 // If there are no longer any background processes running,
4568 // and the app that died was not running instrumentation,
4569 // then tell everyone we are now low on memory.
4570 boolean haveBg = false;
4571 int count = mLRUProcesses.size();
4572 int i;
4573 for (i=0; i<count; i++) {
4574 ProcessRecord rec = mLRUProcesses.get(i);
4575 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4576 haveBg = true;
4577 break;
4578 }
4579 }
4580
4581 if (!haveBg) {
4582 Log.i(TAG, "Low Memory: No more background processes.");
4583 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004584 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004585 for (i=0; i<count; i++) {
4586 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004587 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004588 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4589 // The low memory report is overriding any current
4590 // state for a GC request. Make sure to do
4591 // visible/foreground processes first.
4592 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4593 rec.lastRequestedGc = 0;
4594 } else {
4595 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004596 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004597 rec.reportLowMemory = true;
4598 rec.lastLowMemory = now;
4599 mProcessesToGc.remove(rec);
4600 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004601 }
4602 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004603 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004604 }
4605 }
4606 } else if (Config.LOGD) {
4607 Log.d(TAG, "Received spurious death notification for thread "
4608 + thread.asBinder());
4609 }
4610 }
4611
4612 final String readFile(String filename) {
4613 try {
4614 FileInputStream fs = new FileInputStream(filename);
4615 byte[] inp = new byte[8192];
4616 int size = fs.read(inp);
4617 fs.close();
4618 return new String(inp, 0, 0, size);
4619 } catch (java.io.IOException e) {
4620 }
4621 return "";
4622 }
4623
4624 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004625 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004626 if (app.notResponding || app.crashing) {
4627 return;
4628 }
4629
4630 // Log the ANR to the event log.
4631 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4632
4633 // If we are on a secure build and the application is not interesting to the user (it is
4634 // not visible or in the background), just kill it instead of displaying a dialog.
4635 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4636 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4637 Process.killProcess(app.pid);
4638 return;
4639 }
4640
4641 // DeviceMonitor.start();
4642
4643 String processInfo = null;
4644 if (MONITOR_CPU_USAGE) {
4645 updateCpuStatsNow();
4646 synchronized (mProcessStatsThread) {
4647 processInfo = mProcessStats.printCurrentState();
4648 }
4649 }
4650
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004651 StringBuilder info = mStringBuilder;
4652 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004653 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004654 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004655 if (reportedActivity != null && reportedActivity.app != null) {
4656 info.append(" (last in ");
4657 info.append(reportedActivity.app.processName);
4658 info.append(")");
4659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004660 if (annotation != null) {
4661 info.append("\nAnnotation: ");
4662 info.append(annotation);
4663 }
4664 if (MONITOR_CPU_USAGE) {
4665 info.append("\nCPU usage:\n");
4666 info.append(processInfo);
4667 }
4668 Log.i(TAG, info.toString());
4669
4670 // The application is not responding. Dump as many thread traces as we can.
4671 boolean fileDump = prepareTraceFile(true);
4672 if (!fileDump) {
4673 // Dumping traces to the log, just dump the process that isn't responding so
4674 // we don't overflow the log
4675 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4676 } else {
4677 // Dumping traces to a file so dump all active processes we know about
4678 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004679 // First, these are the most important processes.
4680 final int[] imppids = new int[3];
4681 int i=0;
4682 imppids[0] = app.pid;
4683 i++;
4684 if (reportedActivity != null && reportedActivity.app != null
4685 && reportedActivity.app.thread != null
4686 && reportedActivity.app.pid != app.pid) {
4687 imppids[i] = reportedActivity.app.pid;
4688 i++;
4689 }
4690 imppids[i] = Process.myPid();
4691 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4692 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4693 synchronized (this) {
4694 try {
4695 wait(200);
4696 } catch (InterruptedException e) {
4697 }
4698 }
4699 }
4700 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004701 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004702 boolean done = false;
4703 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4704 if (imppids[j] == r.pid) {
4705 done = true;
4706 break;
4707 }
4708 }
4709 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004710 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004711 synchronized (this) {
4712 try {
4713 wait(200);
4714 } catch (InterruptedException e) {
4715 }
4716 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004717 }
4718 }
4719 }
4720 }
4721
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004722 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004723 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004724 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004725 app.pid, info.toString());
4726 if (res != 0) {
4727 if (res < 0) {
4728 // wait until the SIGQUIT has had a chance to process before killing the
4729 // process.
4730 try {
4731 wait(2000);
4732 } catch (InterruptedException e) {
4733 }
4734
4735 Process.killProcess(app.pid);
4736 return;
4737 }
4738 }
4739 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004740 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004741 }
4742 }
4743
4744 makeAppNotRespondingLocked(app,
4745 activity != null ? activity.shortComponentName : null,
4746 annotation != null ? "ANR " + annotation : "ANR",
4747 info.toString(), null);
4748 Message msg = Message.obtain();
4749 HashMap map = new HashMap();
4750 msg.what = SHOW_NOT_RESPONDING_MSG;
4751 msg.obj = map;
4752 map.put("app", app);
4753 if (activity != null) {
4754 map.put("activity", activity);
4755 }
4756
4757 mHandler.sendMessage(msg);
4758 return;
4759 }
4760
4761 /**
4762 * If a stack trace file has been configured, prepare the filesystem
4763 * by creating the directory if it doesn't exist and optionally
4764 * removing the old trace file.
4765 *
4766 * @param removeExisting If set, the existing trace file will be removed.
4767 * @return Returns true if the trace file preparations succeeded
4768 */
4769 public static boolean prepareTraceFile(boolean removeExisting) {
4770 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4771 boolean fileReady = false;
4772 if (!TextUtils.isEmpty(tracesPath)) {
4773 File f = new File(tracesPath);
4774 if (!f.exists()) {
4775 // Ensure the enclosing directory exists
4776 File dir = f.getParentFile();
4777 if (!dir.exists()) {
4778 fileReady = dir.mkdirs();
4779 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004780 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004781 } else if (dir.isDirectory()) {
4782 fileReady = true;
4783 }
4784 } else if (removeExisting) {
4785 // Remove the previous traces file, so we don't fill the disk.
4786 // The VM will recreate it
4787 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4788 fileReady = f.delete();
4789 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004790
4791 if (removeExisting) {
4792 try {
4793 f.createNewFile();
4794 FileUtils.setPermissions(f.getAbsolutePath(),
4795 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4796 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4797 fileReady = true;
4798 } catch (IOException e) {
4799 Log.w(TAG, "Unable to make ANR traces file", e);
4800 }
4801 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004802 }
4803
4804 return fileReady;
4805 }
4806
4807
4808 private final void decPersistentCountLocked(ProcessRecord app)
4809 {
4810 app.persistentActivities--;
4811 if (app.persistentActivities > 0) {
4812 // Still more of 'em...
4813 return;
4814 }
4815 if (app.persistent) {
4816 // Ah, but the application itself is persistent. Whatever!
4817 return;
4818 }
4819
4820 // App is no longer persistent... make sure it and the ones
4821 // following it in the LRU list have the correc oom_adj.
4822 updateOomAdjLocked();
4823 }
4824
4825 public void setPersistent(IBinder token, boolean isPersistent) {
4826 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4827 != PackageManager.PERMISSION_GRANTED) {
4828 String msg = "Permission Denial: setPersistent() from pid="
4829 + Binder.getCallingPid()
4830 + ", uid=" + Binder.getCallingUid()
4831 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4832 Log.w(TAG, msg);
4833 throw new SecurityException(msg);
4834 }
4835
4836 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004837 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004838 if (index < 0) {
4839 return;
4840 }
4841 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4842 ProcessRecord app = r.app;
4843
4844 if (localLOGV) Log.v(
4845 TAG, "Setting persistence " + isPersistent + ": " + r);
4846
4847 if (isPersistent) {
4848 if (r.persistent) {
4849 // Okay okay, I heard you already!
4850 if (localLOGV) Log.v(TAG, "Already persistent!");
4851 return;
4852 }
4853 r.persistent = true;
4854 app.persistentActivities++;
4855 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4856 if (app.persistentActivities > 1) {
4857 // We aren't the first...
4858 if (localLOGV) Log.v(TAG, "Not the first!");
4859 return;
4860 }
4861 if (app.persistent) {
4862 // This would be redundant.
4863 if (localLOGV) Log.v(TAG, "App is persistent!");
4864 return;
4865 }
4866
4867 // App is now persistent... make sure it and the ones
4868 // following it now have the correct oom_adj.
4869 final long origId = Binder.clearCallingIdentity();
4870 updateOomAdjLocked();
4871 Binder.restoreCallingIdentity(origId);
4872
4873 } else {
4874 if (!r.persistent) {
4875 // Okay okay, I heard you already!
4876 return;
4877 }
4878 r.persistent = false;
4879 final long origId = Binder.clearCallingIdentity();
4880 decPersistentCountLocked(app);
4881 Binder.restoreCallingIdentity(origId);
4882
4883 }
4884 }
4885 }
4886
4887 public boolean clearApplicationUserData(final String packageName,
4888 final IPackageDataObserver observer) {
4889 int uid = Binder.getCallingUid();
4890 int pid = Binder.getCallingPid();
4891 long callingId = Binder.clearCallingIdentity();
4892 try {
4893 IPackageManager pm = ActivityThread.getPackageManager();
4894 int pkgUid = -1;
4895 synchronized(this) {
4896 try {
4897 pkgUid = pm.getPackageUid(packageName);
4898 } catch (RemoteException e) {
4899 }
4900 if (pkgUid == -1) {
4901 Log.w(TAG, "Invalid packageName:" + packageName);
4902 return false;
4903 }
4904 if (uid == pkgUid || checkComponentPermission(
4905 android.Manifest.permission.CLEAR_APP_USER_DATA,
4906 pid, uid, -1)
4907 == PackageManager.PERMISSION_GRANTED) {
4908 restartPackageLocked(packageName, pkgUid);
4909 } else {
4910 throw new SecurityException(pid+" does not have permission:"+
4911 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4912 "for process:"+packageName);
4913 }
4914 }
4915
4916 try {
4917 //clear application user data
4918 pm.clearApplicationUserData(packageName, observer);
4919 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4920 Uri.fromParts("package", packageName, null));
4921 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4922 broadcastIntentLocked(null, null, intent,
4923 null, null, 0, null, null, null,
4924 false, false, MY_PID, Process.SYSTEM_UID);
4925 } catch (RemoteException e) {
4926 }
4927 } finally {
4928 Binder.restoreCallingIdentity(callingId);
4929 }
4930 return true;
4931 }
4932
4933 public void restartPackage(final String packageName) {
4934 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4935 != PackageManager.PERMISSION_GRANTED) {
4936 String msg = "Permission Denial: restartPackage() from pid="
4937 + Binder.getCallingPid()
4938 + ", uid=" + Binder.getCallingUid()
4939 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4940 Log.w(TAG, msg);
4941 throw new SecurityException(msg);
4942 }
4943
4944 long callingId = Binder.clearCallingIdentity();
4945 try {
4946 IPackageManager pm = ActivityThread.getPackageManager();
4947 int pkgUid = -1;
4948 synchronized(this) {
4949 try {
4950 pkgUid = pm.getPackageUid(packageName);
4951 } catch (RemoteException e) {
4952 }
4953 if (pkgUid == -1) {
4954 Log.w(TAG, "Invalid packageName: " + packageName);
4955 return;
4956 }
4957 restartPackageLocked(packageName, pkgUid);
4958 }
4959 } finally {
4960 Binder.restoreCallingIdentity(callingId);
4961 }
4962 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004963
4964 /*
4965 * The pkg name and uid have to be specified.
4966 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4967 */
4968 public void killApplicationWithUid(String pkg, int uid) {
4969 if (pkg == null) {
4970 return;
4971 }
4972 // Make sure the uid is valid.
4973 if (uid < 0) {
4974 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4975 return;
4976 }
4977 int callerUid = Binder.getCallingUid();
4978 // Only the system server can kill an application
4979 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004980 // Post an aysnc message to kill the application
4981 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4982 msg.arg1 = uid;
4983 msg.arg2 = 0;
4984 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004985 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004986 } else {
4987 throw new SecurityException(callerUid + " cannot kill pkg: " +
4988 pkg);
4989 }
4990 }
4991
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004992 public void closeSystemDialogs(String reason) {
4993 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4994 if (reason != null) {
4995 intent.putExtra("reason", reason);
4996 }
4997
4998 final int uid = Binder.getCallingUid();
4999 final long origId = Binder.clearCallingIdentity();
5000 synchronized (this) {
5001 int i = mWatchers.beginBroadcast();
5002 while (i > 0) {
5003 i--;
5004 IActivityWatcher w = mWatchers.getBroadcastItem(i);
5005 if (w != null) {
5006 try {
5007 w.closingSystemDialogs(reason);
5008 } catch (RemoteException e) {
5009 }
5010 }
5011 }
5012 mWatchers.finishBroadcast();
5013
Dianne Hackbornffa42482009-09-23 22:20:11 -07005014 mWindowManager.closeSystemDialogs(reason);
5015
5016 for (i=mHistory.size()-1; i>=0; i--) {
5017 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5018 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
5019 finishActivityLocked(r, i,
5020 Activity.RESULT_CANCELED, null, "close-sys");
5021 }
5022 }
5023
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005024 broadcastIntentLocked(null, null, intent, null,
5025 null, 0, null, null, null, false, false, -1, uid);
5026 }
5027 Binder.restoreCallingIdentity(origId);
5028 }
5029
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005030 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005031 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005032 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5033 for (int i=pids.length-1; i>=0; i--) {
5034 infos[i] = new Debug.MemoryInfo();
5035 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005036 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005037 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005038 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005039
5040 public void killApplicationProcess(String processName, int uid) {
5041 if (processName == null) {
5042 return;
5043 }
5044
5045 int callerUid = Binder.getCallingUid();
5046 // Only the system server can kill an application
5047 if (callerUid == Process.SYSTEM_UID) {
5048 synchronized (this) {
5049 ProcessRecord app = getProcessRecordLocked(processName, uid);
5050 if (app != null) {
5051 try {
5052 app.thread.scheduleSuicide();
5053 } catch (RemoteException e) {
5054 // If the other end already died, then our work here is done.
5055 }
5056 } else {
5057 Log.w(TAG, "Process/uid not found attempting kill of "
5058 + processName + " / " + uid);
5059 }
5060 }
5061 } else {
5062 throw new SecurityException(callerUid + " cannot kill app process: " +
5063 processName);
5064 }
5065 }
5066
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005067 private void restartPackageLocked(final String packageName, int uid) {
5068 uninstallPackageLocked(packageName, uid, false);
5069 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5070 Uri.fromParts("package", packageName, null));
5071 intent.putExtra(Intent.EXTRA_UID, uid);
5072 broadcastIntentLocked(null, null, intent,
5073 null, null, 0, null, null, null,
5074 false, false, MY_PID, Process.SYSTEM_UID);
5075 }
5076
5077 private final void uninstallPackageLocked(String name, int uid,
5078 boolean callerWillRestart) {
5079 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5080
5081 int i, N;
5082
5083 final String procNamePrefix = name + ":";
5084 if (uid < 0) {
5085 try {
5086 uid = ActivityThread.getPackageManager().getPackageUid(name);
5087 } catch (RemoteException e) {
5088 }
5089 }
5090
5091 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5092 while (badApps.hasNext()) {
5093 SparseArray<Long> ba = badApps.next();
5094 if (ba.get(uid) != null) {
5095 badApps.remove();
5096 }
5097 }
5098
5099 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5100
5101 // Remove all processes this package may have touched: all with the
5102 // same UID (except for the system or root user), and all whose name
5103 // matches the package name.
5104 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5105 final int NA = apps.size();
5106 for (int ia=0; ia<NA; ia++) {
5107 ProcessRecord app = apps.valueAt(ia);
5108 if (app.removed) {
5109 procs.add(app);
5110 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5111 || app.processName.equals(name)
5112 || app.processName.startsWith(procNamePrefix)) {
5113 app.removed = true;
5114 procs.add(app);
5115 }
5116 }
5117 }
5118
5119 N = procs.size();
5120 for (i=0; i<N; i++) {
5121 removeProcessLocked(procs.get(i), callerWillRestart);
5122 }
5123
5124 for (i=mHistory.size()-1; i>=0; i--) {
5125 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5126 if (r.packageName.equals(name)) {
5127 if (Config.LOGD) Log.d(
5128 TAG, " Force finishing activity "
5129 + r.intent.getComponent().flattenToShortString());
5130 if (r.app != null) {
5131 r.app.removed = true;
5132 }
5133 r.app = null;
5134 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5135 }
5136 }
5137
5138 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5139 for (ServiceRecord service : mServices.values()) {
5140 if (service.packageName.equals(name)) {
5141 if (service.app != null) {
5142 service.app.removed = true;
5143 }
5144 service.app = null;
5145 services.add(service);
5146 }
5147 }
5148
5149 N = services.size();
5150 for (i=0; i<N; i++) {
5151 bringDownServiceLocked(services.get(i), true);
5152 }
5153
5154 resumeTopActivityLocked(null);
5155 }
5156
5157 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5158 final String name = app.processName;
5159 final int uid = app.info.uid;
5160 if (Config.LOGD) Log.d(
5161 TAG, "Force removing process " + app + " (" + name
5162 + "/" + uid + ")");
5163
5164 mProcessNames.remove(name, uid);
5165 boolean needRestart = false;
5166 if (app.pid > 0 && app.pid != MY_PID) {
5167 int pid = app.pid;
5168 synchronized (mPidsSelfLocked) {
5169 mPidsSelfLocked.remove(pid);
5170 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5171 }
5172 handleAppDiedLocked(app, true);
5173 mLRUProcesses.remove(app);
5174 Process.killProcess(pid);
5175
5176 if (app.persistent) {
5177 if (!callerWillRestart) {
5178 addAppLocked(app.info);
5179 } else {
5180 needRestart = true;
5181 }
5182 }
5183 } else {
5184 mRemovedProcesses.add(app);
5185 }
5186
5187 return needRestart;
5188 }
5189
5190 private final void processStartTimedOutLocked(ProcessRecord app) {
5191 final int pid = app.pid;
5192 boolean gone = false;
5193 synchronized (mPidsSelfLocked) {
5194 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5195 if (knownApp != null && knownApp.thread == null) {
5196 mPidsSelfLocked.remove(pid);
5197 gone = true;
5198 }
5199 }
5200
5201 if (gone) {
5202 Log.w(TAG, "Process " + app + " failed to attach");
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005203 EventLog.writeEvent(LOG_AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
5204 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005205 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005206 // Take care of any launching providers waiting for this process.
5207 checkAppInLaunchingProvidersLocked(app, true);
5208 // Take care of any services that are waiting for the process.
5209 for (int i=0; i<mPendingServices.size(); i++) {
5210 ServiceRecord sr = mPendingServices.get(i);
5211 if (app.info.uid == sr.appInfo.uid
5212 && app.processName.equals(sr.processName)) {
5213 Log.w(TAG, "Forcing bringing down service: " + sr);
5214 mPendingServices.remove(i);
5215 i--;
5216 bringDownServiceLocked(sr, true);
5217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005218 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005219 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005220 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5221 Log.w(TAG, "Unattached app died before backup, skipping");
5222 try {
5223 IBackupManager bm = IBackupManager.Stub.asInterface(
5224 ServiceManager.getService(Context.BACKUP_SERVICE));
5225 bm.agentDisconnected(app.info.packageName);
5226 } catch (RemoteException e) {
5227 // Can't happen; the backup manager is local
5228 }
5229 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005230 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5231 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5232 mPendingBroadcast = null;
5233 scheduleBroadcastsLocked();
5234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005235 } else {
5236 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5237 }
5238 }
5239
5240 private final boolean attachApplicationLocked(IApplicationThread thread,
5241 int pid) {
5242
5243 // Find the application record that is being attached... either via
5244 // the pid if we are running in multiple processes, or just pull the
5245 // next app record if we are emulating process with anonymous threads.
5246 ProcessRecord app;
5247 if (pid != MY_PID && pid >= 0) {
5248 synchronized (mPidsSelfLocked) {
5249 app = mPidsSelfLocked.get(pid);
5250 }
5251 } else if (mStartingProcesses.size() > 0) {
5252 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005253 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005254 } else {
5255 app = null;
5256 }
5257
5258 if (app == null) {
5259 Log.w(TAG, "No pending application record for pid " + pid
5260 + " (IApplicationThread " + thread + "); dropping process");
5261 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5262 if (pid > 0 && pid != MY_PID) {
5263 Process.killProcess(pid);
5264 } else {
5265 try {
5266 thread.scheduleExit();
5267 } catch (Exception e) {
5268 // Ignore exceptions.
5269 }
5270 }
5271 return false;
5272 }
5273
5274 // If this application record is still attached to a previous
5275 // process, clean it up now.
5276 if (app.thread != null) {
5277 handleAppDiedLocked(app, true);
5278 }
5279
5280 // Tell the process all about itself.
5281
5282 if (localLOGV) Log.v(
5283 TAG, "Binding process pid " + pid + " to record " + app);
5284
5285 String processName = app.processName;
5286 try {
5287 thread.asBinder().linkToDeath(new AppDeathRecipient(
5288 app, pid, thread), 0);
5289 } catch (RemoteException e) {
5290 app.resetPackageList();
5291 startProcessLocked(app, "link fail", processName);
5292 return false;
5293 }
5294
5295 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5296
5297 app.thread = thread;
5298 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005299 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005300 app.forcingToForeground = null;
5301 app.foregroundServices = false;
5302 app.debugging = false;
5303
5304 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5305
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005306 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5307 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005308
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005309 if (!normalMode) {
5310 Log.i(TAG, "Launching preboot mode app: " + app);
5311 }
5312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005313 if (localLOGV) Log.v(
5314 TAG, "New app record " + app
5315 + " thread=" + thread.asBinder() + " pid=" + pid);
5316 try {
5317 int testMode = IApplicationThread.DEBUG_OFF;
5318 if (mDebugApp != null && mDebugApp.equals(processName)) {
5319 testMode = mWaitForDebugger
5320 ? IApplicationThread.DEBUG_WAIT
5321 : IApplicationThread.DEBUG_ON;
5322 app.debugging = true;
5323 if (mDebugTransient) {
5324 mDebugApp = mOrigDebugApp;
5325 mWaitForDebugger = mOrigWaitForDebugger;
5326 }
5327 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005328
Christopher Tate181fafa2009-05-14 11:12:14 -07005329 // If the app is being launched for restore or full backup, set it up specially
5330 boolean isRestrictedBackupMode = false;
5331 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5332 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5333 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5334 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005335
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005336 ensurePackageDexOpt(app.instrumentationInfo != null
5337 ? app.instrumentationInfo.packageName
5338 : app.info.packageName);
5339 if (app.instrumentationClass != null) {
5340 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005341 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005342 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5343 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005344 thread.bindApplication(processName, app.instrumentationInfo != null
5345 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005346 app.instrumentationClass, app.instrumentationProfileFile,
5347 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005348 isRestrictedBackupMode || !normalMode,
5349 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005350 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005351 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005352 } catch (Exception e) {
5353 // todo: Yikes! What should we do? For now we will try to
5354 // start another process, but that could easily get us in
5355 // an infinite loop of restarting processes...
5356 Log.w(TAG, "Exception thrown during bind!", e);
5357
5358 app.resetPackageList();
5359 startProcessLocked(app, "bind fail", processName);
5360 return false;
5361 }
5362
5363 // Remove this record from the list of starting applications.
5364 mPersistentStartingProcesses.remove(app);
5365 mProcessesOnHold.remove(app);
5366
5367 boolean badApp = false;
5368 boolean didSomething = false;
5369
5370 // See if the top visible activity is waiting to run in this process...
5371 HistoryRecord hr = topRunningActivityLocked(null);
5372 if (hr != null) {
5373 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5374 && processName.equals(hr.processName)) {
5375 try {
5376 if (realStartActivityLocked(hr, app, true, true)) {
5377 didSomething = true;
5378 }
5379 } catch (Exception e) {
5380 Log.w(TAG, "Exception in new application when starting activity "
5381 + hr.intent.getComponent().flattenToShortString(), e);
5382 badApp = true;
5383 }
5384 } else {
5385 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5386 }
5387 }
5388
5389 // Find any services that should be running in this process...
5390 if (!badApp && mPendingServices.size() > 0) {
5391 ServiceRecord sr = null;
5392 try {
5393 for (int i=0; i<mPendingServices.size(); i++) {
5394 sr = mPendingServices.get(i);
5395 if (app.info.uid != sr.appInfo.uid
5396 || !processName.equals(sr.processName)) {
5397 continue;
5398 }
5399
5400 mPendingServices.remove(i);
5401 i--;
5402 realStartServiceLocked(sr, app);
5403 didSomething = true;
5404 }
5405 } catch (Exception e) {
5406 Log.w(TAG, "Exception in new application when starting service "
5407 + sr.shortName, e);
5408 badApp = true;
5409 }
5410 }
5411
5412 // Check if the next broadcast receiver is in this process...
5413 BroadcastRecord br = mPendingBroadcast;
5414 if (!badApp && br != null && br.curApp == app) {
5415 try {
5416 mPendingBroadcast = null;
5417 processCurBroadcastLocked(br, app);
5418 didSomething = true;
5419 } catch (Exception e) {
5420 Log.w(TAG, "Exception in new application when starting receiver "
5421 + br.curComponent.flattenToShortString(), e);
5422 badApp = true;
5423 logBroadcastReceiverDiscard(br);
5424 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5425 br.resultExtras, br.resultAbort, true);
5426 scheduleBroadcastsLocked();
5427 }
5428 }
5429
Christopher Tate181fafa2009-05-14 11:12:14 -07005430 // Check whether the next backup agent is in this process...
5431 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5432 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005433 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005434 try {
5435 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5436 } catch (Exception e) {
5437 Log.w(TAG, "Exception scheduling backup agent creation: ");
5438 e.printStackTrace();
5439 }
5440 }
5441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005442 if (badApp) {
5443 // todo: Also need to kill application to deal with all
5444 // kinds of exceptions.
5445 handleAppDiedLocked(app, false);
5446 return false;
5447 }
5448
5449 if (!didSomething) {
5450 updateOomAdjLocked();
5451 }
5452
5453 return true;
5454 }
5455
5456 public final void attachApplication(IApplicationThread thread) {
5457 synchronized (this) {
5458 int callingPid = Binder.getCallingPid();
5459 final long origId = Binder.clearCallingIdentity();
5460 attachApplicationLocked(thread, callingPid);
5461 Binder.restoreCallingIdentity(origId);
5462 }
5463 }
5464
Dianne Hackborne88846e2009-09-30 21:34:25 -07005465 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005466 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005467 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005468 Binder.restoreCallingIdentity(origId);
5469 }
5470
5471 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5472 boolean remove) {
5473 int N = mStoppingActivities.size();
5474 if (N <= 0) return null;
5475
5476 ArrayList<HistoryRecord> stops = null;
5477
5478 final boolean nowVisible = mResumedActivity != null
5479 && mResumedActivity.nowVisible
5480 && !mResumedActivity.waitingVisible;
5481 for (int i=0; i<N; i++) {
5482 HistoryRecord s = mStoppingActivities.get(i);
5483 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5484 + nowVisible + " waitingVisible=" + s.waitingVisible
5485 + " finishing=" + s.finishing);
5486 if (s.waitingVisible && nowVisible) {
5487 mWaitingVisibleActivities.remove(s);
5488 s.waitingVisible = false;
5489 if (s.finishing) {
5490 // If this activity is finishing, it is sitting on top of
5491 // everyone else but we now know it is no longer needed...
5492 // so get rid of it. Otherwise, we need to go through the
5493 // normal flow and hide it once we determine that it is
5494 // hidden by the activities in front of it.
5495 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5496 mWindowManager.setAppVisibility(s, false);
5497 }
5498 }
5499 if (!s.waitingVisible && remove) {
5500 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5501 if (stops == null) {
5502 stops = new ArrayList<HistoryRecord>();
5503 }
5504 stops.add(s);
5505 mStoppingActivities.remove(i);
5506 N--;
5507 i--;
5508 }
5509 }
5510
5511 return stops;
5512 }
5513
5514 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005515 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5516 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005517 mWindowManager.enableScreenAfterBoot();
5518 }
5519
Dianne Hackborne88846e2009-09-30 21:34:25 -07005520 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5521 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005522 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5523
5524 ArrayList<HistoryRecord> stops = null;
5525 ArrayList<HistoryRecord> finishes = null;
5526 ArrayList<HistoryRecord> thumbnails = null;
5527 int NS = 0;
5528 int NF = 0;
5529 int NT = 0;
5530 IApplicationThread sendThumbnail = null;
5531 boolean booting = false;
5532 boolean enableScreen = false;
5533
5534 synchronized (this) {
5535 if (token != null) {
5536 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5537 }
5538
5539 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005540 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005541 if (index >= 0) {
5542 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5543
Dianne Hackborne88846e2009-09-30 21:34:25 -07005544 // This is a hack to semi-deal with a race condition
5545 // in the client where it can be constructed with a
5546 // newer configuration from when we asked it to launch.
5547 // We'll update with whatever configuration it now says
5548 // it used to launch.
5549 if (config != null) {
5550 r.configuration = config;
5551 }
5552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005553 // No longer need to keep the device awake.
5554 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5555 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5556 mLaunchingActivity.release();
5557 }
5558
5559 // We are now idle. If someone is waiting for a thumbnail from
5560 // us, we can now deliver.
5561 r.idle = true;
5562 scheduleAppGcsLocked();
5563 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5564 sendThumbnail = r.app.thread;
5565 r.thumbnailNeeded = false;
5566 }
5567
5568 // If this activity is fullscreen, set up to hide those under it.
5569
5570 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5571 ensureActivitiesVisibleLocked(null, 0);
5572
5573 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5574 if (!mBooted && !fromTimeout) {
5575 mBooted = true;
5576 enableScreen = true;
5577 }
5578 }
5579
5580 // Atomically retrieve all of the other things to do.
5581 stops = processStoppingActivitiesLocked(true);
5582 NS = stops != null ? stops.size() : 0;
5583 if ((NF=mFinishingActivities.size()) > 0) {
5584 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5585 mFinishingActivities.clear();
5586 }
5587 if ((NT=mCancelledThumbnails.size()) > 0) {
5588 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5589 mCancelledThumbnails.clear();
5590 }
5591
5592 booting = mBooting;
5593 mBooting = false;
5594 }
5595
5596 int i;
5597
5598 // Send thumbnail if requested.
5599 if (sendThumbnail != null) {
5600 try {
5601 sendThumbnail.requestThumbnail(token);
5602 } catch (Exception e) {
5603 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5604 sendPendingThumbnail(null, token, null, null, true);
5605 }
5606 }
5607
5608 // Stop any activities that are scheduled to do so but have been
5609 // waiting for the next one to start.
5610 for (i=0; i<NS; i++) {
5611 HistoryRecord r = (HistoryRecord)stops.get(i);
5612 synchronized (this) {
5613 if (r.finishing) {
5614 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5615 } else {
5616 stopActivityLocked(r);
5617 }
5618 }
5619 }
5620
5621 // Finish any activities that are scheduled to do so but have been
5622 // waiting for the next one to start.
5623 for (i=0; i<NF; i++) {
5624 HistoryRecord r = (HistoryRecord)finishes.get(i);
5625 synchronized (this) {
5626 destroyActivityLocked(r, true);
5627 }
5628 }
5629
5630 // Report back to any thumbnail receivers.
5631 for (i=0; i<NT; i++) {
5632 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5633 sendPendingThumbnail(r, null, null, null, true);
5634 }
5635
5636 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005637 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005638 }
5639
5640 trimApplications();
5641 //dump();
5642 //mWindowManager.dump();
5643
5644 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005645 enableScreenAfterBoot();
5646 }
5647 }
5648
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005649 final void finishBooting() {
5650 // Ensure that any processes we had put on hold are now started
5651 // up.
5652 final int NP = mProcessesOnHold.size();
5653 if (NP > 0) {
5654 ArrayList<ProcessRecord> procs =
5655 new ArrayList<ProcessRecord>(mProcessesOnHold);
5656 for (int ip=0; ip<NP; ip++) {
5657 this.startProcessLocked(procs.get(ip), "on-hold", null);
5658 }
5659 }
5660 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5661 // Tell anyone interested that we are done booting!
5662 synchronized (this) {
5663 broadcastIntentLocked(null, null,
5664 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5665 null, null, 0, null, null,
5666 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5667 false, false, MY_PID, Process.SYSTEM_UID);
5668 }
5669 }
5670 }
5671
5672 final void ensureBootCompleted() {
5673 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005674 boolean enableScreen;
5675 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005676 booting = mBooting;
5677 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005678 enableScreen = !mBooted;
5679 mBooted = true;
5680 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005681
5682 if (booting) {
5683 finishBooting();
5684 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005685
5686 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005687 enableScreenAfterBoot();
5688 }
5689 }
5690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005691 public final void activityPaused(IBinder token, Bundle icicle) {
5692 // Refuse possible leaked file descriptors
5693 if (icicle != null && icicle.hasFileDescriptors()) {
5694 throw new IllegalArgumentException("File descriptors passed in Bundle");
5695 }
5696
5697 final long origId = Binder.clearCallingIdentity();
5698 activityPaused(token, icicle, false);
5699 Binder.restoreCallingIdentity(origId);
5700 }
5701
5702 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5703 if (DEBUG_PAUSE) Log.v(
5704 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5705 + ", timeout=" + timeout);
5706
5707 HistoryRecord r = null;
5708
5709 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005710 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005711 if (index >= 0) {
5712 r = (HistoryRecord)mHistory.get(index);
5713 if (!timeout) {
5714 r.icicle = icicle;
5715 r.haveState = true;
5716 }
5717 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5718 if (mPausingActivity == r) {
5719 r.state = ActivityState.PAUSED;
5720 completePauseLocked();
5721 } else {
5722 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5723 System.identityHashCode(r), r.shortComponentName,
5724 mPausingActivity != null
5725 ? mPausingActivity.shortComponentName : "(none)");
5726 }
5727 }
5728 }
5729 }
5730
5731 public final void activityStopped(IBinder token, Bitmap thumbnail,
5732 CharSequence description) {
5733 if (localLOGV) Log.v(
5734 TAG, "Activity stopped: token=" + token);
5735
5736 HistoryRecord r = null;
5737
5738 final long origId = Binder.clearCallingIdentity();
5739
5740 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005741 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005742 if (index >= 0) {
5743 r = (HistoryRecord)mHistory.get(index);
5744 r.thumbnail = thumbnail;
5745 r.description = description;
5746 r.stopped = true;
5747 r.state = ActivityState.STOPPED;
5748 if (!r.finishing) {
5749 if (r.configDestroy) {
5750 destroyActivityLocked(r, true);
5751 resumeTopActivityLocked(null);
5752 }
5753 }
5754 }
5755 }
5756
5757 if (r != null) {
5758 sendPendingThumbnail(r, null, null, null, false);
5759 }
5760
5761 trimApplications();
5762
5763 Binder.restoreCallingIdentity(origId);
5764 }
5765
5766 public final void activityDestroyed(IBinder token) {
5767 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5768 synchronized (this) {
5769 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5770
Dianne Hackborn75b03852009-06-12 15:43:26 -07005771 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005772 if (index >= 0) {
5773 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5774 if (r.state == ActivityState.DESTROYING) {
5775 final long origId = Binder.clearCallingIdentity();
5776 removeActivityFromHistoryLocked(r);
5777 Binder.restoreCallingIdentity(origId);
5778 }
5779 }
5780 }
5781 }
5782
5783 public String getCallingPackage(IBinder token) {
5784 synchronized (this) {
5785 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005786 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005787 }
5788 }
5789
5790 public ComponentName getCallingActivity(IBinder token) {
5791 synchronized (this) {
5792 HistoryRecord r = getCallingRecordLocked(token);
5793 return r != null ? r.intent.getComponent() : null;
5794 }
5795 }
5796
5797 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005798 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005799 if (index >= 0) {
5800 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5801 if (r != null) {
5802 return r.resultTo;
5803 }
5804 }
5805 return null;
5806 }
5807
5808 public ComponentName getActivityClassForToken(IBinder token) {
5809 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005810 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005811 if (index >= 0) {
5812 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5813 return r.intent.getComponent();
5814 }
5815 return null;
5816 }
5817 }
5818
5819 public String getPackageForToken(IBinder token) {
5820 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005821 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005822 if (index >= 0) {
5823 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5824 return r.packageName;
5825 }
5826 return null;
5827 }
5828 }
5829
5830 public IIntentSender getIntentSender(int type,
5831 String packageName, IBinder token, String resultWho,
5832 int requestCode, Intent intent, String resolvedType, int flags) {
5833 // Refuse possible leaked file descriptors
5834 if (intent != null && intent.hasFileDescriptors() == true) {
5835 throw new IllegalArgumentException("File descriptors passed in Intent");
5836 }
5837
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005838 if (type == INTENT_SENDER_BROADCAST) {
5839 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5840 throw new IllegalArgumentException(
5841 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5842 }
5843 }
5844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005845 synchronized(this) {
5846 int callingUid = Binder.getCallingUid();
5847 try {
5848 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5849 Process.supportsProcesses()) {
5850 int uid = ActivityThread.getPackageManager()
5851 .getPackageUid(packageName);
5852 if (uid != Binder.getCallingUid()) {
5853 String msg = "Permission Denial: getIntentSender() from pid="
5854 + Binder.getCallingPid()
5855 + ", uid=" + Binder.getCallingUid()
5856 + ", (need uid=" + uid + ")"
5857 + " is not allowed to send as package " + packageName;
5858 Log.w(TAG, msg);
5859 throw new SecurityException(msg);
5860 }
5861 }
5862 } catch (RemoteException e) {
5863 throw new SecurityException(e);
5864 }
5865 HistoryRecord activity = null;
5866 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005867 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005868 if (index < 0) {
5869 return null;
5870 }
5871 activity = (HistoryRecord)mHistory.get(index);
5872 if (activity.finishing) {
5873 return null;
5874 }
5875 }
5876
5877 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5878 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5879 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5880 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5881 |PendingIntent.FLAG_UPDATE_CURRENT);
5882
5883 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5884 type, packageName, activity, resultWho,
5885 requestCode, intent, resolvedType, flags);
5886 WeakReference<PendingIntentRecord> ref;
5887 ref = mIntentSenderRecords.get(key);
5888 PendingIntentRecord rec = ref != null ? ref.get() : null;
5889 if (rec != null) {
5890 if (!cancelCurrent) {
5891 if (updateCurrent) {
5892 rec.key.requestIntent.replaceExtras(intent);
5893 }
5894 return rec;
5895 }
5896 rec.canceled = true;
5897 mIntentSenderRecords.remove(key);
5898 }
5899 if (noCreate) {
5900 return rec;
5901 }
5902 rec = new PendingIntentRecord(this, key, callingUid);
5903 mIntentSenderRecords.put(key, rec.ref);
5904 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5905 if (activity.pendingResults == null) {
5906 activity.pendingResults
5907 = new HashSet<WeakReference<PendingIntentRecord>>();
5908 }
5909 activity.pendingResults.add(rec.ref);
5910 }
5911 return rec;
5912 }
5913 }
5914
5915 public void cancelIntentSender(IIntentSender sender) {
5916 if (!(sender instanceof PendingIntentRecord)) {
5917 return;
5918 }
5919 synchronized(this) {
5920 PendingIntentRecord rec = (PendingIntentRecord)sender;
5921 try {
5922 int uid = ActivityThread.getPackageManager()
5923 .getPackageUid(rec.key.packageName);
5924 if (uid != Binder.getCallingUid()) {
5925 String msg = "Permission Denial: cancelIntentSender() from pid="
5926 + Binder.getCallingPid()
5927 + ", uid=" + Binder.getCallingUid()
5928 + " is not allowed to cancel packges "
5929 + rec.key.packageName;
5930 Log.w(TAG, msg);
5931 throw new SecurityException(msg);
5932 }
5933 } catch (RemoteException e) {
5934 throw new SecurityException(e);
5935 }
5936 cancelIntentSenderLocked(rec, true);
5937 }
5938 }
5939
5940 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5941 rec.canceled = true;
5942 mIntentSenderRecords.remove(rec.key);
5943 if (cleanActivity && rec.key.activity != null) {
5944 rec.key.activity.pendingResults.remove(rec.ref);
5945 }
5946 }
5947
5948 public String getPackageForIntentSender(IIntentSender pendingResult) {
5949 if (!(pendingResult instanceof PendingIntentRecord)) {
5950 return null;
5951 }
5952 synchronized(this) {
5953 try {
5954 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5955 return res.key.packageName;
5956 } catch (ClassCastException e) {
5957 }
5958 }
5959 return null;
5960 }
5961
5962 public void setProcessLimit(int max) {
5963 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5964 "setProcessLimit()");
5965 mProcessLimit = max;
5966 }
5967
5968 public int getProcessLimit() {
5969 return mProcessLimit;
5970 }
5971
5972 void foregroundTokenDied(ForegroundToken token) {
5973 synchronized (ActivityManagerService.this) {
5974 synchronized (mPidsSelfLocked) {
5975 ForegroundToken cur
5976 = mForegroundProcesses.get(token.pid);
5977 if (cur != token) {
5978 return;
5979 }
5980 mForegroundProcesses.remove(token.pid);
5981 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5982 if (pr == null) {
5983 return;
5984 }
5985 pr.forcingToForeground = null;
5986 pr.foregroundServices = false;
5987 }
5988 updateOomAdjLocked();
5989 }
5990 }
5991
5992 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5993 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5994 "setProcessForeground()");
5995 synchronized(this) {
5996 boolean changed = false;
5997
5998 synchronized (mPidsSelfLocked) {
5999 ProcessRecord pr = mPidsSelfLocked.get(pid);
6000 if (pr == null) {
6001 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
6002 return;
6003 }
6004 ForegroundToken oldToken = mForegroundProcesses.get(pid);
6005 if (oldToken != null) {
6006 oldToken.token.unlinkToDeath(oldToken, 0);
6007 mForegroundProcesses.remove(pid);
6008 pr.forcingToForeground = null;
6009 changed = true;
6010 }
6011 if (isForeground && token != null) {
6012 ForegroundToken newToken = new ForegroundToken() {
6013 public void binderDied() {
6014 foregroundTokenDied(this);
6015 }
6016 };
6017 newToken.pid = pid;
6018 newToken.token = token;
6019 try {
6020 token.linkToDeath(newToken, 0);
6021 mForegroundProcesses.put(pid, newToken);
6022 pr.forcingToForeground = token;
6023 changed = true;
6024 } catch (RemoteException e) {
6025 // If the process died while doing this, we will later
6026 // do the cleanup with the process death link.
6027 }
6028 }
6029 }
6030
6031 if (changed) {
6032 updateOomAdjLocked();
6033 }
6034 }
6035 }
6036
6037 // =========================================================
6038 // PERMISSIONS
6039 // =========================================================
6040
6041 static class PermissionController extends IPermissionController.Stub {
6042 ActivityManagerService mActivityManagerService;
6043 PermissionController(ActivityManagerService activityManagerService) {
6044 mActivityManagerService = activityManagerService;
6045 }
6046
6047 public boolean checkPermission(String permission, int pid, int uid) {
6048 return mActivityManagerService.checkPermission(permission, pid,
6049 uid) == PackageManager.PERMISSION_GRANTED;
6050 }
6051 }
6052
6053 /**
6054 * This can be called with or without the global lock held.
6055 */
6056 int checkComponentPermission(String permission, int pid, int uid,
6057 int reqUid) {
6058 // We might be performing an operation on behalf of an indirect binder
6059 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6060 // client identity accordingly before proceeding.
6061 Identity tlsIdentity = sCallerIdentity.get();
6062 if (tlsIdentity != null) {
6063 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6064 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6065 uid = tlsIdentity.uid;
6066 pid = tlsIdentity.pid;
6067 }
6068
6069 // Root, system server and our own process get to do everything.
6070 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6071 !Process.supportsProcesses()) {
6072 return PackageManager.PERMISSION_GRANTED;
6073 }
6074 // If the target requires a specific UID, always fail for others.
6075 if (reqUid >= 0 && uid != reqUid) {
6076 return PackageManager.PERMISSION_DENIED;
6077 }
6078 if (permission == null) {
6079 return PackageManager.PERMISSION_GRANTED;
6080 }
6081 try {
6082 return ActivityThread.getPackageManager()
6083 .checkUidPermission(permission, uid);
6084 } catch (RemoteException e) {
6085 // Should never happen, but if it does... deny!
6086 Log.e(TAG, "PackageManager is dead?!?", e);
6087 }
6088 return PackageManager.PERMISSION_DENIED;
6089 }
6090
6091 /**
6092 * As the only public entry point for permissions checking, this method
6093 * can enforce the semantic that requesting a check on a null global
6094 * permission is automatically denied. (Internally a null permission
6095 * string is used when calling {@link #checkComponentPermission} in cases
6096 * when only uid-based security is needed.)
6097 *
6098 * This can be called with or without the global lock held.
6099 */
6100 public int checkPermission(String permission, int pid, int uid) {
6101 if (permission == null) {
6102 return PackageManager.PERMISSION_DENIED;
6103 }
6104 return checkComponentPermission(permission, pid, uid, -1);
6105 }
6106
6107 /**
6108 * Binder IPC calls go through the public entry point.
6109 * This can be called with or without the global lock held.
6110 */
6111 int checkCallingPermission(String permission) {
6112 return checkPermission(permission,
6113 Binder.getCallingPid(),
6114 Binder.getCallingUid());
6115 }
6116
6117 /**
6118 * This can be called with or without the global lock held.
6119 */
6120 void enforceCallingPermission(String permission, String func) {
6121 if (checkCallingPermission(permission)
6122 == PackageManager.PERMISSION_GRANTED) {
6123 return;
6124 }
6125
6126 String msg = "Permission Denial: " + func + " from pid="
6127 + Binder.getCallingPid()
6128 + ", uid=" + Binder.getCallingUid()
6129 + " requires " + permission;
6130 Log.w(TAG, msg);
6131 throw new SecurityException(msg);
6132 }
6133
6134 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6135 ProviderInfo pi, int uid, int modeFlags) {
6136 try {
6137 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6138 if ((pi.readPermission != null) &&
6139 (pm.checkUidPermission(pi.readPermission, uid)
6140 != PackageManager.PERMISSION_GRANTED)) {
6141 return false;
6142 }
6143 }
6144 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6145 if ((pi.writePermission != null) &&
6146 (pm.checkUidPermission(pi.writePermission, uid)
6147 != PackageManager.PERMISSION_GRANTED)) {
6148 return false;
6149 }
6150 }
6151 return true;
6152 } catch (RemoteException e) {
6153 return false;
6154 }
6155 }
6156
6157 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6158 int modeFlags) {
6159 // Root gets to do everything.
6160 if (uid == 0 || !Process.supportsProcesses()) {
6161 return true;
6162 }
6163 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6164 if (perms == null) return false;
6165 UriPermission perm = perms.get(uri);
6166 if (perm == null) return false;
6167 return (modeFlags&perm.modeFlags) == modeFlags;
6168 }
6169
6170 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6171 // Another redirected-binder-call permissions check as in
6172 // {@link checkComponentPermission}.
6173 Identity tlsIdentity = sCallerIdentity.get();
6174 if (tlsIdentity != null) {
6175 uid = tlsIdentity.uid;
6176 pid = tlsIdentity.pid;
6177 }
6178
6179 // Our own process gets to do everything.
6180 if (pid == MY_PID) {
6181 return PackageManager.PERMISSION_GRANTED;
6182 }
6183 synchronized(this) {
6184 return checkUriPermissionLocked(uri, uid, modeFlags)
6185 ? PackageManager.PERMISSION_GRANTED
6186 : PackageManager.PERMISSION_DENIED;
6187 }
6188 }
6189
6190 private void grantUriPermissionLocked(int callingUid,
6191 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6192 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6193 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6194 if (modeFlags == 0) {
6195 return;
6196 }
6197
6198 final IPackageManager pm = ActivityThread.getPackageManager();
6199
6200 // If this is not a content: uri, we can't do anything with it.
6201 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6202 return;
6203 }
6204
6205 String name = uri.getAuthority();
6206 ProviderInfo pi = null;
6207 ContentProviderRecord cpr
6208 = (ContentProviderRecord)mProvidersByName.get(name);
6209 if (cpr != null) {
6210 pi = cpr.info;
6211 } else {
6212 try {
6213 pi = pm.resolveContentProvider(name,
6214 PackageManager.GET_URI_PERMISSION_PATTERNS);
6215 } catch (RemoteException ex) {
6216 }
6217 }
6218 if (pi == null) {
6219 Log.w(TAG, "No content provider found for: " + name);
6220 return;
6221 }
6222
6223 int targetUid;
6224 try {
6225 targetUid = pm.getPackageUid(targetPkg);
6226 if (targetUid < 0) {
6227 return;
6228 }
6229 } catch (RemoteException ex) {
6230 return;
6231 }
6232
6233 // First... does the target actually need this permission?
6234 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6235 // No need to grant the target this permission.
6236 return;
6237 }
6238
6239 // Second... maybe someone else has already granted the
6240 // permission?
6241 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6242 // No need to grant the target this permission.
6243 return;
6244 }
6245
6246 // Third... is the provider allowing granting of URI permissions?
6247 if (!pi.grantUriPermissions) {
6248 throw new SecurityException("Provider " + pi.packageName
6249 + "/" + pi.name
6250 + " does not allow granting of Uri permissions (uri "
6251 + uri + ")");
6252 }
6253 if (pi.uriPermissionPatterns != null) {
6254 final int N = pi.uriPermissionPatterns.length;
6255 boolean allowed = false;
6256 for (int i=0; i<N; i++) {
6257 if (pi.uriPermissionPatterns[i] != null
6258 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6259 allowed = true;
6260 break;
6261 }
6262 }
6263 if (!allowed) {
6264 throw new SecurityException("Provider " + pi.packageName
6265 + "/" + pi.name
6266 + " does not allow granting of permission to path of Uri "
6267 + uri);
6268 }
6269 }
6270
6271 // Fourth... does the caller itself have permission to access
6272 // this uri?
6273 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6274 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6275 throw new SecurityException("Uid " + callingUid
6276 + " does not have permission to uri " + uri);
6277 }
6278 }
6279
6280 // Okay! So here we are: the caller has the assumed permission
6281 // to the uri, and the target doesn't. Let's now give this to
6282 // the target.
6283
6284 HashMap<Uri, UriPermission> targetUris
6285 = mGrantedUriPermissions.get(targetUid);
6286 if (targetUris == null) {
6287 targetUris = new HashMap<Uri, UriPermission>();
6288 mGrantedUriPermissions.put(targetUid, targetUris);
6289 }
6290
6291 UriPermission perm = targetUris.get(uri);
6292 if (perm == null) {
6293 perm = new UriPermission(targetUid, uri);
6294 targetUris.put(uri, perm);
6295
6296 }
6297 perm.modeFlags |= modeFlags;
6298 if (activity == null) {
6299 perm.globalModeFlags |= modeFlags;
6300 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6301 perm.readActivities.add(activity);
6302 if (activity.readUriPermissions == null) {
6303 activity.readUriPermissions = new HashSet<UriPermission>();
6304 }
6305 activity.readUriPermissions.add(perm);
6306 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6307 perm.writeActivities.add(activity);
6308 if (activity.writeUriPermissions == null) {
6309 activity.writeUriPermissions = new HashSet<UriPermission>();
6310 }
6311 activity.writeUriPermissions.add(perm);
6312 }
6313 }
6314
6315 private void grantUriPermissionFromIntentLocked(int callingUid,
6316 String targetPkg, Intent intent, HistoryRecord activity) {
6317 if (intent == null) {
6318 return;
6319 }
6320 Uri data = intent.getData();
6321 if (data == null) {
6322 return;
6323 }
6324 grantUriPermissionLocked(callingUid, targetPkg, data,
6325 intent.getFlags(), activity);
6326 }
6327
6328 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6329 Uri uri, int modeFlags) {
6330 synchronized(this) {
6331 final ProcessRecord r = getRecordForAppLocked(caller);
6332 if (r == null) {
6333 throw new SecurityException("Unable to find app for caller "
6334 + caller
6335 + " when granting permission to uri " + uri);
6336 }
6337 if (targetPkg == null) {
6338 Log.w(TAG, "grantUriPermission: null target");
6339 return;
6340 }
6341 if (uri == null) {
6342 Log.w(TAG, "grantUriPermission: null uri");
6343 return;
6344 }
6345
6346 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6347 null);
6348 }
6349 }
6350
6351 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6352 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6353 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6354 HashMap<Uri, UriPermission> perms
6355 = mGrantedUriPermissions.get(perm.uid);
6356 if (perms != null) {
6357 perms.remove(perm.uri);
6358 if (perms.size() == 0) {
6359 mGrantedUriPermissions.remove(perm.uid);
6360 }
6361 }
6362 }
6363 }
6364
6365 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6366 if (activity.readUriPermissions != null) {
6367 for (UriPermission perm : activity.readUriPermissions) {
6368 perm.readActivities.remove(activity);
6369 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6370 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6371 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6372 removeUriPermissionIfNeededLocked(perm);
6373 }
6374 }
6375 }
6376 if (activity.writeUriPermissions != null) {
6377 for (UriPermission perm : activity.writeUriPermissions) {
6378 perm.writeActivities.remove(activity);
6379 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6380 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6381 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6382 removeUriPermissionIfNeededLocked(perm);
6383 }
6384 }
6385 }
6386 }
6387
6388 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6389 int modeFlags) {
6390 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6391 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6392 if (modeFlags == 0) {
6393 return;
6394 }
6395
6396 final IPackageManager pm = ActivityThread.getPackageManager();
6397
6398 final String authority = uri.getAuthority();
6399 ProviderInfo pi = null;
6400 ContentProviderRecord cpr
6401 = (ContentProviderRecord)mProvidersByName.get(authority);
6402 if (cpr != null) {
6403 pi = cpr.info;
6404 } else {
6405 try {
6406 pi = pm.resolveContentProvider(authority,
6407 PackageManager.GET_URI_PERMISSION_PATTERNS);
6408 } catch (RemoteException ex) {
6409 }
6410 }
6411 if (pi == null) {
6412 Log.w(TAG, "No content provider found for: " + authority);
6413 return;
6414 }
6415
6416 // Does the caller have this permission on the URI?
6417 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6418 // Right now, if you are not the original owner of the permission,
6419 // you are not allowed to revoke it.
6420 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6421 throw new SecurityException("Uid " + callingUid
6422 + " does not have permission to uri " + uri);
6423 //}
6424 }
6425
6426 // Go through all of the permissions and remove any that match.
6427 final List<String> SEGMENTS = uri.getPathSegments();
6428 if (SEGMENTS != null) {
6429 final int NS = SEGMENTS.size();
6430 int N = mGrantedUriPermissions.size();
6431 for (int i=0; i<N; i++) {
6432 HashMap<Uri, UriPermission> perms
6433 = mGrantedUriPermissions.valueAt(i);
6434 Iterator<UriPermission> it = perms.values().iterator();
6435 toploop:
6436 while (it.hasNext()) {
6437 UriPermission perm = it.next();
6438 Uri targetUri = perm.uri;
6439 if (!authority.equals(targetUri.getAuthority())) {
6440 continue;
6441 }
6442 List<String> targetSegments = targetUri.getPathSegments();
6443 if (targetSegments == null) {
6444 continue;
6445 }
6446 if (targetSegments.size() < NS) {
6447 continue;
6448 }
6449 for (int j=0; j<NS; j++) {
6450 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6451 continue toploop;
6452 }
6453 }
6454 perm.clearModes(modeFlags);
6455 if (perm.modeFlags == 0) {
6456 it.remove();
6457 }
6458 }
6459 if (perms.size() == 0) {
6460 mGrantedUriPermissions.remove(
6461 mGrantedUriPermissions.keyAt(i));
6462 N--;
6463 i--;
6464 }
6465 }
6466 }
6467 }
6468
6469 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6470 int modeFlags) {
6471 synchronized(this) {
6472 final ProcessRecord r = getRecordForAppLocked(caller);
6473 if (r == null) {
6474 throw new SecurityException("Unable to find app for caller "
6475 + caller
6476 + " when revoking permission to uri " + uri);
6477 }
6478 if (uri == null) {
6479 Log.w(TAG, "revokeUriPermission: null uri");
6480 return;
6481 }
6482
6483 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6484 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6485 if (modeFlags == 0) {
6486 return;
6487 }
6488
6489 final IPackageManager pm = ActivityThread.getPackageManager();
6490
6491 final String authority = uri.getAuthority();
6492 ProviderInfo pi = null;
6493 ContentProviderRecord cpr
6494 = (ContentProviderRecord)mProvidersByName.get(authority);
6495 if (cpr != null) {
6496 pi = cpr.info;
6497 } else {
6498 try {
6499 pi = pm.resolveContentProvider(authority,
6500 PackageManager.GET_URI_PERMISSION_PATTERNS);
6501 } catch (RemoteException ex) {
6502 }
6503 }
6504 if (pi == null) {
6505 Log.w(TAG, "No content provider found for: " + authority);
6506 return;
6507 }
6508
6509 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6510 }
6511 }
6512
6513 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6514 synchronized (this) {
6515 ProcessRecord app =
6516 who != null ? getRecordForAppLocked(who) : null;
6517 if (app == null) return;
6518
6519 Message msg = Message.obtain();
6520 msg.what = WAIT_FOR_DEBUGGER_MSG;
6521 msg.obj = app;
6522 msg.arg1 = waiting ? 1 : 0;
6523 mHandler.sendMessage(msg);
6524 }
6525 }
6526
6527 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6528 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006529 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006530 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006531 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006532 }
6533
6534 // =========================================================
6535 // TASK MANAGEMENT
6536 // =========================================================
6537
6538 public List getTasks(int maxNum, int flags,
6539 IThumbnailReceiver receiver) {
6540 ArrayList list = new ArrayList();
6541
6542 PendingThumbnailsRecord pending = null;
6543 IApplicationThread topThumbnail = null;
6544 HistoryRecord topRecord = null;
6545
6546 synchronized(this) {
6547 if (localLOGV) Log.v(
6548 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6549 + ", receiver=" + receiver);
6550
6551 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6552 != PackageManager.PERMISSION_GRANTED) {
6553 if (receiver != null) {
6554 // If the caller wants to wait for pending thumbnails,
6555 // it ain't gonna get them.
6556 try {
6557 receiver.finished();
6558 } catch (RemoteException ex) {
6559 }
6560 }
6561 String msg = "Permission Denial: getTasks() from pid="
6562 + Binder.getCallingPid()
6563 + ", uid=" + Binder.getCallingUid()
6564 + " requires " + android.Manifest.permission.GET_TASKS;
6565 Log.w(TAG, msg);
6566 throw new SecurityException(msg);
6567 }
6568
6569 int pos = mHistory.size()-1;
6570 HistoryRecord next =
6571 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6572 HistoryRecord top = null;
6573 CharSequence topDescription = null;
6574 TaskRecord curTask = null;
6575 int numActivities = 0;
6576 int numRunning = 0;
6577 while (pos >= 0 && maxNum > 0) {
6578 final HistoryRecord r = next;
6579 pos--;
6580 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6581
6582 // Initialize state for next task if needed.
6583 if (top == null ||
6584 (top.state == ActivityState.INITIALIZING
6585 && top.task == r.task)) {
6586 top = r;
6587 topDescription = r.description;
6588 curTask = r.task;
6589 numActivities = numRunning = 0;
6590 }
6591
6592 // Add 'r' into the current task.
6593 numActivities++;
6594 if (r.app != null && r.app.thread != null) {
6595 numRunning++;
6596 }
6597 if (topDescription == null) {
6598 topDescription = r.description;
6599 }
6600
6601 if (localLOGV) Log.v(
6602 TAG, r.intent.getComponent().flattenToShortString()
6603 + ": task=" + r.task);
6604
6605 // If the next one is a different task, generate a new
6606 // TaskInfo entry for what we have.
6607 if (next == null || next.task != curTask) {
6608 ActivityManager.RunningTaskInfo ci
6609 = new ActivityManager.RunningTaskInfo();
6610 ci.id = curTask.taskId;
6611 ci.baseActivity = r.intent.getComponent();
6612 ci.topActivity = top.intent.getComponent();
6613 ci.thumbnail = top.thumbnail;
6614 ci.description = topDescription;
6615 ci.numActivities = numActivities;
6616 ci.numRunning = numRunning;
6617 //System.out.println(
6618 // "#" + maxNum + ": " + " descr=" + ci.description);
6619 if (ci.thumbnail == null && receiver != null) {
6620 if (localLOGV) Log.v(
6621 TAG, "State=" + top.state + "Idle=" + top.idle
6622 + " app=" + top.app
6623 + " thr=" + (top.app != null ? top.app.thread : null));
6624 if (top.state == ActivityState.RESUMED
6625 || top.state == ActivityState.PAUSING) {
6626 if (top.idle && top.app != null
6627 && top.app.thread != null) {
6628 topRecord = top;
6629 topThumbnail = top.app.thread;
6630 } else {
6631 top.thumbnailNeeded = true;
6632 }
6633 }
6634 if (pending == null) {
6635 pending = new PendingThumbnailsRecord(receiver);
6636 }
6637 pending.pendingRecords.add(top);
6638 }
6639 list.add(ci);
6640 maxNum--;
6641 top = null;
6642 }
6643 }
6644
6645 if (pending != null) {
6646 mPendingThumbnails.add(pending);
6647 }
6648 }
6649
6650 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6651
6652 if (topThumbnail != null) {
6653 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6654 try {
6655 topThumbnail.requestThumbnail(topRecord);
6656 } catch (Exception e) {
6657 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6658 sendPendingThumbnail(null, topRecord, null, null, true);
6659 }
6660 }
6661
6662 if (pending == null && receiver != null) {
6663 // In this case all thumbnails were available and the client
6664 // is being asked to be told when the remaining ones come in...
6665 // which is unusually, since the top-most currently running
6666 // activity should never have a canned thumbnail! Oh well.
6667 try {
6668 receiver.finished();
6669 } catch (RemoteException ex) {
6670 }
6671 }
6672
6673 return list;
6674 }
6675
6676 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6677 int flags) {
6678 synchronized (this) {
6679 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6680 "getRecentTasks()");
6681
6682 final int N = mRecentTasks.size();
6683 ArrayList<ActivityManager.RecentTaskInfo> res
6684 = new ArrayList<ActivityManager.RecentTaskInfo>(
6685 maxNum < N ? maxNum : N);
6686 for (int i=0; i<N && maxNum > 0; i++) {
6687 TaskRecord tr = mRecentTasks.get(i);
6688 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6689 || (tr.intent == null)
6690 || ((tr.intent.getFlags()
6691 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6692 ActivityManager.RecentTaskInfo rti
6693 = new ActivityManager.RecentTaskInfo();
6694 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6695 rti.baseIntent = new Intent(
6696 tr.intent != null ? tr.intent : tr.affinityIntent);
6697 rti.origActivity = tr.origActivity;
6698 res.add(rti);
6699 maxNum--;
6700 }
6701 }
6702 return res;
6703 }
6704 }
6705
6706 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6707 int j;
6708 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6709 TaskRecord jt = startTask;
6710
6711 // First look backwards
6712 for (j=startIndex-1; j>=0; j--) {
6713 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6714 if (r.task != jt) {
6715 jt = r.task;
6716 if (affinity.equals(jt.affinity)) {
6717 return j;
6718 }
6719 }
6720 }
6721
6722 // Now look forwards
6723 final int N = mHistory.size();
6724 jt = startTask;
6725 for (j=startIndex+1; j<N; j++) {
6726 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6727 if (r.task != jt) {
6728 if (affinity.equals(jt.affinity)) {
6729 return j;
6730 }
6731 jt = r.task;
6732 }
6733 }
6734
6735 // Might it be at the top?
6736 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6737 return N-1;
6738 }
6739
6740 return -1;
6741 }
6742
6743 /**
6744 * Perform a reset of the given task, if needed as part of launching it.
6745 * Returns the new HistoryRecord at the top of the task.
6746 */
6747 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6748 HistoryRecord newActivity) {
6749 boolean forceReset = (newActivity.info.flags
6750 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6751 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6752 if ((newActivity.info.flags
6753 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6754 forceReset = true;
6755 }
6756 }
6757
6758 final TaskRecord task = taskTop.task;
6759
6760 // We are going to move through the history list so that we can look
6761 // at each activity 'target' with 'below' either the interesting
6762 // activity immediately below it in the stack or null.
6763 HistoryRecord target = null;
6764 int targetI = 0;
6765 int taskTopI = -1;
6766 int replyChainEnd = -1;
6767 int lastReparentPos = -1;
6768 for (int i=mHistory.size()-1; i>=-1; i--) {
6769 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6770
6771 if (below != null && below.finishing) {
6772 continue;
6773 }
6774 if (target == null) {
6775 target = below;
6776 targetI = i;
6777 // If we were in the middle of a reply chain before this
6778 // task, it doesn't appear like the root of the chain wants
6779 // anything interesting, so drop it.
6780 replyChainEnd = -1;
6781 continue;
6782 }
6783
6784 final int flags = target.info.flags;
6785
6786 final boolean finishOnTaskLaunch =
6787 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6788 final boolean allowTaskReparenting =
6789 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6790
6791 if (target.task == task) {
6792 // We are inside of the task being reset... we'll either
6793 // finish this activity, push it out for another task,
6794 // or leave it as-is. We only do this
6795 // for activities that are not the root of the task (since
6796 // if we finish the root, we may no longer have the task!).
6797 if (taskTopI < 0) {
6798 taskTopI = targetI;
6799 }
6800 if (below != null && below.task == task) {
6801 final boolean clearWhenTaskReset =
6802 (target.intent.getFlags()
6803 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006804 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006805 // If this activity is sending a reply to a previous
6806 // activity, we can't do anything with it now until
6807 // we reach the start of the reply chain.
6808 // XXX note that we are assuming the result is always
6809 // to the previous activity, which is almost always
6810 // the case but we really shouldn't count on.
6811 if (replyChainEnd < 0) {
6812 replyChainEnd = targetI;
6813 }
Ed Heyl73798232009-03-24 21:32:21 -07006814 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006815 && target.taskAffinity != null
6816 && !target.taskAffinity.equals(task.affinity)) {
6817 // If this activity has an affinity for another
6818 // task, then we need to move it out of here. We will
6819 // move it as far out of the way as possible, to the
6820 // bottom of the activity stack. This also keeps it
6821 // correctly ordered with any activities we previously
6822 // moved.
6823 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6824 if (target.taskAffinity != null
6825 && target.taskAffinity.equals(p.task.affinity)) {
6826 // If the activity currently at the bottom has the
6827 // same task affinity as the one we are moving,
6828 // then merge it into the same task.
6829 target.task = p.task;
6830 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6831 + " out to bottom task " + p.task);
6832 } else {
6833 mCurTask++;
6834 if (mCurTask <= 0) {
6835 mCurTask = 1;
6836 }
6837 target.task = new TaskRecord(mCurTask, target.info, null,
6838 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6839 target.task.affinityIntent = target.intent;
6840 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6841 + " out to new task " + target.task);
6842 }
6843 mWindowManager.setAppGroupId(target, task.taskId);
6844 if (replyChainEnd < 0) {
6845 replyChainEnd = targetI;
6846 }
6847 int dstPos = 0;
6848 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6849 p = (HistoryRecord)mHistory.get(srcPos);
6850 if (p.finishing) {
6851 continue;
6852 }
6853 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6854 + " out to target's task " + target.task);
6855 task.numActivities--;
6856 p.task = target.task;
6857 target.task.numActivities++;
6858 mHistory.remove(srcPos);
6859 mHistory.add(dstPos, p);
6860 mWindowManager.moveAppToken(dstPos, p);
6861 mWindowManager.setAppGroupId(p, p.task.taskId);
6862 dstPos++;
6863 if (VALIDATE_TOKENS) {
6864 mWindowManager.validateAppTokens(mHistory);
6865 }
6866 i++;
6867 }
6868 if (taskTop == p) {
6869 taskTop = below;
6870 }
6871 if (taskTopI == replyChainEnd) {
6872 taskTopI = -1;
6873 }
6874 replyChainEnd = -1;
6875 addRecentTask(target.task);
6876 } else if (forceReset || finishOnTaskLaunch
6877 || clearWhenTaskReset) {
6878 // If the activity should just be removed -- either
6879 // because it asks for it, or the task should be
6880 // cleared -- then finish it and anything that is
6881 // part of its reply chain.
6882 if (clearWhenTaskReset) {
6883 // In this case, we want to finish this activity
6884 // and everything above it, so be sneaky and pretend
6885 // like these are all in the reply chain.
6886 replyChainEnd = targetI+1;
6887 while (replyChainEnd < mHistory.size() &&
6888 ((HistoryRecord)mHistory.get(
6889 replyChainEnd)).task == task) {
6890 replyChainEnd++;
6891 }
6892 replyChainEnd--;
6893 } else if (replyChainEnd < 0) {
6894 replyChainEnd = targetI;
6895 }
6896 HistoryRecord p = null;
6897 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6898 p = (HistoryRecord)mHistory.get(srcPos);
6899 if (p.finishing) {
6900 continue;
6901 }
6902 if (finishActivityLocked(p, srcPos,
6903 Activity.RESULT_CANCELED, null, "reset")) {
6904 replyChainEnd--;
6905 srcPos--;
6906 }
6907 }
6908 if (taskTop == p) {
6909 taskTop = below;
6910 }
6911 if (taskTopI == replyChainEnd) {
6912 taskTopI = -1;
6913 }
6914 replyChainEnd = -1;
6915 } else {
6916 // If we were in the middle of a chain, well the
6917 // activity that started it all doesn't want anything
6918 // special, so leave it all as-is.
6919 replyChainEnd = -1;
6920 }
6921 } else {
6922 // Reached the bottom of the task -- any reply chain
6923 // should be left as-is.
6924 replyChainEnd = -1;
6925 }
6926
6927 } else if (target.resultTo != null) {
6928 // If this activity is sending a reply to a previous
6929 // activity, we can't do anything with it now until
6930 // we reach the start of the reply chain.
6931 // XXX note that we are assuming the result is always
6932 // to the previous activity, which is almost always
6933 // the case but we really shouldn't count on.
6934 if (replyChainEnd < 0) {
6935 replyChainEnd = targetI;
6936 }
6937
6938 } else if (taskTopI >= 0 && allowTaskReparenting
6939 && task.affinity != null
6940 && task.affinity.equals(target.taskAffinity)) {
6941 // We are inside of another task... if this activity has
6942 // an affinity for our task, then either remove it if we are
6943 // clearing or move it over to our task. Note that
6944 // we currently punt on the case where we are resetting a
6945 // task that is not at the top but who has activities above
6946 // with an affinity to it... this is really not a normal
6947 // case, and we will need to later pull that task to the front
6948 // and usually at that point we will do the reset and pick
6949 // up those remaining activities. (This only happens if
6950 // someone starts an activity in a new task from an activity
6951 // in a task that is not currently on top.)
6952 if (forceReset || finishOnTaskLaunch) {
6953 if (replyChainEnd < 0) {
6954 replyChainEnd = targetI;
6955 }
6956 HistoryRecord p = null;
6957 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6958 p = (HistoryRecord)mHistory.get(srcPos);
6959 if (p.finishing) {
6960 continue;
6961 }
6962 if (finishActivityLocked(p, srcPos,
6963 Activity.RESULT_CANCELED, null, "reset")) {
6964 taskTopI--;
6965 lastReparentPos--;
6966 replyChainEnd--;
6967 srcPos--;
6968 }
6969 }
6970 replyChainEnd = -1;
6971 } else {
6972 if (replyChainEnd < 0) {
6973 replyChainEnd = targetI;
6974 }
6975 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6976 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6977 if (p.finishing) {
6978 continue;
6979 }
6980 if (lastReparentPos < 0) {
6981 lastReparentPos = taskTopI;
6982 taskTop = p;
6983 } else {
6984 lastReparentPos--;
6985 }
6986 mHistory.remove(srcPos);
6987 p.task.numActivities--;
6988 p.task = task;
6989 mHistory.add(lastReparentPos, p);
6990 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6991 + " in to resetting task " + task);
6992 task.numActivities++;
6993 mWindowManager.moveAppToken(lastReparentPos, p);
6994 mWindowManager.setAppGroupId(p, p.task.taskId);
6995 if (VALIDATE_TOKENS) {
6996 mWindowManager.validateAppTokens(mHistory);
6997 }
6998 }
6999 replyChainEnd = -1;
7000
7001 // Now we've moved it in to place... but what if this is
7002 // a singleTop activity and we have put it on top of another
7003 // instance of the same activity? Then we drop the instance
7004 // below so it remains singleTop.
7005 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
7006 for (int j=lastReparentPos-1; j>=0; j--) {
7007 HistoryRecord p = (HistoryRecord)mHistory.get(j);
7008 if (p.finishing) {
7009 continue;
7010 }
7011 if (p.intent.getComponent().equals(target.intent.getComponent())) {
7012 if (finishActivityLocked(p, j,
7013 Activity.RESULT_CANCELED, null, "replace")) {
7014 taskTopI--;
7015 lastReparentPos--;
7016 }
7017 }
7018 }
7019 }
7020 }
7021 }
7022
7023 target = below;
7024 targetI = i;
7025 }
7026
7027 return taskTop;
7028 }
7029
7030 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007031 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007032 */
7033 public void moveTaskToFront(int task) {
7034 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7035 "moveTaskToFront()");
7036
7037 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007038 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7039 Binder.getCallingUid(), "Task to front")) {
7040 return;
7041 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007042 final long origId = Binder.clearCallingIdentity();
7043 try {
7044 int N = mRecentTasks.size();
7045 for (int i=0; i<N; i++) {
7046 TaskRecord tr = mRecentTasks.get(i);
7047 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007048 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007049 return;
7050 }
7051 }
7052 for (int i=mHistory.size()-1; i>=0; i--) {
7053 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7054 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007055 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007056 return;
7057 }
7058 }
7059 } finally {
7060 Binder.restoreCallingIdentity(origId);
7061 }
7062 }
7063 }
7064
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007065 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007066 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7067
7068 final int task = tr.taskId;
7069 int top = mHistory.size()-1;
7070
7071 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7072 // nothing to do!
7073 return;
7074 }
7075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007076 ArrayList moved = new ArrayList();
7077
7078 // Applying the affinities may have removed entries from the history,
7079 // so get the size again.
7080 top = mHistory.size()-1;
7081 int pos = top;
7082
7083 // Shift all activities with this task up to the top
7084 // of the stack, keeping them in the same internal order.
7085 while (pos >= 0) {
7086 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7087 if (localLOGV) Log.v(
7088 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7089 boolean first = true;
7090 if (r.task.taskId == task) {
7091 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7092 mHistory.remove(pos);
7093 mHistory.add(top, r);
7094 moved.add(0, r);
7095 top--;
7096 if (first) {
7097 addRecentTask(r.task);
7098 first = false;
7099 }
7100 }
7101 pos--;
7102 }
7103
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007104 if (DEBUG_TRANSITION) Log.v(TAG,
7105 "Prepare to front transition: task=" + tr);
7106 if (reason != null &&
7107 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7108 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7109 HistoryRecord r = topRunningActivityLocked(null);
7110 if (r != null) {
7111 mNoAnimActivities.add(r);
7112 }
7113 } else {
7114 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7115 }
7116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007117 mWindowManager.moveAppTokensToTop(moved);
7118 if (VALIDATE_TOKENS) {
7119 mWindowManager.validateAppTokens(mHistory);
7120 }
7121
7122 finishTaskMove(task);
7123 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7124 }
7125
7126 private final void finishTaskMove(int task) {
7127 resumeTopActivityLocked(null);
7128 }
7129
7130 public void moveTaskToBack(int task) {
7131 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7132 "moveTaskToBack()");
7133
7134 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007135 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7136 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7137 Binder.getCallingUid(), "Task to back")) {
7138 return;
7139 }
7140 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007141 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007142 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007143 Binder.restoreCallingIdentity(origId);
7144 }
7145 }
7146
7147 /**
7148 * Moves an activity, and all of the other activities within the same task, to the bottom
7149 * of the history stack. The activity's order within the task is unchanged.
7150 *
7151 * @param token A reference to the activity we wish to move
7152 * @param nonRoot If false then this only works if the activity is the root
7153 * of a task; if true it will work for any activity in a task.
7154 * @return Returns true if the move completed, false if not.
7155 */
7156 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7157 synchronized(this) {
7158 final long origId = Binder.clearCallingIdentity();
7159 int taskId = getTaskForActivityLocked(token, !nonRoot);
7160 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007161 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007162 }
7163 Binder.restoreCallingIdentity(origId);
7164 }
7165 return false;
7166 }
7167
7168 /**
7169 * Worker method for rearranging history stack. Implements the function of moving all
7170 * activities for a specific task (gathering them if disjoint) into a single group at the
7171 * bottom of the stack.
7172 *
7173 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7174 * to premeptively cancel the move.
7175 *
7176 * @param task The taskId to collect and move to the bottom.
7177 * @return Returns true if the move completed, false if not.
7178 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007179 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007180 Log.i(TAG, "moveTaskToBack: " + task);
7181
7182 // If we have a watcher, preflight the move before committing to it. First check
7183 // for *other* available tasks, but if none are available, then try again allowing the
7184 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007185 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007186 HistoryRecord next = topRunningActivityLocked(null, task);
7187 if (next == null) {
7188 next = topRunningActivityLocked(null, 0);
7189 }
7190 if (next != null) {
7191 // ask watcher if this is allowed
7192 boolean moveOK = true;
7193 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007194 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007195 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007196 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007197 }
7198 if (!moveOK) {
7199 return false;
7200 }
7201 }
7202 }
7203
7204 ArrayList moved = new ArrayList();
7205
7206 if (DEBUG_TRANSITION) Log.v(TAG,
7207 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007208
7209 final int N = mHistory.size();
7210 int bottom = 0;
7211 int pos = 0;
7212
7213 // Shift all activities with this task down to the bottom
7214 // of the stack, keeping them in the same internal order.
7215 while (pos < N) {
7216 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7217 if (localLOGV) Log.v(
7218 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7219 if (r.task.taskId == task) {
7220 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7221 mHistory.remove(pos);
7222 mHistory.add(bottom, r);
7223 moved.add(r);
7224 bottom++;
7225 }
7226 pos++;
7227 }
7228
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007229 if (reason != null &&
7230 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7231 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7232 HistoryRecord r = topRunningActivityLocked(null);
7233 if (r != null) {
7234 mNoAnimActivities.add(r);
7235 }
7236 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007237 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007239 mWindowManager.moveAppTokensToBottom(moved);
7240 if (VALIDATE_TOKENS) {
7241 mWindowManager.validateAppTokens(mHistory);
7242 }
7243
7244 finishTaskMove(task);
7245 return true;
7246 }
7247
7248 public void moveTaskBackwards(int task) {
7249 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7250 "moveTaskBackwards()");
7251
7252 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007253 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7254 Binder.getCallingUid(), "Task backwards")) {
7255 return;
7256 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007257 final long origId = Binder.clearCallingIdentity();
7258 moveTaskBackwardsLocked(task);
7259 Binder.restoreCallingIdentity(origId);
7260 }
7261 }
7262
7263 private final void moveTaskBackwardsLocked(int task) {
7264 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7265 }
7266
7267 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7268 synchronized(this) {
7269 return getTaskForActivityLocked(token, onlyRoot);
7270 }
7271 }
7272
7273 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7274 final int N = mHistory.size();
7275 TaskRecord lastTask = null;
7276 for (int i=0; i<N; i++) {
7277 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7278 if (r == token) {
7279 if (!onlyRoot || lastTask != r.task) {
7280 return r.task.taskId;
7281 }
7282 return -1;
7283 }
7284 lastTask = r.task;
7285 }
7286
7287 return -1;
7288 }
7289
7290 /**
7291 * Returns the top activity in any existing task matching the given
7292 * Intent. Returns null if no such task is found.
7293 */
7294 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7295 ComponentName cls = intent.getComponent();
7296 if (info.targetActivity != null) {
7297 cls = new ComponentName(info.packageName, info.targetActivity);
7298 }
7299
7300 TaskRecord cp = null;
7301
7302 final int N = mHistory.size();
7303 for (int i=(N-1); i>=0; i--) {
7304 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7305 if (!r.finishing && r.task != cp
7306 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7307 cp = r.task;
7308 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7309 // + "/aff=" + r.task.affinity + " to new cls="
7310 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7311 if (r.task.affinity != null) {
7312 if (r.task.affinity.equals(info.taskAffinity)) {
7313 //Log.i(TAG, "Found matching affinity!");
7314 return r;
7315 }
7316 } else if (r.task.intent != null
7317 && r.task.intent.getComponent().equals(cls)) {
7318 //Log.i(TAG, "Found matching class!");
7319 //dump();
7320 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7321 return r;
7322 } else if (r.task.affinityIntent != null
7323 && r.task.affinityIntent.getComponent().equals(cls)) {
7324 //Log.i(TAG, "Found matching class!");
7325 //dump();
7326 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7327 return r;
7328 }
7329 }
7330 }
7331
7332 return null;
7333 }
7334
7335 /**
7336 * Returns the first activity (starting from the top of the stack) that
7337 * is the same as the given activity. Returns null if no such activity
7338 * is found.
7339 */
7340 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7341 ComponentName cls = intent.getComponent();
7342 if (info.targetActivity != null) {
7343 cls = new ComponentName(info.packageName, info.targetActivity);
7344 }
7345
7346 final int N = mHistory.size();
7347 for (int i=(N-1); i>=0; i--) {
7348 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7349 if (!r.finishing) {
7350 if (r.intent.getComponent().equals(cls)) {
7351 //Log.i(TAG, "Found matching class!");
7352 //dump();
7353 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7354 return r;
7355 }
7356 }
7357 }
7358
7359 return null;
7360 }
7361
7362 public void finishOtherInstances(IBinder token, ComponentName className) {
7363 synchronized(this) {
7364 final long origId = Binder.clearCallingIdentity();
7365
7366 int N = mHistory.size();
7367 TaskRecord lastTask = null;
7368 for (int i=0; i<N; i++) {
7369 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7370 if (r.realActivity.equals(className)
7371 && r != token && lastTask != r.task) {
7372 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7373 null, "others")) {
7374 i--;
7375 N--;
7376 }
7377 }
7378 lastTask = r.task;
7379 }
7380
7381 Binder.restoreCallingIdentity(origId);
7382 }
7383 }
7384
7385 // =========================================================
7386 // THUMBNAILS
7387 // =========================================================
7388
7389 public void reportThumbnail(IBinder token,
7390 Bitmap thumbnail, CharSequence description) {
7391 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7392 final long origId = Binder.clearCallingIdentity();
7393 sendPendingThumbnail(null, token, thumbnail, description, true);
7394 Binder.restoreCallingIdentity(origId);
7395 }
7396
7397 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7398 Bitmap thumbnail, CharSequence description, boolean always) {
7399 TaskRecord task = null;
7400 ArrayList receivers = null;
7401
7402 //System.out.println("Send pending thumbnail: " + r);
7403
7404 synchronized(this) {
7405 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007406 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007407 if (index < 0) {
7408 return;
7409 }
7410 r = (HistoryRecord)mHistory.get(index);
7411 }
7412 if (thumbnail == null) {
7413 thumbnail = r.thumbnail;
7414 description = r.description;
7415 }
7416 if (thumbnail == null && !always) {
7417 // If there is no thumbnail, and this entry is not actually
7418 // going away, then abort for now and pick up the next
7419 // thumbnail we get.
7420 return;
7421 }
7422 task = r.task;
7423
7424 int N = mPendingThumbnails.size();
7425 int i=0;
7426 while (i<N) {
7427 PendingThumbnailsRecord pr =
7428 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7429 //System.out.println("Looking in " + pr.pendingRecords);
7430 if (pr.pendingRecords.remove(r)) {
7431 if (receivers == null) {
7432 receivers = new ArrayList();
7433 }
7434 receivers.add(pr);
7435 if (pr.pendingRecords.size() == 0) {
7436 pr.finished = true;
7437 mPendingThumbnails.remove(i);
7438 N--;
7439 continue;
7440 }
7441 }
7442 i++;
7443 }
7444 }
7445
7446 if (receivers != null) {
7447 final int N = receivers.size();
7448 for (int i=0; i<N; i++) {
7449 try {
7450 PendingThumbnailsRecord pr =
7451 (PendingThumbnailsRecord)receivers.get(i);
7452 pr.receiver.newThumbnail(
7453 task != null ? task.taskId : -1, thumbnail, description);
7454 if (pr.finished) {
7455 pr.receiver.finished();
7456 }
7457 } catch (Exception e) {
7458 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7459 }
7460 }
7461 }
7462 }
7463
7464 // =========================================================
7465 // CONTENT PROVIDERS
7466 // =========================================================
7467
7468 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7469 List providers = null;
7470 try {
7471 providers = ActivityThread.getPackageManager().
7472 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007473 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007474 } catch (RemoteException ex) {
7475 }
7476 if (providers != null) {
7477 final int N = providers.size();
7478 for (int i=0; i<N; i++) {
7479 ProviderInfo cpi =
7480 (ProviderInfo)providers.get(i);
7481 ContentProviderRecord cpr =
7482 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7483 if (cpr == null) {
7484 cpr = new ContentProviderRecord(cpi, app.info);
7485 mProvidersByClass.put(cpi.name, cpr);
7486 }
7487 app.pubProviders.put(cpi.name, cpr);
7488 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007489 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007490 }
7491 }
7492 return providers;
7493 }
7494
7495 private final String checkContentProviderPermissionLocked(
7496 ProviderInfo cpi, ProcessRecord r, int mode) {
7497 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7498 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7499 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7500 cpi.exported ? -1 : cpi.applicationInfo.uid)
7501 == PackageManager.PERMISSION_GRANTED
7502 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7503 return null;
7504 }
7505 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7506 cpi.exported ? -1 : cpi.applicationInfo.uid)
7507 == PackageManager.PERMISSION_GRANTED) {
7508 return null;
7509 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007510
7511 PathPermission[] pps = cpi.pathPermissions;
7512 if (pps != null) {
7513 int i = pps.length;
7514 while (i > 0) {
7515 i--;
7516 PathPermission pp = pps[i];
7517 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7518 cpi.exported ? -1 : cpi.applicationInfo.uid)
7519 == PackageManager.PERMISSION_GRANTED
7520 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7521 return null;
7522 }
7523 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7524 cpi.exported ? -1 : cpi.applicationInfo.uid)
7525 == PackageManager.PERMISSION_GRANTED) {
7526 return null;
7527 }
7528 }
7529 }
7530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007531 String msg = "Permission Denial: opening provider " + cpi.name
7532 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7533 + ", uid=" + callingUid + ") requires "
7534 + cpi.readPermission + " or " + cpi.writePermission;
7535 Log.w(TAG, msg);
7536 return msg;
7537 }
7538
7539 private final ContentProviderHolder getContentProviderImpl(
7540 IApplicationThread caller, String name) {
7541 ContentProviderRecord cpr;
7542 ProviderInfo cpi = null;
7543
7544 synchronized(this) {
7545 ProcessRecord r = null;
7546 if (caller != null) {
7547 r = getRecordForAppLocked(caller);
7548 if (r == null) {
7549 throw new SecurityException(
7550 "Unable to find app for caller " + caller
7551 + " (pid=" + Binder.getCallingPid()
7552 + ") when getting content provider " + name);
7553 }
7554 }
7555
7556 // First check if this content provider has been published...
7557 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7558 if (cpr != null) {
7559 cpi = cpr.info;
7560 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7561 return new ContentProviderHolder(cpi,
7562 cpi.readPermission != null
7563 ? cpi.readPermission : cpi.writePermission);
7564 }
7565
7566 if (r != null && cpr.canRunHere(r)) {
7567 // This provider has been published or is in the process
7568 // of being published... but it is also allowed to run
7569 // in the caller's process, so don't make a connection
7570 // and just let the caller instantiate its own instance.
7571 if (cpr.provider != null) {
7572 // don't give caller the provider object, it needs
7573 // to make its own.
7574 cpr = new ContentProviderRecord(cpr);
7575 }
7576 return cpr;
7577 }
7578
7579 final long origId = Binder.clearCallingIdentity();
7580
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007581 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007582 // return it right away.
7583 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007584 if (DEBUG_PROVIDER) Log.v(TAG,
7585 "Adding provider requested by "
7586 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007587 + cpr.info.processName);
7588 Integer cnt = r.conProviders.get(cpr);
7589 if (cnt == null) {
7590 r.conProviders.put(cpr, new Integer(1));
7591 } else {
7592 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7593 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007594 cpr.clients.add(r);
7595 } else {
7596 cpr.externals++;
7597 }
7598
7599 if (cpr.app != null) {
7600 updateOomAdjLocked(cpr.app);
7601 }
7602
7603 Binder.restoreCallingIdentity(origId);
7604
7605 } else {
7606 try {
7607 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007608 resolveContentProvider(name,
7609 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007610 } catch (RemoteException ex) {
7611 }
7612 if (cpi == null) {
7613 return null;
7614 }
7615
7616 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7617 return new ContentProviderHolder(cpi,
7618 cpi.readPermission != null
7619 ? cpi.readPermission : cpi.writePermission);
7620 }
7621
7622 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7623 final boolean firstClass = cpr == null;
7624 if (firstClass) {
7625 try {
7626 ApplicationInfo ai =
7627 ActivityThread.getPackageManager().
7628 getApplicationInfo(
7629 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007630 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007631 if (ai == null) {
7632 Log.w(TAG, "No package info for content provider "
7633 + cpi.name);
7634 return null;
7635 }
7636 cpr = new ContentProviderRecord(cpi, ai);
7637 } catch (RemoteException ex) {
7638 // pm is in same process, this will never happen.
7639 }
7640 }
7641
7642 if (r != null && cpr.canRunHere(r)) {
7643 // If this is a multiprocess provider, then just return its
7644 // info and allow the caller to instantiate it. Only do
7645 // this if the provider is the same user as the caller's
7646 // process, or can run as root (so can be in any process).
7647 return cpr;
7648 }
7649
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007650 if (DEBUG_PROVIDER) {
7651 RuntimeException e = new RuntimeException("here");
7652 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7653 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007654 }
7655
7656 // This is single process, and our app is now connecting to it.
7657 // See if we are already in the process of launching this
7658 // provider.
7659 final int N = mLaunchingProviders.size();
7660 int i;
7661 for (i=0; i<N; i++) {
7662 if (mLaunchingProviders.get(i) == cpr) {
7663 break;
7664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007665 }
7666
7667 // If the provider is not already being launched, then get it
7668 // started.
7669 if (i >= N) {
7670 final long origId = Binder.clearCallingIdentity();
7671 ProcessRecord proc = startProcessLocked(cpi.processName,
7672 cpr.appInfo, false, 0, "content provider",
7673 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007674 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007675 if (proc == null) {
7676 Log.w(TAG, "Unable to launch app "
7677 + cpi.applicationInfo.packageName + "/"
7678 + cpi.applicationInfo.uid + " for provider "
7679 + name + ": process is bad");
7680 return null;
7681 }
7682 cpr.launchingApp = proc;
7683 mLaunchingProviders.add(cpr);
7684 Binder.restoreCallingIdentity(origId);
7685 }
7686
7687 // Make sure the provider is published (the same provider class
7688 // may be published under multiple names).
7689 if (firstClass) {
7690 mProvidersByClass.put(cpi.name, cpr);
7691 }
7692 mProvidersByName.put(name, cpr);
7693
7694 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007695 if (DEBUG_PROVIDER) Log.v(TAG,
7696 "Adding provider requested by "
7697 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007698 + cpr.info.processName);
7699 Integer cnt = r.conProviders.get(cpr);
7700 if (cnt == null) {
7701 r.conProviders.put(cpr, new Integer(1));
7702 } else {
7703 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7704 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007705 cpr.clients.add(r);
7706 } else {
7707 cpr.externals++;
7708 }
7709 }
7710 }
7711
7712 // Wait for the provider to be published...
7713 synchronized (cpr) {
7714 while (cpr.provider == null) {
7715 if (cpr.launchingApp == null) {
7716 Log.w(TAG, "Unable to launch app "
7717 + cpi.applicationInfo.packageName + "/"
7718 + cpi.applicationInfo.uid + " for provider "
7719 + name + ": launching app became null");
7720 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7721 cpi.applicationInfo.packageName,
7722 cpi.applicationInfo.uid, name);
7723 return null;
7724 }
7725 try {
7726 cpr.wait();
7727 } catch (InterruptedException ex) {
7728 }
7729 }
7730 }
7731 return cpr;
7732 }
7733
7734 public final ContentProviderHolder getContentProvider(
7735 IApplicationThread caller, String name) {
7736 if (caller == null) {
7737 String msg = "null IApplicationThread when getting content provider "
7738 + name;
7739 Log.w(TAG, msg);
7740 throw new SecurityException(msg);
7741 }
7742
7743 return getContentProviderImpl(caller, name);
7744 }
7745
7746 private ContentProviderHolder getContentProviderExternal(String name) {
7747 return getContentProviderImpl(null, name);
7748 }
7749
7750 /**
7751 * Drop a content provider from a ProcessRecord's bookkeeping
7752 * @param cpr
7753 */
7754 public void removeContentProvider(IApplicationThread caller, String name) {
7755 synchronized (this) {
7756 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7757 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007758 // remove from mProvidersByClass
7759 if (DEBUG_PROVIDER) Log.v(TAG, name +
7760 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007761 return;
7762 }
7763 final ProcessRecord r = getRecordForAppLocked(caller);
7764 if (r == null) {
7765 throw new SecurityException(
7766 "Unable to find app for caller " + caller +
7767 " when removing content provider " + name);
7768 }
7769 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007770 ContentProviderRecord localCpr = (ContentProviderRecord)
7771 mProvidersByClass.get(cpr.info.name);
7772 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7773 + r.info.processName + " from process "
7774 + localCpr.appInfo.processName);
7775 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007776 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007777 Log.w(TAG, "removeContentProvider called on local provider: "
7778 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007779 return;
7780 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007781 Integer cnt = r.conProviders.get(localCpr);
7782 if (cnt == null || cnt.intValue() <= 1) {
7783 localCpr.clients.remove(r);
7784 r.conProviders.remove(localCpr);
7785 } else {
7786 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7787 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007788 }
7789 updateOomAdjLocked();
7790 }
7791 }
7792
7793 private void removeContentProviderExternal(String name) {
7794 synchronized (this) {
7795 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7796 if(cpr == null) {
7797 //remove from mProvidersByClass
7798 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7799 return;
7800 }
7801
7802 //update content provider record entry info
7803 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7804 localCpr.externals--;
7805 if (localCpr.externals < 0) {
7806 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7807 }
7808 updateOomAdjLocked();
7809 }
7810 }
7811
7812 public final void publishContentProviders(IApplicationThread caller,
7813 List<ContentProviderHolder> providers) {
7814 if (providers == null) {
7815 return;
7816 }
7817
7818 synchronized(this) {
7819 final ProcessRecord r = getRecordForAppLocked(caller);
7820 if (r == null) {
7821 throw new SecurityException(
7822 "Unable to find app for caller " + caller
7823 + " (pid=" + Binder.getCallingPid()
7824 + ") when publishing content providers");
7825 }
7826
7827 final long origId = Binder.clearCallingIdentity();
7828
7829 final int N = providers.size();
7830 for (int i=0; i<N; i++) {
7831 ContentProviderHolder src = providers.get(i);
7832 if (src == null || src.info == null || src.provider == null) {
7833 continue;
7834 }
7835 ContentProviderRecord dst =
7836 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7837 if (dst != null) {
7838 mProvidersByClass.put(dst.info.name, dst);
7839 String names[] = dst.info.authority.split(";");
7840 for (int j = 0; j < names.length; j++) {
7841 mProvidersByName.put(names[j], dst);
7842 }
7843
7844 int NL = mLaunchingProviders.size();
7845 int j;
7846 for (j=0; j<NL; j++) {
7847 if (mLaunchingProviders.get(j) == dst) {
7848 mLaunchingProviders.remove(j);
7849 j--;
7850 NL--;
7851 }
7852 }
7853 synchronized (dst) {
7854 dst.provider = src.provider;
7855 dst.app = r;
7856 dst.notifyAll();
7857 }
7858 updateOomAdjLocked(r);
7859 }
7860 }
7861
7862 Binder.restoreCallingIdentity(origId);
7863 }
7864 }
7865
7866 public static final void installSystemProviders() {
7867 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7868 List providers = mSelf.generateApplicationProvidersLocked(app);
7869 mSystemThread.installSystemProviders(providers);
7870 }
7871
7872 // =========================================================
7873 // GLOBAL MANAGEMENT
7874 // =========================================================
7875
7876 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7877 ApplicationInfo info, String customProcess) {
7878 String proc = customProcess != null ? customProcess : info.processName;
7879 BatteryStatsImpl.Uid.Proc ps = null;
7880 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7881 synchronized (stats) {
7882 ps = stats.getProcessStatsLocked(info.uid, proc);
7883 }
7884 return new ProcessRecord(ps, thread, info, proc);
7885 }
7886
7887 final ProcessRecord addAppLocked(ApplicationInfo info) {
7888 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7889
7890 if (app == null) {
7891 app = newProcessRecordLocked(null, info, null);
7892 mProcessNames.put(info.processName, info.uid, app);
7893 updateLRUListLocked(app, true);
7894 }
7895
7896 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7897 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7898 app.persistent = true;
7899 app.maxAdj = CORE_SERVER_ADJ;
7900 }
7901 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7902 mPersistentStartingProcesses.add(app);
7903 startProcessLocked(app, "added application", app.processName);
7904 }
7905
7906 return app;
7907 }
7908
7909 public void unhandledBack() {
7910 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7911 "unhandledBack()");
7912
7913 synchronized(this) {
7914 int count = mHistory.size();
7915 if (Config.LOGD) Log.d(
7916 TAG, "Performing unhandledBack(): stack size = " + count);
7917 if (count > 1) {
7918 final long origId = Binder.clearCallingIdentity();
7919 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7920 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7921 Binder.restoreCallingIdentity(origId);
7922 }
7923 }
7924 }
7925
7926 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7927 String name = uri.getAuthority();
7928 ContentProviderHolder cph = getContentProviderExternal(name);
7929 ParcelFileDescriptor pfd = null;
7930 if (cph != null) {
7931 // We record the binder invoker's uid in thread-local storage before
7932 // going to the content provider to open the file. Later, in the code
7933 // that handles all permissions checks, we look for this uid and use
7934 // that rather than the Activity Manager's own uid. The effect is that
7935 // we do the check against the caller's permissions even though it looks
7936 // to the content provider like the Activity Manager itself is making
7937 // the request.
7938 sCallerIdentity.set(new Identity(
7939 Binder.getCallingPid(), Binder.getCallingUid()));
7940 try {
7941 pfd = cph.provider.openFile(uri, "r");
7942 } catch (FileNotFoundException e) {
7943 // do nothing; pfd will be returned null
7944 } finally {
7945 // Ensure that whatever happens, we clean up the identity state
7946 sCallerIdentity.remove();
7947 }
7948
7949 // We've got the fd now, so we're done with the provider.
7950 removeContentProviderExternal(name);
7951 } else {
7952 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7953 }
7954 return pfd;
7955 }
7956
7957 public void goingToSleep() {
7958 synchronized(this) {
7959 mSleeping = true;
7960 mWindowManager.setEventDispatching(false);
7961
7962 if (mResumedActivity != null) {
7963 pauseIfSleepingLocked();
7964 } else {
7965 Log.w(TAG, "goingToSleep with no resumed activity!");
7966 }
7967 }
7968 }
7969
Dianne Hackborn55280a92009-05-07 15:53:46 -07007970 public boolean shutdown(int timeout) {
7971 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7972 != PackageManager.PERMISSION_GRANTED) {
7973 throw new SecurityException("Requires permission "
7974 + android.Manifest.permission.SHUTDOWN);
7975 }
7976
7977 boolean timedout = false;
7978
7979 synchronized(this) {
7980 mShuttingDown = true;
7981 mWindowManager.setEventDispatching(false);
7982
7983 if (mResumedActivity != null) {
7984 pauseIfSleepingLocked();
7985 final long endTime = System.currentTimeMillis() + timeout;
7986 while (mResumedActivity != null || mPausingActivity != null) {
7987 long delay = endTime - System.currentTimeMillis();
7988 if (delay <= 0) {
7989 Log.w(TAG, "Activity manager shutdown timed out");
7990 timedout = true;
7991 break;
7992 }
7993 try {
7994 this.wait();
7995 } catch (InterruptedException e) {
7996 }
7997 }
7998 }
7999 }
8000
8001 mUsageStatsService.shutdown();
8002 mBatteryStatsService.shutdown();
8003
8004 return timedout;
8005 }
8006
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008007 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07008008 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008009 if (!mGoingToSleep.isHeld()) {
8010 mGoingToSleep.acquire();
8011 if (mLaunchingActivity.isHeld()) {
8012 mLaunchingActivity.release();
8013 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
8014 }
8015 }
8016
8017 // If we are not currently pausing an activity, get the current
8018 // one to pause. If we are pausing one, we will just let that stuff
8019 // run and release the wake lock when all done.
8020 if (mPausingActivity == null) {
8021 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8022 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8023 startPausingLocked(false, true);
8024 }
8025 }
8026 }
8027
8028 public void wakingUp() {
8029 synchronized(this) {
8030 if (mGoingToSleep.isHeld()) {
8031 mGoingToSleep.release();
8032 }
8033 mWindowManager.setEventDispatching(true);
8034 mSleeping = false;
8035 resumeTopActivityLocked(null);
8036 }
8037 }
8038
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008039 public void stopAppSwitches() {
8040 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8041 != PackageManager.PERMISSION_GRANTED) {
8042 throw new SecurityException("Requires permission "
8043 + android.Manifest.permission.STOP_APP_SWITCHES);
8044 }
8045
8046 synchronized(this) {
8047 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8048 + APP_SWITCH_DELAY_TIME;
8049 mDidAppSwitch = false;
8050 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8051 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8052 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8053 }
8054 }
8055
8056 public void resumeAppSwitches() {
8057 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8058 != PackageManager.PERMISSION_GRANTED) {
8059 throw new SecurityException("Requires permission "
8060 + android.Manifest.permission.STOP_APP_SWITCHES);
8061 }
8062
8063 synchronized(this) {
8064 // Note that we don't execute any pending app switches... we will
8065 // let those wait until either the timeout, or the next start
8066 // activity request.
8067 mAppSwitchesAllowedTime = 0;
8068 }
8069 }
8070
8071 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8072 String name) {
8073 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8074 return true;
8075 }
8076
8077 final int perm = checkComponentPermission(
8078 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8079 callingUid, -1);
8080 if (perm == PackageManager.PERMISSION_GRANTED) {
8081 return true;
8082 }
8083
8084 Log.w(TAG, name + " request from " + callingUid + " stopped");
8085 return false;
8086 }
8087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008088 public void setDebugApp(String packageName, boolean waitForDebugger,
8089 boolean persistent) {
8090 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8091 "setDebugApp()");
8092
8093 // Note that this is not really thread safe if there are multiple
8094 // callers into it at the same time, but that's not a situation we
8095 // care about.
8096 if (persistent) {
8097 final ContentResolver resolver = mContext.getContentResolver();
8098 Settings.System.putString(
8099 resolver, Settings.System.DEBUG_APP,
8100 packageName);
8101 Settings.System.putInt(
8102 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8103 waitForDebugger ? 1 : 0);
8104 }
8105
8106 synchronized (this) {
8107 if (!persistent) {
8108 mOrigDebugApp = mDebugApp;
8109 mOrigWaitForDebugger = mWaitForDebugger;
8110 }
8111 mDebugApp = packageName;
8112 mWaitForDebugger = waitForDebugger;
8113 mDebugTransient = !persistent;
8114 if (packageName != null) {
8115 final long origId = Binder.clearCallingIdentity();
8116 uninstallPackageLocked(packageName, -1, false);
8117 Binder.restoreCallingIdentity(origId);
8118 }
8119 }
8120 }
8121
8122 public void setAlwaysFinish(boolean enabled) {
8123 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8124 "setAlwaysFinish()");
8125
8126 Settings.System.putInt(
8127 mContext.getContentResolver(),
8128 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8129
8130 synchronized (this) {
8131 mAlwaysFinishActivities = enabled;
8132 }
8133 }
8134
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008135 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008136 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008137 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008138 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008139 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008140 }
8141 }
8142
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008143 public void registerActivityWatcher(IActivityWatcher watcher) {
8144 mWatchers.register(watcher);
8145 }
8146
8147 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8148 mWatchers.unregister(watcher);
8149 }
8150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008151 public final void enterSafeMode() {
8152 synchronized(this) {
8153 // It only makes sense to do this before the system is ready
8154 // and started launching other packages.
8155 if (!mSystemReady) {
8156 try {
8157 ActivityThread.getPackageManager().enterSafeMode();
8158 } catch (RemoteException e) {
8159 }
8160
8161 View v = LayoutInflater.from(mContext).inflate(
8162 com.android.internal.R.layout.safe_mode, null);
8163 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8164 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8165 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8166 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8167 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8168 lp.format = v.getBackground().getOpacity();
8169 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8170 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8171 ((WindowManager)mContext.getSystemService(
8172 Context.WINDOW_SERVICE)).addView(v, lp);
8173 }
8174 }
8175 }
8176
8177 public void noteWakeupAlarm(IIntentSender sender) {
8178 if (!(sender instanceof PendingIntentRecord)) {
8179 return;
8180 }
8181 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8182 synchronized (stats) {
8183 if (mBatteryStatsService.isOnBattery()) {
8184 mBatteryStatsService.enforceCallingPermission();
8185 PendingIntentRecord rec = (PendingIntentRecord)sender;
8186 int MY_UID = Binder.getCallingUid();
8187 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8188 BatteryStatsImpl.Uid.Pkg pkg =
8189 stats.getPackageStatsLocked(uid, rec.key.packageName);
8190 pkg.incWakeupsLocked();
8191 }
8192 }
8193 }
8194
8195 public boolean killPidsForMemory(int[] pids) {
8196 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8197 throw new SecurityException("killPidsForMemory only available to the system");
8198 }
8199
8200 // XXX Note: don't acquire main activity lock here, because the window
8201 // manager calls in with its locks held.
8202
8203 boolean killed = false;
8204 synchronized (mPidsSelfLocked) {
8205 int[] types = new int[pids.length];
8206 int worstType = 0;
8207 for (int i=0; i<pids.length; i++) {
8208 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8209 if (proc != null) {
8210 int type = proc.setAdj;
8211 types[i] = type;
8212 if (type > worstType) {
8213 worstType = type;
8214 }
8215 }
8216 }
8217
8218 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8219 // then constrain it so we will kill all hidden procs.
8220 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8221 worstType = HIDDEN_APP_MIN_ADJ;
8222 }
8223 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8224 for (int i=0; i<pids.length; i++) {
8225 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8226 if (proc == null) {
8227 continue;
8228 }
8229 int adj = proc.setAdj;
8230 if (adj >= worstType) {
8231 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8232 + adj + ")");
8233 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8234 proc.processName, adj);
8235 killed = true;
8236 Process.killProcess(pids[i]);
8237 }
8238 }
8239 }
8240 return killed;
8241 }
8242
8243 public void reportPss(IApplicationThread caller, int pss) {
8244 Watchdog.PssRequestor req;
8245 String name;
8246 ProcessRecord callerApp;
8247 synchronized (this) {
8248 if (caller == null) {
8249 return;
8250 }
8251 callerApp = getRecordForAppLocked(caller);
8252 if (callerApp == null) {
8253 return;
8254 }
8255 callerApp.lastPss = pss;
8256 req = callerApp;
8257 name = callerApp.processName;
8258 }
8259 Watchdog.getInstance().reportPss(req, name, pss);
8260 if (!callerApp.persistent) {
8261 removeRequestedPss(callerApp);
8262 }
8263 }
8264
8265 public void requestPss(Runnable completeCallback) {
8266 ArrayList<ProcessRecord> procs;
8267 synchronized (this) {
8268 mRequestPssCallback = completeCallback;
8269 mRequestPssList.clear();
8270 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8271 ProcessRecord proc = mLRUProcesses.get(i);
8272 if (!proc.persistent) {
8273 mRequestPssList.add(proc);
8274 }
8275 }
8276 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8277 }
8278
8279 int oldPri = Process.getThreadPriority(Process.myTid());
8280 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8281 for (int i=procs.size()-1; i>=0; i--) {
8282 ProcessRecord proc = procs.get(i);
8283 proc.lastPss = 0;
8284 proc.requestPss();
8285 }
8286 Process.setThreadPriority(oldPri);
8287 }
8288
8289 void removeRequestedPss(ProcessRecord proc) {
8290 Runnable callback = null;
8291 synchronized (this) {
8292 if (mRequestPssList.remove(proc)) {
8293 if (mRequestPssList.size() == 0) {
8294 callback = mRequestPssCallback;
8295 mRequestPssCallback = null;
8296 }
8297 }
8298 }
8299
8300 if (callback != null) {
8301 callback.run();
8302 }
8303 }
8304
8305 public void collectPss(Watchdog.PssStats stats) {
8306 stats.mEmptyPss = 0;
8307 stats.mEmptyCount = 0;
8308 stats.mBackgroundPss = 0;
8309 stats.mBackgroundCount = 0;
8310 stats.mServicePss = 0;
8311 stats.mServiceCount = 0;
8312 stats.mVisiblePss = 0;
8313 stats.mVisibleCount = 0;
8314 stats.mForegroundPss = 0;
8315 stats.mForegroundCount = 0;
8316 stats.mNoPssCount = 0;
8317 synchronized (this) {
8318 int i;
8319 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8320 ? mProcDeaths.length : stats.mProcDeaths.length;
8321 int aggr = 0;
8322 for (i=0; i<NPD; i++) {
8323 aggr += mProcDeaths[i];
8324 stats.mProcDeaths[i] = aggr;
8325 }
8326 while (i<stats.mProcDeaths.length) {
8327 stats.mProcDeaths[i] = 0;
8328 i++;
8329 }
8330
8331 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8332 ProcessRecord proc = mLRUProcesses.get(i);
8333 if (proc.persistent) {
8334 continue;
8335 }
8336 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8337 if (proc.lastPss == 0) {
8338 stats.mNoPssCount++;
8339 continue;
8340 }
8341 if (proc.setAdj == EMPTY_APP_ADJ) {
8342 stats.mEmptyPss += proc.lastPss;
8343 stats.mEmptyCount++;
8344 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8345 stats.mEmptyPss += proc.lastPss;
8346 stats.mEmptyCount++;
8347 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8348 stats.mBackgroundPss += proc.lastPss;
8349 stats.mBackgroundCount++;
8350 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8351 stats.mVisiblePss += proc.lastPss;
8352 stats.mVisibleCount++;
8353 } else {
8354 stats.mForegroundPss += proc.lastPss;
8355 stats.mForegroundCount++;
8356 }
8357 }
8358 }
8359 }
8360
8361 public final void startRunning(String pkg, String cls, String action,
8362 String data) {
8363 synchronized(this) {
8364 if (mStartRunning) {
8365 return;
8366 }
8367 mStartRunning = true;
8368 mTopComponent = pkg != null && cls != null
8369 ? new ComponentName(pkg, cls) : null;
8370 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8371 mTopData = data;
8372 if (!mSystemReady) {
8373 return;
8374 }
8375 }
8376
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008377 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008378 }
8379
8380 private void retrieveSettings() {
8381 final ContentResolver resolver = mContext.getContentResolver();
8382 String debugApp = Settings.System.getString(
8383 resolver, Settings.System.DEBUG_APP);
8384 boolean waitForDebugger = Settings.System.getInt(
8385 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8386 boolean alwaysFinishActivities = Settings.System.getInt(
8387 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8388
8389 Configuration configuration = new Configuration();
8390 Settings.System.getConfiguration(resolver, configuration);
8391
8392 synchronized (this) {
8393 mDebugApp = mOrigDebugApp = debugApp;
8394 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8395 mAlwaysFinishActivities = alwaysFinishActivities;
8396 // This happens before any activities are started, so we can
8397 // change mConfiguration in-place.
8398 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008399 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008400 }
8401 }
8402
8403 public boolean testIsSystemReady() {
8404 // no need to synchronize(this) just to read & return the value
8405 return mSystemReady;
8406 }
8407
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008408 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008409 // In the simulator, startRunning will never have been called, which
8410 // normally sets a few crucial variables. Do it here instead.
8411 if (!Process.supportsProcesses()) {
8412 mStartRunning = true;
8413 mTopAction = Intent.ACTION_MAIN;
8414 }
8415
8416 synchronized(this) {
8417 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008418 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008419 return;
8420 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008421
8422 // Check to see if there are any update receivers to run.
8423 if (!mDidUpdate) {
8424 if (mWaitingUpdate) {
8425 return;
8426 }
8427 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8428 List<ResolveInfo> ris = null;
8429 try {
8430 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8431 intent, null, 0);
8432 } catch (RemoteException e) {
8433 }
8434 if (ris != null) {
8435 for (int i=ris.size()-1; i>=0; i--) {
8436 if ((ris.get(i).activityInfo.applicationInfo.flags
8437 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8438 ris.remove(i);
8439 }
8440 }
8441 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8442 for (int i=0; i<ris.size(); i++) {
8443 ActivityInfo ai = ris.get(i).activityInfo;
8444 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8445 IIntentReceiver finisher = null;
8446 if (i == 0) {
8447 finisher = new IIntentReceiver.Stub() {
8448 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008449 String data, Bundle extras, boolean ordered,
8450 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008451 throws RemoteException {
8452 synchronized (ActivityManagerService.this) {
8453 mDidUpdate = true;
8454 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008455 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008456 }
8457 };
8458 }
8459 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8460 broadcastIntentLocked(null, null, intent, null, finisher,
8461 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8462 if (i == 0) {
8463 mWaitingUpdate = true;
8464 }
8465 }
8466 }
8467 if (mWaitingUpdate) {
8468 return;
8469 }
8470 mDidUpdate = true;
8471 }
8472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008473 mSystemReady = true;
8474 if (!mStartRunning) {
8475 return;
8476 }
8477 }
8478
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008479 ArrayList<ProcessRecord> procsToKill = null;
8480 synchronized(mPidsSelfLocked) {
8481 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8482 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8483 if (!isAllowedWhileBooting(proc.info)){
8484 if (procsToKill == null) {
8485 procsToKill = new ArrayList<ProcessRecord>();
8486 }
8487 procsToKill.add(proc);
8488 }
8489 }
8490 }
8491
8492 if (procsToKill != null) {
8493 synchronized(this) {
8494 for (int i=procsToKill.size()-1; i>=0; i--) {
8495 ProcessRecord proc = procsToKill.get(i);
8496 Log.i(TAG, "Removing system update proc: " + proc);
8497 removeProcessLocked(proc, true);
8498 }
8499 }
8500 }
8501
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008502 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008503 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8504 SystemClock.uptimeMillis());
8505
8506 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008507 // Make sure we have no pre-ready processes sitting around.
8508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008509 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8510 ResolveInfo ri = mContext.getPackageManager()
8511 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008512 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008513 CharSequence errorMsg = null;
8514 if (ri != null) {
8515 ActivityInfo ai = ri.activityInfo;
8516 ApplicationInfo app = ai.applicationInfo;
8517 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8518 mTopAction = Intent.ACTION_FACTORY_TEST;
8519 mTopData = null;
8520 mTopComponent = new ComponentName(app.packageName,
8521 ai.name);
8522 } else {
8523 errorMsg = mContext.getResources().getText(
8524 com.android.internal.R.string.factorytest_not_system);
8525 }
8526 } else {
8527 errorMsg = mContext.getResources().getText(
8528 com.android.internal.R.string.factorytest_no_action);
8529 }
8530 if (errorMsg != null) {
8531 mTopAction = null;
8532 mTopData = null;
8533 mTopComponent = null;
8534 Message msg = Message.obtain();
8535 msg.what = SHOW_FACTORY_ERROR_MSG;
8536 msg.getData().putCharSequence("msg", errorMsg);
8537 mHandler.sendMessage(msg);
8538 }
8539 }
8540 }
8541
8542 retrieveSettings();
8543
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008544 if (goingCallback != null) goingCallback.run();
8545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008546 synchronized (this) {
8547 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8548 try {
8549 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008550 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008551 if (apps != null) {
8552 int N = apps.size();
8553 int i;
8554 for (i=0; i<N; i++) {
8555 ApplicationInfo info
8556 = (ApplicationInfo)apps.get(i);
8557 if (info != null &&
8558 !info.packageName.equals("android")) {
8559 addAppLocked(info);
8560 }
8561 }
8562 }
8563 } catch (RemoteException ex) {
8564 // pm is in same process, this will never happen.
8565 }
8566 }
8567
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008568 // Start up initial activity.
8569 mBooting = true;
8570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008571 try {
8572 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8573 Message msg = Message.obtain();
8574 msg.what = SHOW_UID_ERROR_MSG;
8575 mHandler.sendMessage(msg);
8576 }
8577 } catch (RemoteException e) {
8578 }
8579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008580 resumeTopActivityLocked(null);
8581 }
8582 }
8583
8584 boolean makeAppCrashingLocked(ProcessRecord app,
8585 String tag, String shortMsg, String longMsg, byte[] crashData) {
8586 app.crashing = true;
8587 app.crashingReport = generateProcessError(app,
8588 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8589 startAppProblemLocked(app);
8590 app.stopFreezingAllLocked();
8591 return handleAppCrashLocked(app);
8592 }
8593
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008594 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008595 // check if error reporting is enabled in Gservices
8596 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8597 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8598 if (enabled == 0) {
8599 return null;
8600 }
8601
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008602 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008603
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008604 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008605 // look for receiver in the installer package
8606 String candidate = pm.getInstallerPackageName(app.info.packageName);
8607 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8608 if (result != null) {
8609 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008610 }
8611
Jacek Surazski82a73df2009-06-17 14:33:18 +02008612 // if the error app is on the system image, look for system apps
8613 // error receiver
8614 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8615 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8616 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8617 if (result != null) {
8618 return result;
8619 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008620 }
8621
Jacek Surazski82a73df2009-06-17 14:33:18 +02008622 // if there is a default receiver, try that
8623 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8624 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008625 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008626 // should not happen
8627 Log.e(TAG, "error talking to PackageManager", e);
8628 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008629 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008630 }
8631
8632 /**
8633 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8634 *
8635 * @param pm PackageManager isntance
8636 * @param errorPackage package which caused the error
8637 * @param receiverPackage candidate package to receive the error
8638 * @return activity component within receiverPackage which handles
8639 * ACTION_APP_ERROR, or null if not found
8640 */
8641 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8642 String receiverPackage) throws RemoteException {
8643 if (receiverPackage == null || receiverPackage.length() == 0) {
8644 return null;
8645 }
8646
8647 // break the loop if it's the error report receiver package that crashed
8648 if (receiverPackage.equals(errorPackage)) {
8649 return null;
8650 }
8651
8652 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8653 intent.setPackage(receiverPackage);
8654 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8655 if (info == null || info.activityInfo == null) {
8656 return null;
8657 }
8658 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008659 }
8660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008661 void makeAppNotRespondingLocked(ProcessRecord app,
8662 String tag, String shortMsg, String longMsg, byte[] crashData) {
8663 app.notResponding = true;
8664 app.notRespondingReport = generateProcessError(app,
8665 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8666 crashData);
8667 startAppProblemLocked(app);
8668 app.stopFreezingAllLocked();
8669 }
8670
8671 /**
8672 * Generate a process error record, suitable for attachment to a ProcessRecord.
8673 *
8674 * @param app The ProcessRecord in which the error occurred.
8675 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8676 * ActivityManager.AppErrorStateInfo
8677 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8678 * @param shortMsg Short message describing the crash.
8679 * @param longMsg Long message describing the crash.
8680 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8681 *
8682 * @return Returns a fully-formed AppErrorStateInfo record.
8683 */
8684 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8685 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8686 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8687
8688 report.condition = condition;
8689 report.processName = app.processName;
8690 report.pid = app.pid;
8691 report.uid = app.info.uid;
8692 report.tag = tag;
8693 report.shortMsg = shortMsg;
8694 report.longMsg = longMsg;
8695 report.crashData = crashData;
8696
8697 return report;
8698 }
8699
8700 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8701 boolean crashed) {
8702 synchronized (this) {
8703 app.crashing = false;
8704 app.crashingReport = null;
8705 app.notResponding = false;
8706 app.notRespondingReport = null;
8707 if (app.anrDialog == fromDialog) {
8708 app.anrDialog = null;
8709 }
8710 if (app.waitDialog == fromDialog) {
8711 app.waitDialog = null;
8712 }
8713 if (app.pid > 0 && app.pid != MY_PID) {
8714 if (crashed) {
8715 handleAppCrashLocked(app);
8716 }
8717 Log.i(ActivityManagerService.TAG, "Killing process "
8718 + app.processName
8719 + " (pid=" + app.pid + ") at user's request");
8720 Process.killProcess(app.pid);
8721 }
8722
8723 }
8724 }
8725
8726 boolean handleAppCrashLocked(ProcessRecord app) {
8727 long now = SystemClock.uptimeMillis();
8728
8729 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8730 app.info.uid);
8731 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8732 // This process loses!
8733 Log.w(TAG, "Process " + app.info.processName
8734 + " has crashed too many times: killing!");
8735 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8736 app.info.processName, app.info.uid);
8737 killServicesLocked(app, false);
8738 for (int i=mHistory.size()-1; i>=0; i--) {
8739 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8740 if (r.app == app) {
8741 if (Config.LOGD) Log.d(
8742 TAG, " Force finishing activity "
8743 + r.intent.getComponent().flattenToShortString());
8744 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8745 }
8746 }
8747 if (!app.persistent) {
8748 // We don't want to start this process again until the user
8749 // explicitly does so... but for persistent process, we really
8750 // need to keep it running. If a persistent process is actually
8751 // repeatedly crashing, then badness for everyone.
8752 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8753 app.info.processName);
8754 mBadProcesses.put(app.info.processName, app.info.uid, now);
8755 app.bad = true;
8756 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8757 app.removed = true;
8758 removeProcessLocked(app, false);
8759 return false;
8760 }
8761 }
8762
8763 // Bump up the crash count of any services currently running in the proc.
8764 if (app.services.size() != 0) {
8765 // Any services running in the application need to be placed
8766 // back in the pending list.
8767 Iterator it = app.services.iterator();
8768 while (it.hasNext()) {
8769 ServiceRecord sr = (ServiceRecord)it.next();
8770 sr.crashCount++;
8771 }
8772 }
8773
8774 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8775 return true;
8776 }
8777
8778 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008779 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008780 skipCurrentReceiverLocked(app);
8781 }
8782
8783 void skipCurrentReceiverLocked(ProcessRecord app) {
8784 boolean reschedule = false;
8785 BroadcastRecord r = app.curReceiver;
8786 if (r != null) {
8787 // The current broadcast is waiting for this app's receiver
8788 // to be finished. Looks like that's not going to happen, so
8789 // let the broadcast continue.
8790 logBroadcastReceiverDiscard(r);
8791 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8792 r.resultExtras, r.resultAbort, true);
8793 reschedule = true;
8794 }
8795 r = mPendingBroadcast;
8796 if (r != null && r.curApp == app) {
8797 if (DEBUG_BROADCAST) Log.v(TAG,
8798 "skip & discard pending app " + r);
8799 logBroadcastReceiverDiscard(r);
8800 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8801 r.resultExtras, r.resultAbort, true);
8802 reschedule = true;
8803 }
8804 if (reschedule) {
8805 scheduleBroadcastsLocked();
8806 }
8807 }
8808
8809 public int handleApplicationError(IBinder app, int flags,
8810 String tag, String shortMsg, String longMsg, byte[] crashData) {
8811 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008812 ProcessRecord r = null;
8813 synchronized (this) {
8814 if (app != null) {
8815 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8816 final int NA = apps.size();
8817 for (int ia=0; ia<NA; ia++) {
8818 ProcessRecord p = apps.valueAt(ia);
8819 if (p.thread != null && p.thread.asBinder() == app) {
8820 r = p;
8821 break;
8822 }
8823 }
8824 }
8825 }
8826
8827 if (r != null) {
8828 // The application has crashed. Send the SIGQUIT to the process so
8829 // that it can dump its state.
8830 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8831 //Log.i(TAG, "Current system threads:");
8832 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8833 }
8834
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008835 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008836 try {
8837 String name = r != null ? r.processName : null;
8838 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008839 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008840 shortMsg, longMsg, crashData)) {
8841 Log.w(TAG, "Force-killing crashed app " + name
8842 + " at watcher's request");
8843 Process.killProcess(pid);
8844 return 0;
8845 }
8846 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008847 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008848 }
8849 }
8850
8851 final long origId = Binder.clearCallingIdentity();
8852
8853 // If this process is running instrumentation, finish it.
8854 if (r != null && r.instrumentationClass != null) {
8855 Log.w(TAG, "Error in app " + r.processName
8856 + " running instrumentation " + r.instrumentationClass + ":");
8857 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8858 if (longMsg != null) Log.w(TAG, " " + longMsg);
8859 Bundle info = new Bundle();
8860 info.putString("shortMsg", shortMsg);
8861 info.putString("longMsg", longMsg);
8862 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8863 Binder.restoreCallingIdentity(origId);
8864 return 0;
8865 }
8866
8867 if (r != null) {
8868 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8869 return 0;
8870 }
8871 } else {
8872 Log.w(TAG, "Some application object " + app + " tag " + tag
8873 + " has crashed, but I don't know who it is.");
8874 Log.w(TAG, "ShortMsg:" + shortMsg);
8875 Log.w(TAG, "LongMsg:" + longMsg);
8876 Binder.restoreCallingIdentity(origId);
8877 return 0;
8878 }
8879
8880 Message msg = Message.obtain();
8881 msg.what = SHOW_ERROR_MSG;
8882 HashMap data = new HashMap();
8883 data.put("result", result);
8884 data.put("app", r);
8885 data.put("flags", flags);
8886 data.put("shortMsg", shortMsg);
8887 data.put("longMsg", longMsg);
8888 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8889 // For system processes, submit crash data to the server.
8890 data.put("crashData", crashData);
8891 }
8892 msg.obj = data;
8893 mHandler.sendMessage(msg);
8894
8895 Binder.restoreCallingIdentity(origId);
8896 }
8897
8898 int res = result.get();
8899
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008900 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008901 synchronized (this) {
8902 if (r != null) {
8903 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8904 SystemClock.uptimeMillis());
8905 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008906 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8907 appErrorIntent = createAppErrorIntentLocked(r);
8908 res = AppErrorDialog.FORCE_QUIT;
8909 }
8910 }
8911
8912 if (appErrorIntent != null) {
8913 try {
8914 mContext.startActivity(appErrorIntent);
8915 } catch (ActivityNotFoundException e) {
8916 Log.w(TAG, "bug report receiver dissappeared", e);
8917 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008918 }
8919
8920 return res;
8921 }
8922
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008923 Intent createAppErrorIntentLocked(ProcessRecord r) {
8924 ApplicationErrorReport report = createAppErrorReportLocked(r);
8925 if (report == null) {
8926 return null;
8927 }
8928 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8929 result.setComponent(r.errorReportReceiver);
8930 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8931 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8932 return result;
8933 }
8934
8935 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8936 if (r.errorReportReceiver == null) {
8937 return null;
8938 }
8939
8940 if (!r.crashing && !r.notResponding) {
8941 return null;
8942 }
8943
8944 try {
8945 ApplicationErrorReport report = new ApplicationErrorReport();
8946 report.packageName = r.info.packageName;
8947 report.installerPackageName = r.errorReportReceiver.getPackageName();
8948 report.processName = r.processName;
8949
8950 if (r.crashing) {
8951 report.type = ApplicationErrorReport.TYPE_CRASH;
8952 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8953
8954 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8955 r.crashingReport.crashData);
8956 DataInputStream dataStream = new DataInputStream(byteStream);
8957 CrashData crashData = new CrashData(dataStream);
8958 ThrowableData throwData = crashData.getThrowableData();
8959
8960 report.time = crashData.getTime();
8961 report.crashInfo.stackTrace = throwData.toString();
8962
Jacek Surazskif829a782009-06-11 22:47:02 +02008963 // Extract the source of the exception, useful for report
8964 // clustering. Also extract the "deepest" non-null exception
8965 // message.
8966 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008967 while (throwData.getCause() != null) {
8968 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008969 String msg = throwData.getMessage();
8970 if (msg != null && msg.length() > 0) {
8971 exceptionMessage = msg;
8972 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008973 }
8974 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008975 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008976 report.crashInfo.exceptionClassName = throwData.getType();
8977 report.crashInfo.throwFileName = trace.getFileName();
8978 report.crashInfo.throwClassName = trace.getClassName();
8979 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008980 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008981 } else if (r.notResponding) {
8982 report.type = ApplicationErrorReport.TYPE_ANR;
8983 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8984
8985 report.anrInfo.activity = r.notRespondingReport.tag;
8986 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8987 report.anrInfo.info = r.notRespondingReport.longMsg;
8988 }
8989
8990 return report;
8991 } catch (IOException e) {
8992 // we don't send it
8993 }
8994
8995 return null;
8996 }
8997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008998 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8999 // assume our apps are happy - lazy create the list
9000 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9001
9002 synchronized (this) {
9003
9004 // iterate across all processes
9005 final int N = mLRUProcesses.size();
9006 for (int i = 0; i < N; i++) {
9007 ProcessRecord app = mLRUProcesses.get(i);
9008 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9009 // This one's in trouble, so we'll generate a report for it
9010 // crashes are higher priority (in case there's a crash *and* an anr)
9011 ActivityManager.ProcessErrorStateInfo report = null;
9012 if (app.crashing) {
9013 report = app.crashingReport;
9014 } else if (app.notResponding) {
9015 report = app.notRespondingReport;
9016 }
9017
9018 if (report != null) {
9019 if (errList == null) {
9020 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9021 }
9022 errList.add(report);
9023 } else {
9024 Log.w(TAG, "Missing app error report, app = " + app.processName +
9025 " crashing = " + app.crashing +
9026 " notResponding = " + app.notResponding);
9027 }
9028 }
9029 }
9030 }
9031
9032 return errList;
9033 }
9034
9035 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9036 // Lazy instantiation of list
9037 List<ActivityManager.RunningAppProcessInfo> runList = null;
9038 synchronized (this) {
9039 // Iterate across all processes
9040 final int N = mLRUProcesses.size();
9041 for (int i = 0; i < N; i++) {
9042 ProcessRecord app = mLRUProcesses.get(i);
9043 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9044 // Generate process state info for running application
9045 ActivityManager.RunningAppProcessInfo currApp =
9046 new ActivityManager.RunningAppProcessInfo(app.processName,
9047 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009048 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009049 int adj = app.curAdj;
9050 if (adj >= CONTENT_PROVIDER_ADJ) {
9051 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9052 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9053 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009054 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9055 } else if (adj >= HOME_APP_ADJ) {
9056 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9057 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009058 } else if (adj >= SECONDARY_SERVER_ADJ) {
9059 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9060 } else if (adj >= VISIBLE_APP_ADJ) {
9061 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9062 } else {
9063 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9064 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009065 currApp.importanceReasonCode = app.adjTypeCode;
9066 if (app.adjSource instanceof ProcessRecord) {
9067 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9068 } else if (app.adjSource instanceof HistoryRecord) {
9069 HistoryRecord r = (HistoryRecord)app.adjSource;
9070 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9071 }
9072 if (app.adjTarget instanceof ComponentName) {
9073 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009075 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9076 // + " lru=" + currApp.lru);
9077 if (runList == null) {
9078 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9079 }
9080 runList.add(currApp);
9081 }
9082 }
9083 }
9084 return runList;
9085 }
9086
9087 @Override
9088 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9089 synchronized (this) {
9090 if (checkCallingPermission(android.Manifest.permission.DUMP)
9091 != PackageManager.PERMISSION_GRANTED) {
9092 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9093 + Binder.getCallingPid()
9094 + ", uid=" + Binder.getCallingUid()
9095 + " without permission "
9096 + android.Manifest.permission.DUMP);
9097 return;
9098 }
9099 if (args.length != 0 && "service".equals(args[0])) {
9100 dumpService(fd, pw, args);
9101 return;
9102 }
9103 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009104 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009105 pw.println(" ");
9106 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009107 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009108 if (mWaitingVisibleActivities.size() > 0) {
9109 pw.println(" ");
9110 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009111 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009112 }
9113 if (mStoppingActivities.size() > 0) {
9114 pw.println(" ");
9115 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009116 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009117 }
9118 if (mFinishingActivities.size() > 0) {
9119 pw.println(" ");
9120 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009121 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009122 }
9123
9124 pw.println(" ");
9125 pw.println(" mPausingActivity: " + mPausingActivity);
9126 pw.println(" mResumedActivity: " + mResumedActivity);
9127 pw.println(" mFocusedActivity: " + mFocusedActivity);
9128 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9129
9130 if (mRecentTasks.size() > 0) {
9131 pw.println(" ");
9132 pw.println("Recent tasks in Current Activity Manager State:");
9133
9134 final int N = mRecentTasks.size();
9135 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009136 TaskRecord tr = mRecentTasks.get(i);
9137 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9138 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009139 mRecentTasks.get(i).dump(pw, " ");
9140 }
9141 }
9142
9143 pw.println(" ");
9144 pw.println(" mCurTask: " + mCurTask);
9145
9146 pw.println(" ");
9147 pw.println("Processes in Current Activity Manager State:");
9148
9149 boolean needSep = false;
9150 int numPers = 0;
9151
9152 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9153 final int NA = procs.size();
9154 for (int ia=0; ia<NA; ia++) {
9155 if (!needSep) {
9156 pw.println(" All known processes:");
9157 needSep = true;
9158 }
9159 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009160 pw.print(r.persistent ? " *PERS*" : " *APP*");
9161 pw.print(" UID "); pw.print(procs.keyAt(ia));
9162 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009163 r.dump(pw, " ");
9164 if (r.persistent) {
9165 numPers++;
9166 }
9167 }
9168 }
9169
9170 if (mLRUProcesses.size() > 0) {
9171 if (needSep) pw.println(" ");
9172 needSep = true;
9173 pw.println(" Running processes (most recent first):");
9174 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009175 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009176 needSep = true;
9177 }
9178
9179 synchronized (mPidsSelfLocked) {
9180 if (mPidsSelfLocked.size() > 0) {
9181 if (needSep) pw.println(" ");
9182 needSep = true;
9183 pw.println(" PID mappings:");
9184 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009185 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9186 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009187 }
9188 }
9189 }
9190
9191 if (mForegroundProcesses.size() > 0) {
9192 if (needSep) pw.println(" ");
9193 needSep = true;
9194 pw.println(" Foreground Processes:");
9195 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009196 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9197 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009198 }
9199 }
9200
9201 if (mPersistentStartingProcesses.size() > 0) {
9202 if (needSep) pw.println(" ");
9203 needSep = true;
9204 pw.println(" Persisent processes that are starting:");
9205 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009206 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009207 }
9208
9209 if (mStartingProcesses.size() > 0) {
9210 if (needSep) pw.println(" ");
9211 needSep = true;
9212 pw.println(" Processes that are starting:");
9213 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009214 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009215 }
9216
9217 if (mRemovedProcesses.size() > 0) {
9218 if (needSep) pw.println(" ");
9219 needSep = true;
9220 pw.println(" Processes that are being removed:");
9221 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009222 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009223 }
9224
9225 if (mProcessesOnHold.size() > 0) {
9226 if (needSep) pw.println(" ");
9227 needSep = true;
9228 pw.println(" Processes that are on old until the system is ready:");
9229 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009230 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009231 }
9232
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009233 if (mProcessesToGc.size() > 0) {
9234 if (needSep) pw.println(" ");
9235 needSep = true;
9236 pw.println(" Processes that are waiting to GC:");
9237 long now = SystemClock.uptimeMillis();
9238 for (int i=0; i<mProcessesToGc.size(); i++) {
9239 ProcessRecord proc = mProcessesToGc.get(i);
9240 pw.print(" Process "); pw.println(proc);
9241 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9242 pw.print(", last gced=");
9243 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009244 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009245 pw.print(now-proc.lastLowMemory);
9246 pw.println(" ms ago");
9247
9248 }
9249 }
9250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009251 if (mProcessCrashTimes.getMap().size() > 0) {
9252 if (needSep) pw.println(" ");
9253 needSep = true;
9254 pw.println(" Time since processes crashed:");
9255 long now = SystemClock.uptimeMillis();
9256 for (Map.Entry<String, SparseArray<Long>> procs
9257 : mProcessCrashTimes.getMap().entrySet()) {
9258 SparseArray<Long> uids = procs.getValue();
9259 final int N = uids.size();
9260 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009261 pw.print(" Process "); pw.print(procs.getKey());
9262 pw.print(" uid "); pw.print(uids.keyAt(i));
9263 pw.print(": last crashed ");
9264 pw.print((now-uids.valueAt(i)));
9265 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009266 }
9267 }
9268 }
9269
9270 if (mBadProcesses.getMap().size() > 0) {
9271 if (needSep) pw.println(" ");
9272 needSep = true;
9273 pw.println(" Bad processes:");
9274 for (Map.Entry<String, SparseArray<Long>> procs
9275 : mBadProcesses.getMap().entrySet()) {
9276 SparseArray<Long> uids = procs.getValue();
9277 final int N = uids.size();
9278 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009279 pw.print(" Bad process "); pw.print(procs.getKey());
9280 pw.print(" uid "); pw.print(uids.keyAt(i));
9281 pw.print(": crashed at time ");
9282 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009283 }
9284 }
9285 }
9286
9287 pw.println(" ");
9288 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009289 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009290 pw.println(" mConfiguration: " + mConfiguration);
9291 pw.println(" mStartRunning=" + mStartRunning
9292 + " mSystemReady=" + mSystemReady
9293 + " mBooting=" + mBooting
9294 + " mBooted=" + mBooted
9295 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009296 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009297 pw.println(" mGoingToSleep=" + mGoingToSleep);
9298 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9299 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9300 + " mDebugTransient=" + mDebugTransient
9301 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9302 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009303 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009304 }
9305 }
9306
9307 /**
9308 * There are three ways to call this:
9309 * - no service specified: dump all the services
9310 * - a flattened component name that matched an existing service was specified as the
9311 * first arg: dump that one service
9312 * - the first arg isn't the flattened component name of an existing service:
9313 * dump all services whose component contains the first arg as a substring
9314 */
9315 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9316 String[] newArgs;
9317 String componentNameString;
9318 ServiceRecord r;
9319 if (args.length == 1) {
9320 componentNameString = null;
9321 newArgs = EMPTY_STRING_ARRAY;
9322 r = null;
9323 } else {
9324 componentNameString = args[1];
9325 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9326 r = componentName != null ? mServices.get(componentName) : null;
9327 newArgs = new String[args.length - 2];
9328 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9329 }
9330
9331 if (r != null) {
9332 dumpService(fd, pw, r, newArgs);
9333 } else {
9334 for (ServiceRecord r1 : mServices.values()) {
9335 if (componentNameString == null
9336 || r1.name.flattenToString().contains(componentNameString)) {
9337 dumpService(fd, pw, r1, newArgs);
9338 }
9339 }
9340 }
9341 }
9342
9343 /**
9344 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9345 * there is a thread associated with the service.
9346 */
9347 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9348 pw.println(" Service " + r.name.flattenToString());
9349 if (r.app != null && r.app.thread != null) {
9350 try {
9351 // flush anything that is already in the PrintWriter since the thread is going
9352 // to write to the file descriptor directly
9353 pw.flush();
9354 r.app.thread.dumpService(fd, r, args);
9355 pw.print("\n");
9356 } catch (RemoteException e) {
9357 pw.println("got a RemoteException while dumping the service");
9358 }
9359 }
9360 }
9361
9362 void dumpBroadcasts(PrintWriter pw) {
9363 synchronized (this) {
9364 if (checkCallingPermission(android.Manifest.permission.DUMP)
9365 != PackageManager.PERMISSION_GRANTED) {
9366 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9367 + Binder.getCallingPid()
9368 + ", uid=" + Binder.getCallingUid()
9369 + " without permission "
9370 + android.Manifest.permission.DUMP);
9371 return;
9372 }
9373 pw.println("Broadcasts in Current Activity Manager State:");
9374
9375 if (mRegisteredReceivers.size() > 0) {
9376 pw.println(" ");
9377 pw.println(" Registered Receivers:");
9378 Iterator it = mRegisteredReceivers.values().iterator();
9379 while (it.hasNext()) {
9380 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009381 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009382 r.dump(pw, " ");
9383 }
9384 }
9385
9386 pw.println(" ");
9387 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009388 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009389
9390 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9391 || mPendingBroadcast != null) {
9392 if (mParallelBroadcasts.size() > 0) {
9393 pw.println(" ");
9394 pw.println(" Active broadcasts:");
9395 }
9396 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9397 pw.println(" Broadcast #" + i + ":");
9398 mParallelBroadcasts.get(i).dump(pw, " ");
9399 }
9400 if (mOrderedBroadcasts.size() > 0) {
9401 pw.println(" ");
9402 pw.println(" Active serialized broadcasts:");
9403 }
9404 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9405 pw.println(" Serialized Broadcast #" + i + ":");
9406 mOrderedBroadcasts.get(i).dump(pw, " ");
9407 }
9408 pw.println(" ");
9409 pw.println(" Pending broadcast:");
9410 if (mPendingBroadcast != null) {
9411 mPendingBroadcast.dump(pw, " ");
9412 } else {
9413 pw.println(" (null)");
9414 }
9415 }
9416
9417 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009418 pw.println(" Historical broadcasts:");
9419 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9420 BroadcastRecord r = mBroadcastHistory[i];
9421 if (r == null) {
9422 break;
9423 }
9424 pw.println(" Historical Broadcast #" + i + ":");
9425 r.dump(pw, " ");
9426 }
9427
9428 pw.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009429 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9430 if (mStickyBroadcasts != null) {
9431 pw.println(" ");
9432 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009433 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009434 for (Map.Entry<String, ArrayList<Intent>> ent
9435 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009436 pw.print(" * Sticky action "); pw.print(ent.getKey());
9437 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009438 ArrayList<Intent> intents = ent.getValue();
9439 final int N = intents.size();
9440 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009441 sb.setLength(0);
9442 sb.append(" Intent: ");
9443 intents.get(i).toShortString(sb, true, false);
9444 pw.println(sb.toString());
9445 Bundle bundle = intents.get(i).getExtras();
9446 if (bundle != null) {
9447 pw.print(" ");
9448 pw.println(bundle.toString());
9449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009450 }
9451 }
9452 }
9453
9454 pw.println(" ");
9455 pw.println(" mHandler:");
9456 mHandler.dump(new PrintWriterPrinter(pw), " ");
9457 }
9458 }
9459
9460 void dumpServices(PrintWriter pw) {
9461 synchronized (this) {
9462 if (checkCallingPermission(android.Manifest.permission.DUMP)
9463 != PackageManager.PERMISSION_GRANTED) {
9464 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9465 + Binder.getCallingPid()
9466 + ", uid=" + Binder.getCallingUid()
9467 + " without permission "
9468 + android.Manifest.permission.DUMP);
9469 return;
9470 }
9471 pw.println("Services in Current Activity Manager State:");
9472
9473 boolean needSep = false;
9474
9475 if (mServices.size() > 0) {
9476 pw.println(" Active services:");
9477 Iterator<ServiceRecord> it = mServices.values().iterator();
9478 while (it.hasNext()) {
9479 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009480 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009481 r.dump(pw, " ");
9482 }
9483 needSep = true;
9484 }
9485
9486 if (mPendingServices.size() > 0) {
9487 if (needSep) pw.println(" ");
9488 pw.println(" Pending services:");
9489 for (int i=0; i<mPendingServices.size(); i++) {
9490 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009491 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009492 r.dump(pw, " ");
9493 }
9494 needSep = true;
9495 }
9496
9497 if (mRestartingServices.size() > 0) {
9498 if (needSep) pw.println(" ");
9499 pw.println(" Restarting services:");
9500 for (int i=0; i<mRestartingServices.size(); i++) {
9501 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009502 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009503 r.dump(pw, " ");
9504 }
9505 needSep = true;
9506 }
9507
9508 if (mStoppingServices.size() > 0) {
9509 if (needSep) pw.println(" ");
9510 pw.println(" Stopping services:");
9511 for (int i=0; i<mStoppingServices.size(); i++) {
9512 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009513 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009514 r.dump(pw, " ");
9515 }
9516 needSep = true;
9517 }
9518
9519 if (mServiceConnections.size() > 0) {
9520 if (needSep) pw.println(" ");
9521 pw.println(" Connection bindings to services:");
9522 Iterator<ConnectionRecord> it
9523 = mServiceConnections.values().iterator();
9524 while (it.hasNext()) {
9525 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009526 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009527 r.dump(pw, " ");
9528 }
9529 }
9530 }
9531 }
9532
9533 void dumpProviders(PrintWriter pw) {
9534 synchronized (this) {
9535 if (checkCallingPermission(android.Manifest.permission.DUMP)
9536 != PackageManager.PERMISSION_GRANTED) {
9537 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9538 + Binder.getCallingPid()
9539 + ", uid=" + Binder.getCallingUid()
9540 + " without permission "
9541 + android.Manifest.permission.DUMP);
9542 return;
9543 }
9544
9545 pw.println("Content Providers in Current Activity Manager State:");
9546
9547 boolean needSep = false;
9548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009549 if (mProvidersByClass.size() > 0) {
9550 if (needSep) pw.println(" ");
9551 pw.println(" Published content providers (by class):");
9552 Iterator it = mProvidersByClass.entrySet().iterator();
9553 while (it.hasNext()) {
9554 Map.Entry e = (Map.Entry)it.next();
9555 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009556 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009557 r.dump(pw, " ");
9558 }
9559 needSep = true;
9560 }
9561
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009562 if (mProvidersByName.size() > 0) {
9563 pw.println(" ");
9564 pw.println(" Authority to provider mappings:");
9565 Iterator it = mProvidersByName.entrySet().iterator();
9566 while (it.hasNext()) {
9567 Map.Entry e = (Map.Entry)it.next();
9568 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9569 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9570 pw.println(r);
9571 }
9572 needSep = true;
9573 }
9574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009575 if (mLaunchingProviders.size() > 0) {
9576 if (needSep) pw.println(" ");
9577 pw.println(" Launching content providers:");
9578 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009579 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9580 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009581 }
9582 needSep = true;
9583 }
9584
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009585 if (mGrantedUriPermissions.size() > 0) {
9586 pw.println();
9587 pw.println("Granted Uri Permissions:");
9588 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9589 int uid = mGrantedUriPermissions.keyAt(i);
9590 HashMap<Uri, UriPermission> perms
9591 = mGrantedUriPermissions.valueAt(i);
9592 pw.print(" * UID "); pw.print(uid);
9593 pw.println(" holds:");
9594 for (UriPermission perm : perms.values()) {
9595 pw.print(" "); pw.println(perm);
9596 perm.dump(pw, " ");
9597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009598 }
9599 }
9600 }
9601 }
9602
9603 void dumpSenders(PrintWriter pw) {
9604 synchronized (this) {
9605 if (checkCallingPermission(android.Manifest.permission.DUMP)
9606 != PackageManager.PERMISSION_GRANTED) {
9607 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9608 + Binder.getCallingPid()
9609 + ", uid=" + Binder.getCallingUid()
9610 + " without permission "
9611 + android.Manifest.permission.DUMP);
9612 return;
9613 }
9614
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009615 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009616
9617 if (this.mIntentSenderRecords.size() > 0) {
9618 Iterator<WeakReference<PendingIntentRecord>> it
9619 = mIntentSenderRecords.values().iterator();
9620 while (it.hasNext()) {
9621 WeakReference<PendingIntentRecord> ref = it.next();
9622 PendingIntentRecord rec = ref != null ? ref.get(): null;
9623 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009624 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009625 rec.dump(pw, " ");
9626 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009627 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009628 }
9629 }
9630 }
9631 }
9632 }
9633
9634 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009635 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009636 TaskRecord lastTask = null;
9637 for (int i=list.size()-1; i>=0; i--) {
9638 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009639 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009640 if (lastTask != r.task) {
9641 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009642 pw.print(prefix);
9643 pw.print(full ? "* " : " ");
9644 pw.println(lastTask);
9645 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009646 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009648 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009649 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9650 pw.print(" #"); pw.print(i); pw.print(": ");
9651 pw.println(r);
9652 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009653 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009654 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009655 }
9656 }
9657
9658 private static final int dumpProcessList(PrintWriter pw, List list,
9659 String prefix, String normalLabel, String persistentLabel,
9660 boolean inclOomAdj) {
9661 int numPers = 0;
9662 for (int i=list.size()-1; i>=0; i--) {
9663 ProcessRecord r = (ProcessRecord)list.get(i);
9664 if (false) {
9665 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9666 + " #" + i + ":");
9667 r.dump(pw, prefix + " ");
9668 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009669 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009670 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009671 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9672 if (r.adjSource != null || r.adjTarget != null) {
9673 pw.println(prefix + " " + r.adjTarget
9674 + " used by " + r.adjSource);
9675 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009676 } else {
9677 pw.println(String.format("%s%s #%2d: %s",
9678 prefix, (r.persistent ? persistentLabel : normalLabel),
9679 i, r.toString()));
9680 }
9681 if (r.persistent) {
9682 numPers++;
9683 }
9684 }
9685 return numPers;
9686 }
9687
9688 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9689 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009690 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009691 long uptime = SystemClock.uptimeMillis();
9692 long realtime = SystemClock.elapsedRealtime();
9693
9694 if (isCheckinRequest) {
9695 // short checkin version
9696 pw.println(uptime + "," + realtime);
9697 pw.flush();
9698 } else {
9699 pw.println("Applications Memory Usage (kB):");
9700 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9701 }
9702 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9703 ProcessRecord r = (ProcessRecord)list.get(i);
9704 if (r.thread != null) {
9705 if (!isCheckinRequest) {
9706 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9707 pw.flush();
9708 }
9709 try {
9710 r.thread.asBinder().dump(fd, args);
9711 } catch (RemoteException e) {
9712 if (!isCheckinRequest) {
9713 pw.println("Got RemoteException!");
9714 pw.flush();
9715 }
9716 }
9717 }
9718 }
9719 }
9720
9721 /**
9722 * Searches array of arguments for the specified string
9723 * @param args array of argument strings
9724 * @param value value to search for
9725 * @return true if the value is contained in the array
9726 */
9727 private static boolean scanArgs(String[] args, String value) {
9728 if (args != null) {
9729 for (String arg : args) {
9730 if (value.equals(arg)) {
9731 return true;
9732 }
9733 }
9734 }
9735 return false;
9736 }
9737
Dianne Hackborn75b03852009-06-12 15:43:26 -07009738 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009739 int count = mHistory.size();
9740
9741 // convert the token to an entry in the history.
9742 HistoryRecord r = null;
9743 int index = -1;
9744 for (int i=count-1; i>=0; i--) {
9745 Object o = mHistory.get(i);
9746 if (o == token) {
9747 r = (HistoryRecord)o;
9748 index = i;
9749 break;
9750 }
9751 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009752
9753 return index;
9754 }
9755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009756 private final void killServicesLocked(ProcessRecord app,
9757 boolean allowRestart) {
9758 // Report disconnected services.
9759 if (false) {
9760 // XXX we are letting the client link to the service for
9761 // death notifications.
9762 if (app.services.size() > 0) {
9763 Iterator it = app.services.iterator();
9764 while (it.hasNext()) {
9765 ServiceRecord r = (ServiceRecord)it.next();
9766 if (r.connections.size() > 0) {
9767 Iterator<ConnectionRecord> jt
9768 = r.connections.values().iterator();
9769 while (jt.hasNext()) {
9770 ConnectionRecord c = jt.next();
9771 if (c.binding.client != app) {
9772 try {
9773 //c.conn.connected(r.className, null);
9774 } catch (Exception e) {
9775 // todo: this should be asynchronous!
9776 Log.w(TAG, "Exception thrown disconnected servce "
9777 + r.shortName
9778 + " from app " + app.processName, e);
9779 }
9780 }
9781 }
9782 }
9783 }
9784 }
9785 }
9786
9787 // Clean up any connections this application has to other services.
9788 if (app.connections.size() > 0) {
9789 Iterator<ConnectionRecord> it = app.connections.iterator();
9790 while (it.hasNext()) {
9791 ConnectionRecord r = it.next();
9792 removeConnectionLocked(r, app, null);
9793 }
9794 }
9795 app.connections.clear();
9796
9797 if (app.services.size() != 0) {
9798 // Any services running in the application need to be placed
9799 // back in the pending list.
9800 Iterator it = app.services.iterator();
9801 while (it.hasNext()) {
9802 ServiceRecord sr = (ServiceRecord)it.next();
9803 synchronized (sr.stats.getBatteryStats()) {
9804 sr.stats.stopLaunchedLocked();
9805 }
9806 sr.app = null;
9807 sr.executeNesting = 0;
9808 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009809
9810 boolean hasClients = sr.bindings.size() > 0;
9811 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009812 Iterator<IntentBindRecord> bindings
9813 = sr.bindings.values().iterator();
9814 while (bindings.hasNext()) {
9815 IntentBindRecord b = bindings.next();
9816 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9817 + ": shouldUnbind=" + b.hasBound);
9818 b.binder = null;
9819 b.requested = b.received = b.hasBound = false;
9820 }
9821 }
9822
9823 if (sr.crashCount >= 2) {
9824 Log.w(TAG, "Service crashed " + sr.crashCount
9825 + " times, stopping: " + sr);
9826 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9827 sr.crashCount, sr.shortName, app.pid);
9828 bringDownServiceLocked(sr, true);
9829 } else if (!allowRestart) {
9830 bringDownServiceLocked(sr, true);
9831 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009832 boolean canceled = scheduleServiceRestartLocked(sr, true);
9833
9834 // Should the service remain running? Note that in the
9835 // extreme case of so many attempts to deliver a command
9836 // that it failed, that we also will stop it here.
9837 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9838 if (sr.pendingStarts.size() == 0) {
9839 sr.startRequested = false;
9840 if (!hasClients) {
9841 // Whoops, no reason to restart!
9842 bringDownServiceLocked(sr, true);
9843 }
9844 }
9845 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009846 }
9847 }
9848
9849 if (!allowRestart) {
9850 app.services.clear();
9851 }
9852 }
9853
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009854 // Make sure we have no more records on the stopping list.
9855 int i = mStoppingServices.size();
9856 while (i > 0) {
9857 i--;
9858 ServiceRecord sr = mStoppingServices.get(i);
9859 if (sr.app == app) {
9860 mStoppingServices.remove(i);
9861 }
9862 }
9863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009864 app.executingServices.clear();
9865 }
9866
9867 private final void removeDyingProviderLocked(ProcessRecord proc,
9868 ContentProviderRecord cpr) {
9869 synchronized (cpr) {
9870 cpr.launchingApp = null;
9871 cpr.notifyAll();
9872 }
9873
9874 mProvidersByClass.remove(cpr.info.name);
9875 String names[] = cpr.info.authority.split(";");
9876 for (int j = 0; j < names.length; j++) {
9877 mProvidersByName.remove(names[j]);
9878 }
9879
9880 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9881 while (cit.hasNext()) {
9882 ProcessRecord capp = cit.next();
9883 if (!capp.persistent && capp.thread != null
9884 && capp.pid != 0
9885 && capp.pid != MY_PID) {
9886 Log.i(TAG, "Killing app " + capp.processName
9887 + " (pid " + capp.pid
9888 + ") because provider " + cpr.info.name
9889 + " is in dying process " + proc.processName);
9890 Process.killProcess(capp.pid);
9891 }
9892 }
9893
9894 mLaunchingProviders.remove(cpr);
9895 }
9896
9897 /**
9898 * Main code for cleaning up a process when it has gone away. This is
9899 * called both as a result of the process dying, or directly when stopping
9900 * a process when running in single process mode.
9901 */
9902 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9903 boolean restarting, int index) {
9904 if (index >= 0) {
9905 mLRUProcesses.remove(index);
9906 }
9907
Dianne Hackborn36124872009-10-08 16:22:03 -07009908 mProcessesToGc.remove(app);
9909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009910 // Dismiss any open dialogs.
9911 if (app.crashDialog != null) {
9912 app.crashDialog.dismiss();
9913 app.crashDialog = null;
9914 }
9915 if (app.anrDialog != null) {
9916 app.anrDialog.dismiss();
9917 app.anrDialog = null;
9918 }
9919 if (app.waitDialog != null) {
9920 app.waitDialog.dismiss();
9921 app.waitDialog = null;
9922 }
9923
9924 app.crashing = false;
9925 app.notResponding = false;
9926
9927 app.resetPackageList();
9928 app.thread = null;
9929 app.forcingToForeground = null;
9930 app.foregroundServices = false;
9931
9932 killServicesLocked(app, true);
9933
9934 boolean restart = false;
9935
9936 int NL = mLaunchingProviders.size();
9937
9938 // Remove published content providers.
9939 if (!app.pubProviders.isEmpty()) {
9940 Iterator it = app.pubProviders.values().iterator();
9941 while (it.hasNext()) {
9942 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9943 cpr.provider = null;
9944 cpr.app = null;
9945
9946 // See if someone is waiting for this provider... in which
9947 // case we don't remove it, but just let it restart.
9948 int i = 0;
9949 if (!app.bad) {
9950 for (; i<NL; i++) {
9951 if (mLaunchingProviders.get(i) == cpr) {
9952 restart = true;
9953 break;
9954 }
9955 }
9956 } else {
9957 i = NL;
9958 }
9959
9960 if (i >= NL) {
9961 removeDyingProviderLocked(app, cpr);
9962 NL = mLaunchingProviders.size();
9963 }
9964 }
9965 app.pubProviders.clear();
9966 }
9967
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009968 // Take care of any launching providers waiting for this process.
9969 if (checkAppInLaunchingProvidersLocked(app, false)) {
9970 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009971 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009972
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009973 // Unregister from connected content providers.
9974 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07009975 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009976 while (it.hasNext()) {
9977 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9978 cpr.clients.remove(app);
9979 }
9980 app.conProviders.clear();
9981 }
9982
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009983 // At this point there may be remaining entries in mLaunchingProviders
9984 // where we were the only one waiting, so they are no longer of use.
9985 // Look for these and clean up if found.
9986 // XXX Commented out for now. Trying to figure out a way to reproduce
9987 // the actual situation to identify what is actually going on.
9988 if (false) {
9989 for (int i=0; i<NL; i++) {
9990 ContentProviderRecord cpr = (ContentProviderRecord)
9991 mLaunchingProviders.get(i);
9992 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9993 synchronized (cpr) {
9994 cpr.launchingApp = null;
9995 cpr.notifyAll();
9996 }
9997 }
9998 }
9999 }
10000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010001 skipCurrentReceiverLocked(app);
10002
10003 // Unregister any receivers.
10004 if (app.receivers.size() > 0) {
10005 Iterator<ReceiverList> it = app.receivers.iterator();
10006 while (it.hasNext()) {
10007 removeReceiverLocked(it.next());
10008 }
10009 app.receivers.clear();
10010 }
10011
Christopher Tate181fafa2009-05-14 11:12:14 -070010012 // If the app is undergoing backup, tell the backup manager about it
10013 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10014 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10015 try {
10016 IBackupManager bm = IBackupManager.Stub.asInterface(
10017 ServiceManager.getService(Context.BACKUP_SERVICE));
10018 bm.agentDisconnected(app.info.packageName);
10019 } catch (RemoteException e) {
10020 // can't happen; backup manager is local
10021 }
10022 }
10023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010024 // If the caller is restarting this app, then leave it in its
10025 // current lists and let the caller take care of it.
10026 if (restarting) {
10027 return;
10028 }
10029
10030 if (!app.persistent) {
10031 if (DEBUG_PROCESSES) Log.v(TAG,
10032 "Removing non-persistent process during cleanup: " + app);
10033 mProcessNames.remove(app.processName, app.info.uid);
10034 } else if (!app.removed) {
10035 // This app is persistent, so we need to keep its record around.
10036 // If it is not already on the pending app list, add it there
10037 // and start a new process for it.
10038 app.thread = null;
10039 app.forcingToForeground = null;
10040 app.foregroundServices = false;
10041 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10042 mPersistentStartingProcesses.add(app);
10043 restart = true;
10044 }
10045 }
10046 mProcessesOnHold.remove(app);
10047
The Android Open Source Project4df24232009-03-05 14:34:35 -080010048 if (app == mHomeProcess) {
10049 mHomeProcess = null;
10050 }
10051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010052 if (restart) {
10053 // We have components that still need to be running in the
10054 // process, so re-launch it.
10055 mProcessNames.put(app.processName, app.info.uid, app);
10056 startProcessLocked(app, "restart", app.processName);
10057 } else if (app.pid > 0 && app.pid != MY_PID) {
10058 // Goodbye!
10059 synchronized (mPidsSelfLocked) {
10060 mPidsSelfLocked.remove(app.pid);
10061 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10062 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010063 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010064 }
10065 }
10066
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010067 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10068 // Look through the content providers we are waiting to have launched,
10069 // and if any run in this process then either schedule a restart of
10070 // the process or kill the client waiting for it if this process has
10071 // gone bad.
10072 int NL = mLaunchingProviders.size();
10073 boolean restart = false;
10074 for (int i=0; i<NL; i++) {
10075 ContentProviderRecord cpr = (ContentProviderRecord)
10076 mLaunchingProviders.get(i);
10077 if (cpr.launchingApp == app) {
10078 if (!alwaysBad && !app.bad) {
10079 restart = true;
10080 } else {
10081 removeDyingProviderLocked(app, cpr);
10082 NL = mLaunchingProviders.size();
10083 }
10084 }
10085 }
10086 return restart;
10087 }
10088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010089 // =========================================================
10090 // SERVICES
10091 // =========================================================
10092
10093 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10094 ActivityManager.RunningServiceInfo info =
10095 new ActivityManager.RunningServiceInfo();
10096 info.service = r.name;
10097 if (r.app != null) {
10098 info.pid = r.app.pid;
10099 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010100 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010101 info.process = r.processName;
10102 info.foreground = r.isForeground;
10103 info.activeSince = r.createTime;
10104 info.started = r.startRequested;
10105 info.clientCount = r.connections.size();
10106 info.crashCount = r.crashCount;
10107 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010108 if (r.isForeground) {
10109 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10110 }
10111 if (r.startRequested) {
10112 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10113 }
10114 if (r.app != null && r.app.pid == Process.myPid()) {
10115 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10116 }
10117 if (r.app != null && r.app.persistent) {
10118 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10119 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010120 for (ConnectionRecord conn : r.connections.values()) {
10121 if (conn.clientLabel != 0) {
10122 info.clientPackage = conn.binding.client.info.packageName;
10123 info.clientLabel = conn.clientLabel;
10124 break;
10125 }
10126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010127 return info;
10128 }
10129
10130 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10131 int flags) {
10132 synchronized (this) {
10133 ArrayList<ActivityManager.RunningServiceInfo> res
10134 = new ArrayList<ActivityManager.RunningServiceInfo>();
10135
10136 if (mServices.size() > 0) {
10137 Iterator<ServiceRecord> it = mServices.values().iterator();
10138 while (it.hasNext() && res.size() < maxNum) {
10139 res.add(makeRunningServiceInfoLocked(it.next()));
10140 }
10141 }
10142
10143 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10144 ServiceRecord r = mRestartingServices.get(i);
10145 ActivityManager.RunningServiceInfo info =
10146 makeRunningServiceInfoLocked(r);
10147 info.restarting = r.nextRestartTime;
10148 res.add(info);
10149 }
10150
10151 return res;
10152 }
10153 }
10154
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010155 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10156 synchronized (this) {
10157 ServiceRecord r = mServices.get(name);
10158 if (r != null) {
10159 for (ConnectionRecord conn : r.connections.values()) {
10160 if (conn.clientIntent != null) {
10161 return conn.clientIntent;
10162 }
10163 }
10164 }
10165 }
10166 return null;
10167 }
10168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010169 private final ServiceRecord findServiceLocked(ComponentName name,
10170 IBinder token) {
10171 ServiceRecord r = mServices.get(name);
10172 return r == token ? r : null;
10173 }
10174
10175 private final class ServiceLookupResult {
10176 final ServiceRecord record;
10177 final String permission;
10178
10179 ServiceLookupResult(ServiceRecord _record, String _permission) {
10180 record = _record;
10181 permission = _permission;
10182 }
10183 };
10184
10185 private ServiceLookupResult findServiceLocked(Intent service,
10186 String resolvedType) {
10187 ServiceRecord r = null;
10188 if (service.getComponent() != null) {
10189 r = mServices.get(service.getComponent());
10190 }
10191 if (r == null) {
10192 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10193 r = mServicesByIntent.get(filter);
10194 }
10195
10196 if (r == null) {
10197 try {
10198 ResolveInfo rInfo =
10199 ActivityThread.getPackageManager().resolveService(
10200 service, resolvedType, 0);
10201 ServiceInfo sInfo =
10202 rInfo != null ? rInfo.serviceInfo : null;
10203 if (sInfo == null) {
10204 return null;
10205 }
10206
10207 ComponentName name = new ComponentName(
10208 sInfo.applicationInfo.packageName, sInfo.name);
10209 r = mServices.get(name);
10210 } catch (RemoteException ex) {
10211 // pm is in same process, this will never happen.
10212 }
10213 }
10214 if (r != null) {
10215 int callingPid = Binder.getCallingPid();
10216 int callingUid = Binder.getCallingUid();
10217 if (checkComponentPermission(r.permission,
10218 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10219 != PackageManager.PERMISSION_GRANTED) {
10220 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10221 + " from pid=" + callingPid
10222 + ", uid=" + callingUid
10223 + " requires " + r.permission);
10224 return new ServiceLookupResult(null, r.permission);
10225 }
10226 return new ServiceLookupResult(r, null);
10227 }
10228 return null;
10229 }
10230
10231 private class ServiceRestarter implements Runnable {
10232 private ServiceRecord mService;
10233
10234 void setService(ServiceRecord service) {
10235 mService = service;
10236 }
10237
10238 public void run() {
10239 synchronized(ActivityManagerService.this) {
10240 performServiceRestartLocked(mService);
10241 }
10242 }
10243 }
10244
10245 private ServiceLookupResult retrieveServiceLocked(Intent service,
10246 String resolvedType, int callingPid, int callingUid) {
10247 ServiceRecord r = null;
10248 if (service.getComponent() != null) {
10249 r = mServices.get(service.getComponent());
10250 }
10251 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10252 r = mServicesByIntent.get(filter);
10253 if (r == null) {
10254 try {
10255 ResolveInfo rInfo =
10256 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010257 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010258 ServiceInfo sInfo =
10259 rInfo != null ? rInfo.serviceInfo : null;
10260 if (sInfo == null) {
10261 Log.w(TAG, "Unable to start service " + service +
10262 ": not found");
10263 return null;
10264 }
10265
10266 ComponentName name = new ComponentName(
10267 sInfo.applicationInfo.packageName, sInfo.name);
10268 r = mServices.get(name);
10269 if (r == null) {
10270 filter = new Intent.FilterComparison(service.cloneFilter());
10271 ServiceRestarter res = new ServiceRestarter();
10272 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10273 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10274 synchronized (stats) {
10275 ss = stats.getServiceStatsLocked(
10276 sInfo.applicationInfo.uid, sInfo.packageName,
10277 sInfo.name);
10278 }
10279 r = new ServiceRecord(ss, name, filter, sInfo, res);
10280 res.setService(r);
10281 mServices.put(name, r);
10282 mServicesByIntent.put(filter, r);
10283
10284 // Make sure this component isn't in the pending list.
10285 int N = mPendingServices.size();
10286 for (int i=0; i<N; i++) {
10287 ServiceRecord pr = mPendingServices.get(i);
10288 if (pr.name.equals(name)) {
10289 mPendingServices.remove(i);
10290 i--;
10291 N--;
10292 }
10293 }
10294 }
10295 } catch (RemoteException ex) {
10296 // pm is in same process, this will never happen.
10297 }
10298 }
10299 if (r != null) {
10300 if (checkComponentPermission(r.permission,
10301 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10302 != PackageManager.PERMISSION_GRANTED) {
10303 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10304 + " from pid=" + Binder.getCallingPid()
10305 + ", uid=" + Binder.getCallingUid()
10306 + " requires " + r.permission);
10307 return new ServiceLookupResult(null, r.permission);
10308 }
10309 return new ServiceLookupResult(r, null);
10310 }
10311 return null;
10312 }
10313
10314 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10315 long now = SystemClock.uptimeMillis();
10316 if (r.executeNesting == 0 && r.app != null) {
10317 if (r.app.executingServices.size() == 0) {
10318 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10319 msg.obj = r.app;
10320 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10321 }
10322 r.app.executingServices.add(r);
10323 }
10324 r.executeNesting++;
10325 r.executingStart = now;
10326 }
10327
10328 private final void sendServiceArgsLocked(ServiceRecord r,
10329 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010330 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010331 if (N == 0) {
10332 return;
10333 }
10334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010335 int i = 0;
10336 while (i < N) {
10337 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010338 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010339 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010340 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010341 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010342 // If somehow we got a dummy start at the front, then
10343 // just drop it here.
10344 i++;
10345 continue;
10346 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010347 bumpServiceExecutingLocked(r);
10348 if (!oomAdjusted) {
10349 oomAdjusted = true;
10350 updateOomAdjLocked(r.app);
10351 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010352 int flags = 0;
10353 if (si.deliveryCount > 0) {
10354 flags |= Service.START_FLAG_RETRY;
10355 }
10356 if (si.doneExecutingCount > 0) {
10357 flags |= Service.START_FLAG_REDELIVERY;
10358 }
10359 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10360 si.deliveredTime = SystemClock.uptimeMillis();
10361 r.deliveredStarts.add(si);
10362 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010363 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010364 } catch (RemoteException e) {
10365 // Remote process gone... we'll let the normal cleanup take
10366 // care of this.
10367 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010368 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010369 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010370 break;
10371 }
10372 }
10373 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010374 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010375 } else {
10376 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010377 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010378 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010379 }
10380 }
10381 }
10382
10383 private final boolean requestServiceBindingLocked(ServiceRecord r,
10384 IntentBindRecord i, boolean rebind) {
10385 if (r.app == null || r.app.thread == null) {
10386 // If service is not currently running, can't yet bind.
10387 return false;
10388 }
10389 if ((!i.requested || rebind) && i.apps.size() > 0) {
10390 try {
10391 bumpServiceExecutingLocked(r);
10392 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10393 + ": shouldUnbind=" + i.hasBound);
10394 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10395 if (!rebind) {
10396 i.requested = true;
10397 }
10398 i.hasBound = true;
10399 i.doRebind = false;
10400 } catch (RemoteException e) {
10401 return false;
10402 }
10403 }
10404 return true;
10405 }
10406
10407 private final void requestServiceBindingsLocked(ServiceRecord r) {
10408 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10409 while (bindings.hasNext()) {
10410 IntentBindRecord i = bindings.next();
10411 if (!requestServiceBindingLocked(r, i, false)) {
10412 break;
10413 }
10414 }
10415 }
10416
10417 private final void realStartServiceLocked(ServiceRecord r,
10418 ProcessRecord app) throws RemoteException {
10419 if (app.thread == null) {
10420 throw new RemoteException();
10421 }
10422
10423 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010424 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010425
10426 app.services.add(r);
10427 bumpServiceExecutingLocked(r);
10428 updateLRUListLocked(app, true);
10429
10430 boolean created = false;
10431 try {
10432 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10433 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010434 mStringBuilder.setLength(0);
10435 r.intent.getIntent().toShortString(mStringBuilder, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010436 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10437 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010438 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010439 synchronized (r.stats.getBatteryStats()) {
10440 r.stats.startLaunchedLocked();
10441 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010442 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010443 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010444 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010445 created = true;
10446 } finally {
10447 if (!created) {
10448 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010449 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010450 }
10451 }
10452
10453 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010454
10455 // If the service is in the started state, and there are no
10456 // pending arguments, then fake up one so its onStartCommand() will
10457 // be called.
10458 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10459 r.lastStartId++;
10460 if (r.lastStartId < 1) {
10461 r.lastStartId = 1;
10462 }
10463 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10464 }
10465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010466 sendServiceArgsLocked(r, true);
10467 }
10468
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010469 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10470 boolean allowCancel) {
10471 boolean canceled = false;
10472
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010473 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010474 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010475 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010476
10477 // Any delivered but not yet finished starts should be put back
10478 // on the pending list.
10479 final int N = r.deliveredStarts.size();
10480 if (N > 0) {
10481 for (int i=N-1; i>=0; i--) {
10482 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10483 if (si.intent == null) {
10484 // We'll generate this again if needed.
10485 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10486 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10487 r.pendingStarts.add(0, si);
10488 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10489 dur *= 2;
10490 if (minDuration < dur) minDuration = dur;
10491 if (resetTime < dur) resetTime = dur;
10492 } else {
10493 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10494 + r.name);
10495 canceled = true;
10496 }
10497 }
10498 r.deliveredStarts.clear();
10499 }
10500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010501 r.totalRestartCount++;
10502 if (r.restartDelay == 0) {
10503 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010504 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010505 } else {
10506 // If it has been a "reasonably long time" since the service
10507 // was started, then reset our restart duration back to
10508 // the beginning, so we don't infinitely increase the duration
10509 // on a service that just occasionally gets killed (which is
10510 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010511 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010512 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010513 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010514 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010515 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010516 if (r.restartDelay < minDuration) {
10517 r.restartDelay = minDuration;
10518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010519 }
10520 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010521
10522 r.nextRestartTime = now + r.restartDelay;
10523
10524 // Make sure that we don't end up restarting a bunch of services
10525 // all at the same time.
10526 boolean repeat;
10527 do {
10528 repeat = false;
10529 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10530 ServiceRecord r2 = mRestartingServices.get(i);
10531 if (r2 != r && r.nextRestartTime
10532 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10533 && r.nextRestartTime
10534 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10535 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10536 r.restartDelay = r.nextRestartTime - now;
10537 repeat = true;
10538 break;
10539 }
10540 }
10541 } while (repeat);
10542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010543 if (!mRestartingServices.contains(r)) {
10544 mRestartingServices.add(r);
10545 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010546
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010547 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010549 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010550 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010551 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10552 Log.w(TAG, "Scheduling restart of crashed service "
10553 + r.shortName + " in " + r.restartDelay + "ms");
10554 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10555 r.shortName, r.restartDelay);
10556
10557 Message msg = Message.obtain();
10558 msg.what = SERVICE_ERROR_MSG;
10559 msg.obj = r;
10560 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010561
10562 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010563 }
10564
10565 final void performServiceRestartLocked(ServiceRecord r) {
10566 if (!mRestartingServices.contains(r)) {
10567 return;
10568 }
10569 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10570 }
10571
10572 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10573 if (r.restartDelay == 0) {
10574 return false;
10575 }
10576 r.resetRestartCounter();
10577 mRestartingServices.remove(r);
10578 mHandler.removeCallbacks(r.restarter);
10579 return true;
10580 }
10581
10582 private final boolean bringUpServiceLocked(ServiceRecord r,
10583 int intentFlags, boolean whileRestarting) {
10584 //Log.i(TAG, "Bring up service:");
10585 //r.dump(" ");
10586
Dianne Hackborn36124872009-10-08 16:22:03 -070010587 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010588 sendServiceArgsLocked(r, false);
10589 return true;
10590 }
10591
10592 if (!whileRestarting && r.restartDelay > 0) {
10593 // If waiting for a restart, then do nothing.
10594 return true;
10595 }
10596
10597 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10598 + " " + r.intent);
10599
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010600 // We are now bringing the service up, so no longer in the
10601 // restarting state.
10602 mRestartingServices.remove(r);
10603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010604 final String appName = r.processName;
10605 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10606 if (app != null && app.thread != null) {
10607 try {
10608 realStartServiceLocked(r, app);
10609 return true;
10610 } catch (RemoteException e) {
10611 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10612 }
10613
10614 // If a dead object exception was thrown -- fall through to
10615 // restart the application.
10616 }
10617
Dianne Hackborn36124872009-10-08 16:22:03 -070010618 // Not running -- get it started, and enqueue this service record
10619 // to be executed when the app comes up.
10620 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10621 "service", r.name, false) == null) {
10622 Log.w(TAG, "Unable to launch app "
10623 + r.appInfo.packageName + "/"
10624 + r.appInfo.uid + " for service "
10625 + r.intent.getIntent() + ": process is bad");
10626 bringDownServiceLocked(r, true);
10627 return false;
10628 }
10629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010630 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010631 mPendingServices.add(r);
10632 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010633
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010634 return true;
10635 }
10636
10637 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10638 //Log.i(TAG, "Bring down service:");
10639 //r.dump(" ");
10640
10641 // Does it still need to run?
10642 if (!force && r.startRequested) {
10643 return;
10644 }
10645 if (r.connections.size() > 0) {
10646 if (!force) {
10647 // XXX should probably keep a count of the number of auto-create
10648 // connections directly in the service.
10649 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10650 while (it.hasNext()) {
10651 ConnectionRecord cr = it.next();
10652 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10653 return;
10654 }
10655 }
10656 }
10657
10658 // Report to all of the connections that the service is no longer
10659 // available.
10660 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10661 while (it.hasNext()) {
10662 ConnectionRecord c = it.next();
10663 try {
10664 // todo: shouldn't be a synchronous call!
10665 c.conn.connected(r.name, null);
10666 } catch (Exception e) {
10667 Log.w(TAG, "Failure disconnecting service " + r.name +
10668 " to connection " + c.conn.asBinder() +
10669 " (in " + c.binding.client.processName + ")", e);
10670 }
10671 }
10672 }
10673
10674 // Tell the service that it has been unbound.
10675 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10676 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10677 while (it.hasNext()) {
10678 IntentBindRecord ibr = it.next();
10679 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10680 + ": hasBound=" + ibr.hasBound);
10681 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10682 try {
10683 bumpServiceExecutingLocked(r);
10684 updateOomAdjLocked(r.app);
10685 ibr.hasBound = false;
10686 r.app.thread.scheduleUnbindService(r,
10687 ibr.intent.getIntent());
10688 } catch (Exception e) {
10689 Log.w(TAG, "Exception when unbinding service "
10690 + r.shortName, e);
10691 serviceDoneExecutingLocked(r, true);
10692 }
10693 }
10694 }
10695 }
10696
10697 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10698 + " " + r.intent);
10699 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10700 System.identityHashCode(r), r.shortName,
10701 (r.app != null) ? r.app.pid : -1);
10702
10703 mServices.remove(r.name);
10704 mServicesByIntent.remove(r.intent);
10705 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10706 r.totalRestartCount = 0;
10707 unscheduleServiceRestartLocked(r);
10708
10709 // Also make sure it is not on the pending list.
10710 int N = mPendingServices.size();
10711 for (int i=0; i<N; i++) {
10712 if (mPendingServices.get(i) == r) {
10713 mPendingServices.remove(i);
10714 if (DEBUG_SERVICE) Log.v(
10715 TAG, "Removed pending service: " + r.shortName);
10716 i--;
10717 N--;
10718 }
10719 }
10720
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010721 r.cancelNotification();
10722 r.isForeground = false;
10723 r.foregroundId = 0;
10724 r.foregroundNoti = null;
10725
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010726 // Clear start entries.
10727 r.deliveredStarts.clear();
10728 r.pendingStarts.clear();
10729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010730 if (r.app != null) {
10731 synchronized (r.stats.getBatteryStats()) {
10732 r.stats.stopLaunchedLocked();
10733 }
10734 r.app.services.remove(r);
10735 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010736 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010737 if (DEBUG_SERVICE) Log.v(TAG,
10738 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010739 bumpServiceExecutingLocked(r);
10740 mStoppingServices.add(r);
10741 updateOomAdjLocked(r.app);
10742 r.app.thread.scheduleStopService(r);
10743 } catch (Exception e) {
10744 Log.w(TAG, "Exception when stopping service "
10745 + r.shortName, e);
10746 serviceDoneExecutingLocked(r, true);
10747 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010748 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010749 } else {
10750 if (DEBUG_SERVICE) Log.v(
10751 TAG, "Removed service that has no process: " + r.shortName);
10752 }
10753 } else {
10754 if (DEBUG_SERVICE) Log.v(
10755 TAG, "Removed service that is not running: " + r.shortName);
10756 }
10757 }
10758
10759 ComponentName startServiceLocked(IApplicationThread caller,
10760 Intent service, String resolvedType,
10761 int callingPid, int callingUid) {
10762 synchronized(this) {
10763 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10764 + " type=" + resolvedType + " args=" + service.getExtras());
10765
10766 if (caller != null) {
10767 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10768 if (callerApp == null) {
10769 throw new SecurityException(
10770 "Unable to find app for caller " + caller
10771 + " (pid=" + Binder.getCallingPid()
10772 + ") when starting service " + service);
10773 }
10774 }
10775
10776 ServiceLookupResult res =
10777 retrieveServiceLocked(service, resolvedType,
10778 callingPid, callingUid);
10779 if (res == null) {
10780 return null;
10781 }
10782 if (res.record == null) {
10783 return new ComponentName("!", res.permission != null
10784 ? res.permission : "private to package");
10785 }
10786 ServiceRecord r = res.record;
10787 if (unscheduleServiceRestartLocked(r)) {
10788 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10789 + r.shortName);
10790 }
10791 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010792 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010793 r.lastStartId++;
10794 if (r.lastStartId < 1) {
10795 r.lastStartId = 1;
10796 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010797 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010798 r.lastActivity = SystemClock.uptimeMillis();
10799 synchronized (r.stats.getBatteryStats()) {
10800 r.stats.startRunningLocked();
10801 }
10802 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10803 return new ComponentName("!", "Service process is bad");
10804 }
10805 return r.name;
10806 }
10807 }
10808
10809 public ComponentName startService(IApplicationThread caller, Intent service,
10810 String resolvedType) {
10811 // Refuse possible leaked file descriptors
10812 if (service != null && service.hasFileDescriptors() == true) {
10813 throw new IllegalArgumentException("File descriptors passed in Intent");
10814 }
10815
10816 synchronized(this) {
10817 final int callingPid = Binder.getCallingPid();
10818 final int callingUid = Binder.getCallingUid();
10819 final long origId = Binder.clearCallingIdentity();
10820 ComponentName res = startServiceLocked(caller, service,
10821 resolvedType, callingPid, callingUid);
10822 Binder.restoreCallingIdentity(origId);
10823 return res;
10824 }
10825 }
10826
10827 ComponentName startServiceInPackage(int uid,
10828 Intent service, String resolvedType) {
10829 synchronized(this) {
10830 final long origId = Binder.clearCallingIdentity();
10831 ComponentName res = startServiceLocked(null, service,
10832 resolvedType, -1, uid);
10833 Binder.restoreCallingIdentity(origId);
10834 return res;
10835 }
10836 }
10837
10838 public int stopService(IApplicationThread caller, Intent service,
10839 String resolvedType) {
10840 // Refuse possible leaked file descriptors
10841 if (service != null && service.hasFileDescriptors() == true) {
10842 throw new IllegalArgumentException("File descriptors passed in Intent");
10843 }
10844
10845 synchronized(this) {
10846 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10847 + " type=" + resolvedType);
10848
10849 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10850 if (caller != null && callerApp == null) {
10851 throw new SecurityException(
10852 "Unable to find app for caller " + caller
10853 + " (pid=" + Binder.getCallingPid()
10854 + ") when stopping service " + service);
10855 }
10856
10857 // If this service is active, make sure it is stopped.
10858 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10859 if (r != null) {
10860 if (r.record != null) {
10861 synchronized (r.record.stats.getBatteryStats()) {
10862 r.record.stats.stopRunningLocked();
10863 }
10864 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010865 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010866 final long origId = Binder.clearCallingIdentity();
10867 bringDownServiceLocked(r.record, false);
10868 Binder.restoreCallingIdentity(origId);
10869 return 1;
10870 }
10871 return -1;
10872 }
10873 }
10874
10875 return 0;
10876 }
10877
10878 public IBinder peekService(Intent service, String resolvedType) {
10879 // Refuse possible leaked file descriptors
10880 if (service != null && service.hasFileDescriptors() == true) {
10881 throw new IllegalArgumentException("File descriptors passed in Intent");
10882 }
10883
10884 IBinder ret = null;
10885
10886 synchronized(this) {
10887 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10888
10889 if (r != null) {
10890 // r.record is null if findServiceLocked() failed the caller permission check
10891 if (r.record == null) {
10892 throw new SecurityException(
10893 "Permission Denial: Accessing service " + r.record.name
10894 + " from pid=" + Binder.getCallingPid()
10895 + ", uid=" + Binder.getCallingUid()
10896 + " requires " + r.permission);
10897 }
10898 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10899 if (ib != null) {
10900 ret = ib.binder;
10901 }
10902 }
10903 }
10904
10905 return ret;
10906 }
10907
10908 public boolean stopServiceToken(ComponentName className, IBinder token,
10909 int startId) {
10910 synchronized(this) {
10911 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10912 + " " + token + " startId=" + startId);
10913 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010914 if (r != null) {
10915 if (startId >= 0) {
10916 // Asked to only stop if done with all work. Note that
10917 // to avoid leaks, we will take this as dropping all
10918 // start items up to and including this one.
10919 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10920 if (si != null) {
10921 while (r.deliveredStarts.size() > 0) {
10922 if (r.deliveredStarts.remove(0) == si) {
10923 break;
10924 }
10925 }
10926 }
10927
10928 if (r.lastStartId != startId) {
10929 return false;
10930 }
10931
10932 if (r.deliveredStarts.size() > 0) {
10933 Log.w(TAG, "stopServiceToken startId " + startId
10934 + " is last, but have " + r.deliveredStarts.size()
10935 + " remaining args");
10936 }
10937 }
10938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010939 synchronized (r.stats.getBatteryStats()) {
10940 r.stats.stopRunningLocked();
10941 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010942 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010943 }
10944 final long origId = Binder.clearCallingIdentity();
10945 bringDownServiceLocked(r, false);
10946 Binder.restoreCallingIdentity(origId);
10947 return true;
10948 }
10949 }
10950 return false;
10951 }
10952
10953 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010954 int id, Notification notification, boolean removeNotification) {
10955 final long origId = Binder.clearCallingIdentity();
10956 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010957 synchronized(this) {
10958 ServiceRecord r = findServiceLocked(className, token);
10959 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010960 if (id != 0) {
10961 if (notification == null) {
10962 throw new IllegalArgumentException("null notification");
10963 }
10964 if (r.foregroundId != id) {
10965 r.cancelNotification();
10966 r.foregroundId = id;
10967 }
10968 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10969 r.foregroundNoti = notification;
10970 r.isForeground = true;
10971 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010972 if (r.app != null) {
10973 updateServiceForegroundLocked(r.app, true);
10974 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010975 } else {
10976 if (r.isForeground) {
10977 r.isForeground = false;
10978 if (r.app != null) {
10979 updateServiceForegroundLocked(r.app, true);
10980 }
10981 }
10982 if (removeNotification) {
10983 r.cancelNotification();
10984 r.foregroundId = 0;
10985 r.foregroundNoti = null;
10986 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010987 }
10988 }
10989 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010990 } finally {
10991 Binder.restoreCallingIdentity(origId);
10992 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010993 }
10994
10995 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10996 boolean anyForeground = false;
10997 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10998 if (sr.isForeground) {
10999 anyForeground = true;
11000 break;
11001 }
11002 }
11003 if (anyForeground != proc.foregroundServices) {
11004 proc.foregroundServices = anyForeground;
11005 if (oomAdj) {
11006 updateOomAdjLocked();
11007 }
11008 }
11009 }
11010
11011 public int bindService(IApplicationThread caller, IBinder token,
11012 Intent service, String resolvedType,
11013 IServiceConnection connection, int flags) {
11014 // Refuse possible leaked file descriptors
11015 if (service != null && service.hasFileDescriptors() == true) {
11016 throw new IllegalArgumentException("File descriptors passed in Intent");
11017 }
11018
11019 synchronized(this) {
11020 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11021 + " type=" + resolvedType + " conn=" + connection.asBinder()
11022 + " flags=0x" + Integer.toHexString(flags));
11023 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11024 if (callerApp == null) {
11025 throw new SecurityException(
11026 "Unable to find app for caller " + caller
11027 + " (pid=" + Binder.getCallingPid()
11028 + ") when binding service " + service);
11029 }
11030
11031 HistoryRecord activity = null;
11032 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011033 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011034 if (aindex < 0) {
11035 Log.w(TAG, "Binding with unknown activity: " + token);
11036 return 0;
11037 }
11038 activity = (HistoryRecord)mHistory.get(aindex);
11039 }
11040
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011041 int clientLabel = 0;
11042 PendingIntent clientIntent = null;
11043
11044 if (callerApp.info.uid == Process.SYSTEM_UID) {
11045 // Hacky kind of thing -- allow system stuff to tell us
11046 // what they are, so we can report this elsewhere for
11047 // others to know why certain services are running.
11048 try {
11049 clientIntent = (PendingIntent)service.getParcelableExtra(
11050 Intent.EXTRA_CLIENT_INTENT);
11051 } catch (RuntimeException e) {
11052 }
11053 if (clientIntent != null) {
11054 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11055 if (clientLabel != 0) {
11056 // There are no useful extras in the intent, trash them.
11057 // System code calling with this stuff just needs to know
11058 // this will happen.
11059 service = service.cloneFilter();
11060 }
11061 }
11062 }
11063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011064 ServiceLookupResult res =
11065 retrieveServiceLocked(service, resolvedType,
11066 Binder.getCallingPid(), Binder.getCallingUid());
11067 if (res == null) {
11068 return 0;
11069 }
11070 if (res.record == null) {
11071 return -1;
11072 }
11073 ServiceRecord s = res.record;
11074
11075 final long origId = Binder.clearCallingIdentity();
11076
11077 if (unscheduleServiceRestartLocked(s)) {
11078 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11079 + s.shortName);
11080 }
11081
11082 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11083 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011084 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011085
11086 IBinder binder = connection.asBinder();
11087 s.connections.put(binder, c);
11088 b.connections.add(c);
11089 if (activity != null) {
11090 if (activity.connections == null) {
11091 activity.connections = new HashSet<ConnectionRecord>();
11092 }
11093 activity.connections.add(c);
11094 }
11095 b.client.connections.add(c);
11096 mServiceConnections.put(binder, c);
11097
11098 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11099 s.lastActivity = SystemClock.uptimeMillis();
11100 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11101 return 0;
11102 }
11103 }
11104
11105 if (s.app != null) {
11106 // This could have made the service more important.
11107 updateOomAdjLocked(s.app);
11108 }
11109
11110 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11111 + ": received=" + b.intent.received
11112 + " apps=" + b.intent.apps.size()
11113 + " doRebind=" + b.intent.doRebind);
11114
11115 if (s.app != null && b.intent.received) {
11116 // Service is already running, so we can immediately
11117 // publish the connection.
11118 try {
11119 c.conn.connected(s.name, b.intent.binder);
11120 } catch (Exception e) {
11121 Log.w(TAG, "Failure sending service " + s.shortName
11122 + " to connection " + c.conn.asBinder()
11123 + " (in " + c.binding.client.processName + ")", e);
11124 }
11125
11126 // If this is the first app connected back to this binding,
11127 // and the service had previously asked to be told when
11128 // rebound, then do so.
11129 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11130 requestServiceBindingLocked(s, b.intent, true);
11131 }
11132 } else if (!b.intent.requested) {
11133 requestServiceBindingLocked(s, b.intent, false);
11134 }
11135
11136 Binder.restoreCallingIdentity(origId);
11137 }
11138
11139 return 1;
11140 }
11141
11142 private void removeConnectionLocked(
11143 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11144 IBinder binder = c.conn.asBinder();
11145 AppBindRecord b = c.binding;
11146 ServiceRecord s = b.service;
11147 s.connections.remove(binder);
11148 b.connections.remove(c);
11149 if (c.activity != null && c.activity != skipAct) {
11150 if (c.activity.connections != null) {
11151 c.activity.connections.remove(c);
11152 }
11153 }
11154 if (b.client != skipApp) {
11155 b.client.connections.remove(c);
11156 }
11157 mServiceConnections.remove(binder);
11158
11159 if (b.connections.size() == 0) {
11160 b.intent.apps.remove(b.client);
11161 }
11162
11163 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11164 + ": shouldUnbind=" + b.intent.hasBound);
11165 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11166 && b.intent.hasBound) {
11167 try {
11168 bumpServiceExecutingLocked(s);
11169 updateOomAdjLocked(s.app);
11170 b.intent.hasBound = false;
11171 // Assume the client doesn't want to know about a rebind;
11172 // we will deal with that later if it asks for one.
11173 b.intent.doRebind = false;
11174 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11175 } catch (Exception e) {
11176 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11177 serviceDoneExecutingLocked(s, true);
11178 }
11179 }
11180
11181 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11182 bringDownServiceLocked(s, false);
11183 }
11184 }
11185
11186 public boolean unbindService(IServiceConnection connection) {
11187 synchronized (this) {
11188 IBinder binder = connection.asBinder();
11189 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11190 ConnectionRecord r = mServiceConnections.get(binder);
11191 if (r == null) {
11192 Log.w(TAG, "Unbind failed: could not find connection for "
11193 + connection.asBinder());
11194 return false;
11195 }
11196
11197 final long origId = Binder.clearCallingIdentity();
11198
11199 removeConnectionLocked(r, null, null);
11200
11201 if (r.binding.service.app != null) {
11202 // This could have made the service less important.
11203 updateOomAdjLocked(r.binding.service.app);
11204 }
11205
11206 Binder.restoreCallingIdentity(origId);
11207 }
11208
11209 return true;
11210 }
11211
11212 public void publishService(IBinder token, Intent intent, IBinder service) {
11213 // Refuse possible leaked file descriptors
11214 if (intent != null && intent.hasFileDescriptors() == true) {
11215 throw new IllegalArgumentException("File descriptors passed in Intent");
11216 }
11217
11218 synchronized(this) {
11219 if (!(token instanceof ServiceRecord)) {
11220 throw new IllegalArgumentException("Invalid service token");
11221 }
11222 ServiceRecord r = (ServiceRecord)token;
11223
11224 final long origId = Binder.clearCallingIdentity();
11225
11226 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11227 + " " + intent + ": " + service);
11228 if (r != null) {
11229 Intent.FilterComparison filter
11230 = new Intent.FilterComparison(intent);
11231 IntentBindRecord b = r.bindings.get(filter);
11232 if (b != null && !b.received) {
11233 b.binder = service;
11234 b.requested = true;
11235 b.received = true;
11236 if (r.connections.size() > 0) {
11237 Iterator<ConnectionRecord> it
11238 = r.connections.values().iterator();
11239 while (it.hasNext()) {
11240 ConnectionRecord c = it.next();
11241 if (!filter.equals(c.binding.intent.intent)) {
11242 if (DEBUG_SERVICE) Log.v(
11243 TAG, "Not publishing to: " + c);
11244 if (DEBUG_SERVICE) Log.v(
11245 TAG, "Bound intent: " + c.binding.intent.intent);
11246 if (DEBUG_SERVICE) Log.v(
11247 TAG, "Published intent: " + intent);
11248 continue;
11249 }
11250 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11251 try {
11252 c.conn.connected(r.name, service);
11253 } catch (Exception e) {
11254 Log.w(TAG, "Failure sending service " + r.name +
11255 " to connection " + c.conn.asBinder() +
11256 " (in " + c.binding.client.processName + ")", e);
11257 }
11258 }
11259 }
11260 }
11261
11262 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11263
11264 Binder.restoreCallingIdentity(origId);
11265 }
11266 }
11267 }
11268
11269 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11270 // Refuse possible leaked file descriptors
11271 if (intent != null && intent.hasFileDescriptors() == true) {
11272 throw new IllegalArgumentException("File descriptors passed in Intent");
11273 }
11274
11275 synchronized(this) {
11276 if (!(token instanceof ServiceRecord)) {
11277 throw new IllegalArgumentException("Invalid service token");
11278 }
11279 ServiceRecord r = (ServiceRecord)token;
11280
11281 final long origId = Binder.clearCallingIdentity();
11282
11283 if (r != null) {
11284 Intent.FilterComparison filter
11285 = new Intent.FilterComparison(intent);
11286 IntentBindRecord b = r.bindings.get(filter);
11287 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11288 + " at " + b + ": apps="
11289 + (b != null ? b.apps.size() : 0));
11290 if (b != null) {
11291 if (b.apps.size() > 0) {
11292 // Applications have already bound since the last
11293 // unbind, so just rebind right here.
11294 requestServiceBindingLocked(r, b, true);
11295 } else {
11296 // Note to tell the service the next time there is
11297 // a new client.
11298 b.doRebind = true;
11299 }
11300 }
11301
11302 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11303
11304 Binder.restoreCallingIdentity(origId);
11305 }
11306 }
11307 }
11308
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011309 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011310 synchronized(this) {
11311 if (!(token instanceof ServiceRecord)) {
11312 throw new IllegalArgumentException("Invalid service token");
11313 }
11314 ServiceRecord r = (ServiceRecord)token;
11315 boolean inStopping = mStoppingServices.contains(token);
11316 if (r != null) {
11317 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11318 + ": nesting=" + r.executeNesting
11319 + ", inStopping=" + inStopping);
11320 if (r != token) {
11321 Log.w(TAG, "Done executing service " + r.name
11322 + " with incorrect token: given " + token
11323 + ", expected " + r);
11324 return;
11325 }
11326
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011327 if (type == 1) {
11328 // This is a call from a service start... take care of
11329 // book-keeping.
11330 r.callStart = true;
11331 switch (res) {
11332 case Service.START_STICKY_COMPATIBILITY:
11333 case Service.START_STICKY: {
11334 // We are done with the associated start arguments.
11335 r.findDeliveredStart(startId, true);
11336 // Don't stop if killed.
11337 r.stopIfKilled = false;
11338 break;
11339 }
11340 case Service.START_NOT_STICKY: {
11341 // We are done with the associated start arguments.
11342 r.findDeliveredStart(startId, true);
11343 if (r.lastStartId == startId) {
11344 // There is no more work, and this service
11345 // doesn't want to hang around if killed.
11346 r.stopIfKilled = true;
11347 }
11348 break;
11349 }
11350 case Service.START_REDELIVER_INTENT: {
11351 // We'll keep this item until they explicitly
11352 // call stop for it, but keep track of the fact
11353 // that it was delivered.
11354 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11355 if (si != null) {
11356 si.deliveryCount = 0;
11357 si.doneExecutingCount++;
11358 // Don't stop if killed.
11359 r.stopIfKilled = true;
11360 }
11361 break;
11362 }
11363 default:
11364 throw new IllegalArgumentException(
11365 "Unknown service start result: " + res);
11366 }
11367 if (res == Service.START_STICKY_COMPATIBILITY) {
11368 r.callStart = false;
11369 }
11370 }
11371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011372 final long origId = Binder.clearCallingIdentity();
11373 serviceDoneExecutingLocked(r, inStopping);
11374 Binder.restoreCallingIdentity(origId);
11375 } else {
11376 Log.w(TAG, "Done executing unknown service " + r.name
11377 + " with token " + token);
11378 }
11379 }
11380 }
11381
11382 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11383 r.executeNesting--;
11384 if (r.executeNesting <= 0 && r.app != null) {
11385 r.app.executingServices.remove(r);
11386 if (r.app.executingServices.size() == 0) {
11387 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11388 }
11389 if (inStopping) {
11390 mStoppingServices.remove(r);
11391 }
11392 updateOomAdjLocked(r.app);
11393 }
11394 }
11395
11396 void serviceTimeout(ProcessRecord proc) {
11397 synchronized(this) {
11398 if (proc.executingServices.size() == 0 || proc.thread == null) {
11399 return;
11400 }
11401 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11402 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11403 ServiceRecord timeout = null;
11404 long nextTime = 0;
11405 while (it.hasNext()) {
11406 ServiceRecord sr = it.next();
11407 if (sr.executingStart < maxTime) {
11408 timeout = sr;
11409 break;
11410 }
11411 if (sr.executingStart > nextTime) {
11412 nextTime = sr.executingStart;
11413 }
11414 }
11415 if (timeout != null && mLRUProcesses.contains(proc)) {
11416 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011417 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011418 + timeout.name);
11419 } else {
11420 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11421 msg.obj = proc;
11422 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11423 }
11424 }
11425 }
11426
11427 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011428 // BACKUP AND RESTORE
11429 // =========================================================
11430
11431 // Cause the target app to be launched if necessary and its backup agent
11432 // instantiated. The backup agent will invoke backupAgentCreated() on the
11433 // activity manager to announce its creation.
11434 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11435 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11436 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11437
11438 synchronized(this) {
11439 // !!! TODO: currently no check here that we're already bound
11440 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11441 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11442 synchronized (stats) {
11443 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11444 }
11445
11446 BackupRecord r = new BackupRecord(ss, app, backupMode);
11447 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11448 // startProcessLocked() returns existing proc's record if it's already running
11449 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011450 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011451 if (proc == null) {
11452 Log.e(TAG, "Unable to start backup agent process " + r);
11453 return false;
11454 }
11455
11456 r.app = proc;
11457 mBackupTarget = r;
11458 mBackupAppName = app.packageName;
11459
Christopher Tate6fa95972009-06-05 18:43:55 -070011460 // Try not to kill the process during backup
11461 updateOomAdjLocked(proc);
11462
Christopher Tate181fafa2009-05-14 11:12:14 -070011463 // If the process is already attached, schedule the creation of the backup agent now.
11464 // If it is not yet live, this will be done when it attaches to the framework.
11465 if (proc.thread != null) {
11466 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11467 try {
11468 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11469 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011470 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011471 }
11472 } else {
11473 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11474 }
11475 // Invariants: at this point, the target app process exists and the application
11476 // is either already running or in the process of coming up. mBackupTarget and
11477 // mBackupAppName describe the app, so that when it binds back to the AM we
11478 // know that it's scheduled for a backup-agent operation.
11479 }
11480
11481 return true;
11482 }
11483
11484 // A backup agent has just come up
11485 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11486 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11487 + " = " + agent);
11488
11489 synchronized(this) {
11490 if (!agentPackageName.equals(mBackupAppName)) {
11491 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11492 return;
11493 }
11494
Christopher Tate043dadc2009-06-02 16:11:00 -070011495 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011496 try {
11497 IBackupManager bm = IBackupManager.Stub.asInterface(
11498 ServiceManager.getService(Context.BACKUP_SERVICE));
11499 bm.agentConnected(agentPackageName, agent);
11500 } catch (RemoteException e) {
11501 // can't happen; the backup manager service is local
11502 } catch (Exception e) {
11503 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11504 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011505 } finally {
11506 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011507 }
11508 }
11509 }
11510
11511 // done with this agent
11512 public void unbindBackupAgent(ApplicationInfo appInfo) {
11513 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011514 if (appInfo == null) {
11515 Log.w(TAG, "unbind backup agent for null app");
11516 return;
11517 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011518
11519 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011520 if (mBackupAppName == null) {
11521 Log.w(TAG, "Unbinding backup agent with no active backup");
11522 return;
11523 }
11524
Christopher Tate181fafa2009-05-14 11:12:14 -070011525 if (!mBackupAppName.equals(appInfo.packageName)) {
11526 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11527 return;
11528 }
11529
Christopher Tate6fa95972009-06-05 18:43:55 -070011530 ProcessRecord proc = mBackupTarget.app;
11531 mBackupTarget = null;
11532 mBackupAppName = null;
11533
11534 // Not backing this app up any more; reset its OOM adjustment
11535 updateOomAdjLocked(proc);
11536
Christopher Tatec7b31e32009-06-10 15:49:30 -070011537 // If the app crashed during backup, 'thread' will be null here
11538 if (proc.thread != null) {
11539 try {
11540 proc.thread.scheduleDestroyBackupAgent(appInfo);
11541 } catch (Exception e) {
11542 Log.e(TAG, "Exception when unbinding backup agent:");
11543 e.printStackTrace();
11544 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011545 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011546 }
11547 }
11548 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011549 // BROADCASTS
11550 // =========================================================
11551
11552 private final List getStickies(String action, IntentFilter filter,
11553 List cur) {
11554 final ContentResolver resolver = mContext.getContentResolver();
11555 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11556 if (list == null) {
11557 return cur;
11558 }
11559 int N = list.size();
11560 for (int i=0; i<N; i++) {
11561 Intent intent = list.get(i);
11562 if (filter.match(resolver, intent, true, TAG) >= 0) {
11563 if (cur == null) {
11564 cur = new ArrayList<Intent>();
11565 }
11566 cur.add(intent);
11567 }
11568 }
11569 return cur;
11570 }
11571
11572 private final void scheduleBroadcastsLocked() {
11573 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11574 + mBroadcastsScheduled);
11575
11576 if (mBroadcastsScheduled) {
11577 return;
11578 }
11579 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11580 mBroadcastsScheduled = true;
11581 }
11582
11583 public Intent registerReceiver(IApplicationThread caller,
11584 IIntentReceiver receiver, IntentFilter filter, String permission) {
11585 synchronized(this) {
11586 ProcessRecord callerApp = null;
11587 if (caller != null) {
11588 callerApp = getRecordForAppLocked(caller);
11589 if (callerApp == null) {
11590 throw new SecurityException(
11591 "Unable to find app for caller " + caller
11592 + " (pid=" + Binder.getCallingPid()
11593 + ") when registering receiver " + receiver);
11594 }
11595 }
11596
11597 List allSticky = null;
11598
11599 // Look for any matching sticky broadcasts...
11600 Iterator actions = filter.actionsIterator();
11601 if (actions != null) {
11602 while (actions.hasNext()) {
11603 String action = (String)actions.next();
11604 allSticky = getStickies(action, filter, allSticky);
11605 }
11606 } else {
11607 allSticky = getStickies(null, filter, allSticky);
11608 }
11609
11610 // The first sticky in the list is returned directly back to
11611 // the client.
11612 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11613
11614 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11615 + ": " + sticky);
11616
11617 if (receiver == null) {
11618 return sticky;
11619 }
11620
11621 ReceiverList rl
11622 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11623 if (rl == null) {
11624 rl = new ReceiverList(this, callerApp,
11625 Binder.getCallingPid(),
11626 Binder.getCallingUid(), receiver);
11627 if (rl.app != null) {
11628 rl.app.receivers.add(rl);
11629 } else {
11630 try {
11631 receiver.asBinder().linkToDeath(rl, 0);
11632 } catch (RemoteException e) {
11633 return sticky;
11634 }
11635 rl.linkedToDeath = true;
11636 }
11637 mRegisteredReceivers.put(receiver.asBinder(), rl);
11638 }
11639 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11640 rl.add(bf);
11641 if (!bf.debugCheck()) {
11642 Log.w(TAG, "==> For Dynamic broadast");
11643 }
11644 mReceiverResolver.addFilter(bf);
11645
11646 // Enqueue broadcasts for all existing stickies that match
11647 // this filter.
11648 if (allSticky != null) {
11649 ArrayList receivers = new ArrayList();
11650 receivers.add(bf);
11651
11652 int N = allSticky.size();
11653 for (int i=0; i<N; i++) {
11654 Intent intent = (Intent)allSticky.get(i);
11655 BroadcastRecord r = new BroadcastRecord(intent, null,
11656 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011657 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011658 if (mParallelBroadcasts.size() == 0) {
11659 scheduleBroadcastsLocked();
11660 }
11661 mParallelBroadcasts.add(r);
11662 }
11663 }
11664
11665 return sticky;
11666 }
11667 }
11668
11669 public void unregisterReceiver(IIntentReceiver receiver) {
11670 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11671
11672 boolean doNext = false;
11673
11674 synchronized(this) {
11675 ReceiverList rl
11676 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11677 if (rl != null) {
11678 if (rl.curBroadcast != null) {
11679 BroadcastRecord r = rl.curBroadcast;
11680 doNext = finishReceiverLocked(
11681 receiver.asBinder(), r.resultCode, r.resultData,
11682 r.resultExtras, r.resultAbort, true);
11683 }
11684
11685 if (rl.app != null) {
11686 rl.app.receivers.remove(rl);
11687 }
11688 removeReceiverLocked(rl);
11689 if (rl.linkedToDeath) {
11690 rl.linkedToDeath = false;
11691 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11692 }
11693 }
11694 }
11695
11696 if (!doNext) {
11697 return;
11698 }
11699
11700 final long origId = Binder.clearCallingIdentity();
11701 processNextBroadcast(false);
11702 trimApplications();
11703 Binder.restoreCallingIdentity(origId);
11704 }
11705
11706 void removeReceiverLocked(ReceiverList rl) {
11707 mRegisteredReceivers.remove(rl.receiver.asBinder());
11708 int N = rl.size();
11709 for (int i=0; i<N; i++) {
11710 mReceiverResolver.removeFilter(rl.get(i));
11711 }
11712 }
11713
11714 private final int broadcastIntentLocked(ProcessRecord callerApp,
11715 String callerPackage, Intent intent, String resolvedType,
11716 IIntentReceiver resultTo, int resultCode, String resultData,
11717 Bundle map, String requiredPermission,
11718 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11719 intent = new Intent(intent);
11720
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011721 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011722 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11723 + " ordered=" + ordered);
11724 if ((resultTo != null) && !ordered) {
11725 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11726 }
11727
11728 // Handle special intents: if this broadcast is from the package
11729 // manager about a package being removed, we need to remove all of
11730 // its activities from the history stack.
11731 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11732 intent.getAction());
11733 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11734 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11735 || uidRemoved) {
11736 if (checkComponentPermission(
11737 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11738 callingPid, callingUid, -1)
11739 == PackageManager.PERMISSION_GRANTED) {
11740 if (uidRemoved) {
11741 final Bundle intentExtras = intent.getExtras();
11742 final int uid = intentExtras != null
11743 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11744 if (uid >= 0) {
11745 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11746 synchronized (bs) {
11747 bs.removeUidStatsLocked(uid);
11748 }
11749 }
11750 } else {
11751 Uri data = intent.getData();
11752 String ssp;
11753 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11754 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11755 uninstallPackageLocked(ssp,
11756 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011757 AttributeCache ac = AttributeCache.instance();
11758 if (ac != null) {
11759 ac.removePackage(ssp);
11760 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011761 }
11762 }
11763 }
11764 } else {
11765 String msg = "Permission Denial: " + intent.getAction()
11766 + " broadcast from " + callerPackage + " (pid=" + callingPid
11767 + ", uid=" + callingUid + ")"
11768 + " requires "
11769 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11770 Log.w(TAG, msg);
11771 throw new SecurityException(msg);
11772 }
11773 }
11774
11775 /*
11776 * If this is the time zone changed action, queue up a message that will reset the timezone
11777 * of all currently running processes. This message will get queued up before the broadcast
11778 * happens.
11779 */
11780 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11781 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11782 }
11783
Dianne Hackborn854060af2009-07-09 18:14:31 -070011784 /*
11785 * Prevent non-system code (defined here to be non-persistent
11786 * processes) from sending protected broadcasts.
11787 */
11788 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11789 || callingUid == Process.SHELL_UID || callingUid == 0) {
11790 // Always okay.
11791 } else if (callerApp == null || !callerApp.persistent) {
11792 try {
11793 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11794 intent.getAction())) {
11795 String msg = "Permission Denial: not allowed to send broadcast "
11796 + intent.getAction() + " from pid="
11797 + callingPid + ", uid=" + callingUid;
11798 Log.w(TAG, msg);
11799 throw new SecurityException(msg);
11800 }
11801 } catch (RemoteException e) {
11802 Log.w(TAG, "Remote exception", e);
11803 return BROADCAST_SUCCESS;
11804 }
11805 }
11806
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011807 // Add to the sticky list if requested.
11808 if (sticky) {
11809 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11810 callingPid, callingUid)
11811 != PackageManager.PERMISSION_GRANTED) {
11812 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11813 + callingPid + ", uid=" + callingUid
11814 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11815 Log.w(TAG, msg);
11816 throw new SecurityException(msg);
11817 }
11818 if (requiredPermission != null) {
11819 Log.w(TAG, "Can't broadcast sticky intent " + intent
11820 + " and enforce permission " + requiredPermission);
11821 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11822 }
11823 if (intent.getComponent() != null) {
11824 throw new SecurityException(
11825 "Sticky broadcasts can't target a specific component");
11826 }
11827 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11828 if (list == null) {
11829 list = new ArrayList<Intent>();
11830 mStickyBroadcasts.put(intent.getAction(), list);
11831 }
11832 int N = list.size();
11833 int i;
11834 for (i=0; i<N; i++) {
11835 if (intent.filterEquals(list.get(i))) {
11836 // This sticky already exists, replace it.
11837 list.set(i, new Intent(intent));
11838 break;
11839 }
11840 }
11841 if (i >= N) {
11842 list.add(new Intent(intent));
11843 }
11844 }
11845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011846 // Figure out who all will receive this broadcast.
11847 List receivers = null;
11848 List<BroadcastFilter> registeredReceivers = null;
11849 try {
11850 if (intent.getComponent() != null) {
11851 // Broadcast is going to one specific receiver class...
11852 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011853 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011854 if (ai != null) {
11855 receivers = new ArrayList();
11856 ResolveInfo ri = new ResolveInfo();
11857 ri.activityInfo = ai;
11858 receivers.add(ri);
11859 }
11860 } else {
11861 // Need to resolve the intent to interested receivers...
11862 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11863 == 0) {
11864 receivers =
11865 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011866 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011867 }
Mihai Preda074edef2009-05-18 17:13:31 +020011868 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011869 }
11870 } catch (RemoteException ex) {
11871 // pm is in same process, this will never happen.
11872 }
11873
11874 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11875 if (!ordered && NR > 0) {
11876 // If we are not serializing this broadcast, then send the
11877 // registered receivers separately so they don't wait for the
11878 // components to be launched.
11879 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11880 callerPackage, callingPid, callingUid, requiredPermission,
11881 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011882 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011883 if (DEBUG_BROADCAST) Log.v(
11884 TAG, "Enqueueing parallel broadcast " + r
11885 + ": prev had " + mParallelBroadcasts.size());
11886 mParallelBroadcasts.add(r);
11887 scheduleBroadcastsLocked();
11888 registeredReceivers = null;
11889 NR = 0;
11890 }
11891
11892 // Merge into one list.
11893 int ir = 0;
11894 if (receivers != null) {
11895 // A special case for PACKAGE_ADDED: do not allow the package
11896 // being added to see this broadcast. This prevents them from
11897 // using this as a back door to get run as soon as they are
11898 // installed. Maybe in the future we want to have a special install
11899 // broadcast or such for apps, but we'd like to deliberately make
11900 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011901 boolean skip = false;
11902 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011903 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011904 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11905 skip = true;
11906 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11907 skip = true;
11908 }
11909 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011910 ? intent.getData().getSchemeSpecificPart()
11911 : null;
11912 if (skipPackage != null && receivers != null) {
11913 int NT = receivers.size();
11914 for (int it=0; it<NT; it++) {
11915 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11916 if (curt.activityInfo.packageName.equals(skipPackage)) {
11917 receivers.remove(it);
11918 it--;
11919 NT--;
11920 }
11921 }
11922 }
11923
11924 int NT = receivers != null ? receivers.size() : 0;
11925 int it = 0;
11926 ResolveInfo curt = null;
11927 BroadcastFilter curr = null;
11928 while (it < NT && ir < NR) {
11929 if (curt == null) {
11930 curt = (ResolveInfo)receivers.get(it);
11931 }
11932 if (curr == null) {
11933 curr = registeredReceivers.get(ir);
11934 }
11935 if (curr.getPriority() >= curt.priority) {
11936 // Insert this broadcast record into the final list.
11937 receivers.add(it, curr);
11938 ir++;
11939 curr = null;
11940 it++;
11941 NT++;
11942 } else {
11943 // Skip to the next ResolveInfo in the final list.
11944 it++;
11945 curt = null;
11946 }
11947 }
11948 }
11949 while (ir < NR) {
11950 if (receivers == null) {
11951 receivers = new ArrayList();
11952 }
11953 receivers.add(registeredReceivers.get(ir));
11954 ir++;
11955 }
11956
11957 if ((receivers != null && receivers.size() > 0)
11958 || resultTo != null) {
11959 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11960 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011961 receivers, resultTo, resultCode, resultData, map, ordered,
11962 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011963 if (DEBUG_BROADCAST) Log.v(
11964 TAG, "Enqueueing ordered broadcast " + r
11965 + ": prev had " + mOrderedBroadcasts.size());
11966 if (DEBUG_BROADCAST) {
11967 int seq = r.intent.getIntExtra("seq", -1);
11968 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11969 }
11970 mOrderedBroadcasts.add(r);
11971 scheduleBroadcastsLocked();
11972 }
11973
11974 return BROADCAST_SUCCESS;
11975 }
11976
11977 public final int broadcastIntent(IApplicationThread caller,
11978 Intent intent, String resolvedType, IIntentReceiver resultTo,
11979 int resultCode, String resultData, Bundle map,
11980 String requiredPermission, boolean serialized, boolean sticky) {
11981 // Refuse possible leaked file descriptors
11982 if (intent != null && intent.hasFileDescriptors() == true) {
11983 throw new IllegalArgumentException("File descriptors passed in Intent");
11984 }
11985
11986 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011987 int flags = intent.getFlags();
11988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011989 if (!mSystemReady) {
11990 // if the caller really truly claims to know what they're doing, go
11991 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011992 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11993 intent = new Intent(intent);
11994 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11995 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11996 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11997 + " before boot completion");
11998 throw new IllegalStateException("Cannot broadcast before boot completed");
11999 }
12000 }
12001
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012002 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12003 throw new IllegalArgumentException(
12004 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12005 }
12006
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012007 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12008 final int callingPid = Binder.getCallingPid();
12009 final int callingUid = Binder.getCallingUid();
12010 final long origId = Binder.clearCallingIdentity();
12011 int res = broadcastIntentLocked(callerApp,
12012 callerApp != null ? callerApp.info.packageName : null,
12013 intent, resolvedType, resultTo,
12014 resultCode, resultData, map, requiredPermission, serialized,
12015 sticky, callingPid, callingUid);
12016 Binder.restoreCallingIdentity(origId);
12017 return res;
12018 }
12019 }
12020
12021 int broadcastIntentInPackage(String packageName, int uid,
12022 Intent intent, String resolvedType, IIntentReceiver resultTo,
12023 int resultCode, String resultData, Bundle map,
12024 String requiredPermission, boolean serialized, boolean sticky) {
12025 synchronized(this) {
12026 final long origId = Binder.clearCallingIdentity();
12027 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12028 resultTo, resultCode, resultData, map, requiredPermission,
12029 serialized, sticky, -1, uid);
12030 Binder.restoreCallingIdentity(origId);
12031 return res;
12032 }
12033 }
12034
12035 public final void unbroadcastIntent(IApplicationThread caller,
12036 Intent intent) {
12037 // Refuse possible leaked file descriptors
12038 if (intent != null && intent.hasFileDescriptors() == true) {
12039 throw new IllegalArgumentException("File descriptors passed in Intent");
12040 }
12041
12042 synchronized(this) {
12043 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12044 != PackageManager.PERMISSION_GRANTED) {
12045 String msg = "Permission Denial: unbroadcastIntent() from pid="
12046 + Binder.getCallingPid()
12047 + ", uid=" + Binder.getCallingUid()
12048 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12049 Log.w(TAG, msg);
12050 throw new SecurityException(msg);
12051 }
12052 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12053 if (list != null) {
12054 int N = list.size();
12055 int i;
12056 for (i=0; i<N; i++) {
12057 if (intent.filterEquals(list.get(i))) {
12058 list.remove(i);
12059 break;
12060 }
12061 }
12062 }
12063 }
12064 }
12065
12066 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12067 String resultData, Bundle resultExtras, boolean resultAbort,
12068 boolean explicit) {
12069 if (mOrderedBroadcasts.size() == 0) {
12070 if (explicit) {
12071 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12072 }
12073 return false;
12074 }
12075 BroadcastRecord r = mOrderedBroadcasts.get(0);
12076 if (r.receiver == null) {
12077 if (explicit) {
12078 Log.w(TAG, "finishReceiver called but none active");
12079 }
12080 return false;
12081 }
12082 if (r.receiver != receiver) {
12083 Log.w(TAG, "finishReceiver called but active receiver is different");
12084 return false;
12085 }
12086 int state = r.state;
12087 r.state = r.IDLE;
12088 if (state == r.IDLE) {
12089 if (explicit) {
12090 Log.w(TAG, "finishReceiver called but state is IDLE");
12091 }
12092 }
12093 r.receiver = null;
12094 r.intent.setComponent(null);
12095 if (r.curApp != null) {
12096 r.curApp.curReceiver = null;
12097 }
12098 if (r.curFilter != null) {
12099 r.curFilter.receiverList.curBroadcast = null;
12100 }
12101 r.curFilter = null;
12102 r.curApp = null;
12103 r.curComponent = null;
12104 r.curReceiver = null;
12105 mPendingBroadcast = null;
12106
12107 r.resultCode = resultCode;
12108 r.resultData = resultData;
12109 r.resultExtras = resultExtras;
12110 r.resultAbort = resultAbort;
12111
12112 // We will process the next receiver right now if this is finishing
12113 // an app receiver (which is always asynchronous) or after we have
12114 // come back from calling a receiver.
12115 return state == BroadcastRecord.APP_RECEIVE
12116 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12117 }
12118
12119 public void finishReceiver(IBinder who, int resultCode, String resultData,
12120 Bundle resultExtras, boolean resultAbort) {
12121 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12122
12123 // Refuse possible leaked file descriptors
12124 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12125 throw new IllegalArgumentException("File descriptors passed in Bundle");
12126 }
12127
12128 boolean doNext;
12129
12130 final long origId = Binder.clearCallingIdentity();
12131
12132 synchronized(this) {
12133 doNext = finishReceiverLocked(
12134 who, resultCode, resultData, resultExtras, resultAbort, true);
12135 }
12136
12137 if (doNext) {
12138 processNextBroadcast(false);
12139 }
12140 trimApplications();
12141
12142 Binder.restoreCallingIdentity(origId);
12143 }
12144
12145 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12146 if (r.nextReceiver > 0) {
12147 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12148 if (curReceiver instanceof BroadcastFilter) {
12149 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12150 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12151 System.identityHashCode(r),
12152 r.intent.getAction(),
12153 r.nextReceiver - 1,
12154 System.identityHashCode(bf));
12155 } else {
12156 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12157 System.identityHashCode(r),
12158 r.intent.getAction(),
12159 r.nextReceiver - 1,
12160 ((ResolveInfo)curReceiver).toString());
12161 }
12162 } else {
12163 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12164 + r);
12165 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12166 System.identityHashCode(r),
12167 r.intent.getAction(),
12168 r.nextReceiver,
12169 "NONE");
12170 }
12171 }
12172
12173 private final void broadcastTimeout() {
12174 synchronized (this) {
12175 if (mOrderedBroadcasts.size() == 0) {
12176 return;
12177 }
12178 long now = SystemClock.uptimeMillis();
12179 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012180 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012181 if (DEBUG_BROADCAST) Log.v(TAG,
12182 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012183 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012184 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012185 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012186 return;
12187 }
12188
12189 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012190 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012191 r.anrCount++;
12192
12193 // Current receiver has passed its expiration date.
12194 if (r.nextReceiver <= 0) {
12195 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12196 return;
12197 }
12198
12199 ProcessRecord app = null;
12200
12201 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12202 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12203 logBroadcastReceiverDiscard(r);
12204 if (curReceiver instanceof BroadcastFilter) {
12205 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12206 if (bf.receiverList.pid != 0
12207 && bf.receiverList.pid != MY_PID) {
12208 synchronized (this.mPidsSelfLocked) {
12209 app = this.mPidsSelfLocked.get(
12210 bf.receiverList.pid);
12211 }
12212 }
12213 } else {
12214 app = r.curApp;
12215 }
12216
12217 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012218 appNotRespondingLocked(app, null, null,
12219 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012220 }
12221
12222 if (mPendingBroadcast == r) {
12223 mPendingBroadcast = null;
12224 }
12225
12226 // Move on to the next receiver.
12227 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12228 r.resultExtras, r.resultAbort, true);
12229 scheduleBroadcastsLocked();
12230 }
12231 }
12232
12233 private final void processCurBroadcastLocked(BroadcastRecord r,
12234 ProcessRecord app) throws RemoteException {
12235 if (app.thread == null) {
12236 throw new RemoteException();
12237 }
12238 r.receiver = app.thread.asBinder();
12239 r.curApp = app;
12240 app.curReceiver = r;
12241 updateLRUListLocked(app, true);
12242
12243 // Tell the application to launch this receiver.
12244 r.intent.setComponent(r.curComponent);
12245
12246 boolean started = false;
12247 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012248 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012249 "Delivering to component " + r.curComponent
12250 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012251 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012252 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12253 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12254 started = true;
12255 } finally {
12256 if (!started) {
12257 r.receiver = null;
12258 r.curApp = null;
12259 app.curReceiver = null;
12260 }
12261 }
12262
12263 }
12264
12265 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012266 Intent intent, int resultCode, String data, Bundle extras,
12267 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012268 if (app != null && app.thread != null) {
12269 // If we have an app thread, do the call through that so it is
12270 // correctly ordered with other one-way calls.
12271 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012272 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012273 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012274 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012275 }
12276 }
12277
12278 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12279 BroadcastFilter filter, boolean ordered) {
12280 boolean skip = false;
12281 if (filter.requiredPermission != null) {
12282 int perm = checkComponentPermission(filter.requiredPermission,
12283 r.callingPid, r.callingUid, -1);
12284 if (perm != PackageManager.PERMISSION_GRANTED) {
12285 Log.w(TAG, "Permission Denial: broadcasting "
12286 + r.intent.toString()
12287 + " from " + r.callerPackage + " (pid="
12288 + r.callingPid + ", uid=" + r.callingUid + ")"
12289 + " requires " + filter.requiredPermission
12290 + " due to registered receiver " + filter);
12291 skip = true;
12292 }
12293 }
12294 if (r.requiredPermission != null) {
12295 int perm = checkComponentPermission(r.requiredPermission,
12296 filter.receiverList.pid, filter.receiverList.uid, -1);
12297 if (perm != PackageManager.PERMISSION_GRANTED) {
12298 Log.w(TAG, "Permission Denial: receiving "
12299 + r.intent.toString()
12300 + " to " + filter.receiverList.app
12301 + " (pid=" + filter.receiverList.pid
12302 + ", uid=" + filter.receiverList.uid + ")"
12303 + " requires " + r.requiredPermission
12304 + " due to sender " + r.callerPackage
12305 + " (uid " + r.callingUid + ")");
12306 skip = true;
12307 }
12308 }
12309
12310 if (!skip) {
12311 // If this is not being sent as an ordered broadcast, then we
12312 // don't want to touch the fields that keep track of the current
12313 // state of ordered broadcasts.
12314 if (ordered) {
12315 r.receiver = filter.receiverList.receiver.asBinder();
12316 r.curFilter = filter;
12317 filter.receiverList.curBroadcast = r;
12318 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012319 if (filter.receiverList.app != null) {
12320 // Bump hosting application to no longer be in background
12321 // scheduling class. Note that we can't do that if there
12322 // isn't an app... but we can only be in that case for
12323 // things that directly call the IActivityManager API, which
12324 // are already core system stuff so don't matter for this.
12325 r.curApp = filter.receiverList.app;
12326 filter.receiverList.app.curReceiver = r;
12327 updateOomAdjLocked();
12328 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012329 }
12330 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012331 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012332 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012333 Log.i(TAG, "Delivering to " + filter.receiverList.app
12334 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012335 }
12336 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12337 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012338 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012339 if (ordered) {
12340 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12341 }
12342 } catch (RemoteException e) {
12343 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12344 if (ordered) {
12345 r.receiver = null;
12346 r.curFilter = null;
12347 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012348 if (filter.receiverList.app != null) {
12349 filter.receiverList.app.curReceiver = null;
12350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012351 }
12352 }
12353 }
12354 }
12355
Dianne Hackborn12527f92009-11-11 17:39:50 -080012356 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12357 if (r.callingUid < 0) {
12358 // This was from a registerReceiver() call; ignore it.
12359 return;
12360 }
12361 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12362 MAX_BROADCAST_HISTORY-1);
12363 r.finishTime = SystemClock.uptimeMillis();
12364 mBroadcastHistory[0] = r;
12365 }
12366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012367 private final void processNextBroadcast(boolean fromMsg) {
12368 synchronized(this) {
12369 BroadcastRecord r;
12370
12371 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12372 + mParallelBroadcasts.size() + " broadcasts, "
12373 + mOrderedBroadcasts.size() + " serialized broadcasts");
12374
12375 updateCpuStats();
12376
12377 if (fromMsg) {
12378 mBroadcastsScheduled = false;
12379 }
12380
12381 // First, deliver any non-serialized broadcasts right away.
12382 while (mParallelBroadcasts.size() > 0) {
12383 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012384 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012385 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012386 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12387 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012388 for (int i=0; i<N; i++) {
12389 Object target = r.receivers.get(i);
12390 if (DEBUG_BROADCAST) Log.v(TAG,
12391 "Delivering non-serialized to registered "
12392 + target + ": " + r);
12393 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12394 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012395 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012396 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12397 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012398 }
12399
12400 // Now take care of the next serialized one...
12401
12402 // If we are waiting for a process to come up to handle the next
12403 // broadcast, then do nothing at this point. Just in case, we
12404 // check that the process we're waiting for still exists.
12405 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012406 if (DEBUG_BROADCAST_LIGHT) {
12407 Log.v(TAG, "processNextBroadcast: waiting for "
12408 + mPendingBroadcast.curApp);
12409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012410
12411 boolean isDead;
12412 synchronized (mPidsSelfLocked) {
12413 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12414 }
12415 if (!isDead) {
12416 // It's still alive, so keep waiting
12417 return;
12418 } else {
12419 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12420 + " died before responding to broadcast");
12421 mPendingBroadcast = null;
12422 }
12423 }
12424
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012425 boolean looped = false;
12426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012427 do {
12428 if (mOrderedBroadcasts.size() == 0) {
12429 // No more broadcasts pending, so all done!
12430 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012431 if (looped) {
12432 // If we had finished the last ordered broadcast, then
12433 // make sure all processes have correct oom and sched
12434 // adjustments.
12435 updateOomAdjLocked();
12436 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012437 return;
12438 }
12439 r = mOrderedBroadcasts.get(0);
12440 boolean forceReceive = false;
12441
12442 // Ensure that even if something goes awry with the timeout
12443 // detection, we catch "hung" broadcasts here, discard them,
12444 // and continue to make progress.
12445 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12446 long now = SystemClock.uptimeMillis();
12447 if (r.dispatchTime > 0) {
12448 if ((numReceivers > 0) &&
12449 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12450 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12451 + " now=" + now
12452 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012453 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012454 + " intent=" + r.intent
12455 + " numReceivers=" + numReceivers
12456 + " nextReceiver=" + r.nextReceiver
12457 + " state=" + r.state);
12458 broadcastTimeout(); // forcibly finish this broadcast
12459 forceReceive = true;
12460 r.state = BroadcastRecord.IDLE;
12461 }
12462 }
12463
12464 if (r.state != BroadcastRecord.IDLE) {
12465 if (DEBUG_BROADCAST) Log.d(TAG,
12466 "processNextBroadcast() called when not idle (state="
12467 + r.state + ")");
12468 return;
12469 }
12470
12471 if (r.receivers == null || r.nextReceiver >= numReceivers
12472 || r.resultAbort || forceReceive) {
12473 // No more receivers for this broadcast! Send the final
12474 // result if requested...
12475 if (r.resultTo != null) {
12476 try {
12477 if (DEBUG_BROADCAST) {
12478 int seq = r.intent.getIntExtra("seq", -1);
12479 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12480 + " seq=" + seq + " app=" + r.callerApp);
12481 }
12482 performReceive(r.callerApp, r.resultTo,
12483 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012484 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012485 } catch (RemoteException e) {
12486 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12487 }
12488 }
12489
12490 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12491 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12492
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012493 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12494 + r);
12495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012496 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012497 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012498 mOrderedBroadcasts.remove(0);
12499 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012500 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012501 continue;
12502 }
12503 } while (r == null);
12504
12505 // Get the next receiver...
12506 int recIdx = r.nextReceiver++;
12507
12508 // Keep track of when this receiver started, and make sure there
12509 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012510 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012511 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012512 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012513
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012514 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12515 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012516 if (DEBUG_BROADCAST) Log.v(TAG,
12517 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012518 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012519 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012520 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012521 }
12522
12523 Object nextReceiver = r.receivers.get(recIdx);
12524 if (nextReceiver instanceof BroadcastFilter) {
12525 // Simple case: this is a registered receiver who gets
12526 // a direct call.
12527 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12528 if (DEBUG_BROADCAST) Log.v(TAG,
12529 "Delivering serialized to registered "
12530 + filter + ": " + r);
12531 deliverToRegisteredReceiver(r, filter, r.ordered);
12532 if (r.receiver == null || !r.ordered) {
12533 // The receiver has already finished, so schedule to
12534 // process the next one.
12535 r.state = BroadcastRecord.IDLE;
12536 scheduleBroadcastsLocked();
12537 }
12538 return;
12539 }
12540
12541 // Hard case: need to instantiate the receiver, possibly
12542 // starting its application process to host it.
12543
12544 ResolveInfo info =
12545 (ResolveInfo)nextReceiver;
12546
12547 boolean skip = false;
12548 int perm = checkComponentPermission(info.activityInfo.permission,
12549 r.callingPid, r.callingUid,
12550 info.activityInfo.exported
12551 ? -1 : info.activityInfo.applicationInfo.uid);
12552 if (perm != PackageManager.PERMISSION_GRANTED) {
12553 Log.w(TAG, "Permission Denial: broadcasting "
12554 + r.intent.toString()
12555 + " from " + r.callerPackage + " (pid=" + r.callingPid
12556 + ", uid=" + r.callingUid + ")"
12557 + " requires " + info.activityInfo.permission
12558 + " due to receiver " + info.activityInfo.packageName
12559 + "/" + info.activityInfo.name);
12560 skip = true;
12561 }
12562 if (r.callingUid != Process.SYSTEM_UID &&
12563 r.requiredPermission != null) {
12564 try {
12565 perm = ActivityThread.getPackageManager().
12566 checkPermission(r.requiredPermission,
12567 info.activityInfo.applicationInfo.packageName);
12568 } catch (RemoteException e) {
12569 perm = PackageManager.PERMISSION_DENIED;
12570 }
12571 if (perm != PackageManager.PERMISSION_GRANTED) {
12572 Log.w(TAG, "Permission Denial: receiving "
12573 + r.intent + " to "
12574 + info.activityInfo.applicationInfo.packageName
12575 + " requires " + r.requiredPermission
12576 + " due to sender " + r.callerPackage
12577 + " (uid " + r.callingUid + ")");
12578 skip = true;
12579 }
12580 }
12581 if (r.curApp != null && r.curApp.crashing) {
12582 // If the target process is crashing, just skip it.
12583 skip = true;
12584 }
12585
12586 if (skip) {
12587 r.receiver = null;
12588 r.curFilter = null;
12589 r.state = BroadcastRecord.IDLE;
12590 scheduleBroadcastsLocked();
12591 return;
12592 }
12593
12594 r.state = BroadcastRecord.APP_RECEIVE;
12595 String targetProcess = info.activityInfo.processName;
12596 r.curComponent = new ComponentName(
12597 info.activityInfo.applicationInfo.packageName,
12598 info.activityInfo.name);
12599 r.curReceiver = info.activityInfo;
12600
12601 // Is this receiver's application already running?
12602 ProcessRecord app = getProcessRecordLocked(targetProcess,
12603 info.activityInfo.applicationInfo.uid);
12604 if (app != null && app.thread != null) {
12605 try {
12606 processCurBroadcastLocked(r, app);
12607 return;
12608 } catch (RemoteException e) {
12609 Log.w(TAG, "Exception when sending broadcast to "
12610 + r.curComponent, e);
12611 }
12612
12613 // If a dead object exception was thrown -- fall through to
12614 // restart the application.
12615 }
12616
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012617 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012618 if ((r.curApp=startProcessLocked(targetProcess,
12619 info.activityInfo.applicationInfo, true,
12620 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012621 "broadcast", r.curComponent,
12622 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12623 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012624 // Ah, this recipient is unavailable. Finish it if necessary,
12625 // and mark the broadcast record as ready for the next.
12626 Log.w(TAG, "Unable to launch app "
12627 + info.activityInfo.applicationInfo.packageName + "/"
12628 + info.activityInfo.applicationInfo.uid + " for broadcast "
12629 + r.intent + ": process is bad");
12630 logBroadcastReceiverDiscard(r);
12631 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12632 r.resultExtras, r.resultAbort, true);
12633 scheduleBroadcastsLocked();
12634 r.state = BroadcastRecord.IDLE;
12635 return;
12636 }
12637
12638 mPendingBroadcast = r;
12639 }
12640 }
12641
12642 // =========================================================
12643 // INSTRUMENTATION
12644 // =========================================================
12645
12646 public boolean startInstrumentation(ComponentName className,
12647 String profileFile, int flags, Bundle arguments,
12648 IInstrumentationWatcher watcher) {
12649 // Refuse possible leaked file descriptors
12650 if (arguments != null && arguments.hasFileDescriptors()) {
12651 throw new IllegalArgumentException("File descriptors passed in Bundle");
12652 }
12653
12654 synchronized(this) {
12655 InstrumentationInfo ii = null;
12656 ApplicationInfo ai = null;
12657 try {
12658 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012659 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012660 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012661 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012662 } catch (PackageManager.NameNotFoundException e) {
12663 }
12664 if (ii == null) {
12665 reportStartInstrumentationFailure(watcher, className,
12666 "Unable to find instrumentation info for: " + className);
12667 return false;
12668 }
12669 if (ai == null) {
12670 reportStartInstrumentationFailure(watcher, className,
12671 "Unable to find instrumentation target package: " + ii.targetPackage);
12672 return false;
12673 }
12674
12675 int match = mContext.getPackageManager().checkSignatures(
12676 ii.targetPackage, ii.packageName);
12677 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12678 String msg = "Permission Denial: starting instrumentation "
12679 + className + " from pid="
12680 + Binder.getCallingPid()
12681 + ", uid=" + Binder.getCallingPid()
12682 + " not allowed because package " + ii.packageName
12683 + " does not have a signature matching the target "
12684 + ii.targetPackage;
12685 reportStartInstrumentationFailure(watcher, className, msg);
12686 throw new SecurityException(msg);
12687 }
12688
12689 final long origId = Binder.clearCallingIdentity();
12690 uninstallPackageLocked(ii.targetPackage, -1, true);
12691 ProcessRecord app = addAppLocked(ai);
12692 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012693 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012694 app.instrumentationProfileFile = profileFile;
12695 app.instrumentationArguments = arguments;
12696 app.instrumentationWatcher = watcher;
12697 app.instrumentationResultClass = className;
12698 Binder.restoreCallingIdentity(origId);
12699 }
12700
12701 return true;
12702 }
12703
12704 /**
12705 * Report errors that occur while attempting to start Instrumentation. Always writes the
12706 * error to the logs, but if somebody is watching, send the report there too. This enables
12707 * the "am" command to report errors with more information.
12708 *
12709 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12710 * @param cn The component name of the instrumentation.
12711 * @param report The error report.
12712 */
12713 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12714 ComponentName cn, String report) {
12715 Log.w(TAG, report);
12716 try {
12717 if (watcher != null) {
12718 Bundle results = new Bundle();
12719 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12720 results.putString("Error", report);
12721 watcher.instrumentationStatus(cn, -1, results);
12722 }
12723 } catch (RemoteException e) {
12724 Log.w(TAG, e);
12725 }
12726 }
12727
12728 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12729 if (app.instrumentationWatcher != null) {
12730 try {
12731 // NOTE: IInstrumentationWatcher *must* be oneway here
12732 app.instrumentationWatcher.instrumentationFinished(
12733 app.instrumentationClass,
12734 resultCode,
12735 results);
12736 } catch (RemoteException e) {
12737 }
12738 }
12739 app.instrumentationWatcher = null;
12740 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012741 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012742 app.instrumentationProfileFile = null;
12743 app.instrumentationArguments = null;
12744
12745 uninstallPackageLocked(app.processName, -1, false);
12746 }
12747
12748 public void finishInstrumentation(IApplicationThread target,
12749 int resultCode, Bundle results) {
12750 // Refuse possible leaked file descriptors
12751 if (results != null && results.hasFileDescriptors()) {
12752 throw new IllegalArgumentException("File descriptors passed in Intent");
12753 }
12754
12755 synchronized(this) {
12756 ProcessRecord app = getRecordForAppLocked(target);
12757 if (app == null) {
12758 Log.w(TAG, "finishInstrumentation: no app for " + target);
12759 return;
12760 }
12761 final long origId = Binder.clearCallingIdentity();
12762 finishInstrumentationLocked(app, resultCode, results);
12763 Binder.restoreCallingIdentity(origId);
12764 }
12765 }
12766
12767 // =========================================================
12768 // CONFIGURATION
12769 // =========================================================
12770
12771 public ConfigurationInfo getDeviceConfigurationInfo() {
12772 ConfigurationInfo config = new ConfigurationInfo();
12773 synchronized (this) {
12774 config.reqTouchScreen = mConfiguration.touchscreen;
12775 config.reqKeyboardType = mConfiguration.keyboard;
12776 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012777 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12778 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012779 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12780 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012781 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12782 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012783 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12784 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012785 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012786 }
12787 return config;
12788 }
12789
12790 public Configuration getConfiguration() {
12791 Configuration ci;
12792 synchronized(this) {
12793 ci = new Configuration(mConfiguration);
12794 }
12795 return ci;
12796 }
12797
12798 public void updateConfiguration(Configuration values) {
12799 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12800 "updateConfiguration()");
12801
12802 synchronized(this) {
12803 if (values == null && mWindowManager != null) {
12804 // sentinel: fetch the current configuration from the window manager
12805 values = mWindowManager.computeNewConfiguration();
12806 }
12807
12808 final long origId = Binder.clearCallingIdentity();
12809 updateConfigurationLocked(values, null);
12810 Binder.restoreCallingIdentity(origId);
12811 }
12812 }
12813
12814 /**
12815 * Do either or both things: (1) change the current configuration, and (2)
12816 * make sure the given activity is running with the (now) current
12817 * configuration. Returns true if the activity has been left running, or
12818 * false if <var>starting</var> is being destroyed to match the new
12819 * configuration.
12820 */
12821 public boolean updateConfigurationLocked(Configuration values,
12822 HistoryRecord starting) {
12823 int changes = 0;
12824
12825 boolean kept = true;
12826
12827 if (values != null) {
12828 Configuration newConfig = new Configuration(mConfiguration);
12829 changes = newConfig.updateFrom(values);
12830 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012831 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012832 Log.i(TAG, "Updating configuration to: " + values);
12833 }
12834
12835 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12836
12837 if (values.locale != null) {
12838 saveLocaleLocked(values.locale,
12839 !values.locale.equals(mConfiguration.locale),
12840 values.userSetLocale);
12841 }
12842
12843 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012844 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080012845
12846 AttributeCache ac = AttributeCache.instance();
12847 if (ac != null) {
12848 ac.updateConfiguration(mConfiguration);
12849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012850
12851 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12852 msg.obj = new Configuration(mConfiguration);
12853 mHandler.sendMessage(msg);
12854
12855 final int N = mLRUProcesses.size();
12856 for (int i=0; i<N; i++) {
12857 ProcessRecord app = mLRUProcesses.get(i);
12858 try {
12859 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012860 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12861 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012862 app.thread.scheduleConfigurationChanged(mConfiguration);
12863 }
12864 } catch (Exception e) {
12865 }
12866 }
12867 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012868 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012869 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12870 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012871 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
12872 broadcastIntentLocked(null, null,
12873 new Intent(Intent.ACTION_LOCALE_CHANGED),
12874 null, null, 0, null, null,
12875 null, false, false, MY_PID, Process.SYSTEM_UID);
12876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012877 }
12878 }
12879
12880 if (changes != 0 && starting == null) {
12881 // If the configuration changed, and the caller is not already
12882 // in the process of starting an activity, then find the top
12883 // activity to check if its configuration needs to change.
12884 starting = topRunningActivityLocked(null);
12885 }
12886
12887 if (starting != null) {
12888 kept = ensureActivityConfigurationLocked(starting, changes);
12889 if (kept) {
12890 // If this didn't result in the starting activity being
12891 // destroyed, then we need to make sure at this point that all
12892 // other activities are made visible.
12893 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12894 + ", ensuring others are correct.");
12895 ensureActivitiesVisibleLocked(starting, changes);
12896 }
12897 }
12898
12899 return kept;
12900 }
12901
12902 private final boolean relaunchActivityLocked(HistoryRecord r,
12903 int changes, boolean andResume) {
12904 List<ResultInfo> results = null;
12905 List<Intent> newIntents = null;
12906 if (andResume) {
12907 results = r.results;
12908 newIntents = r.newIntents;
12909 }
12910 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12911 + " with results=" + results + " newIntents=" + newIntents
12912 + " andResume=" + andResume);
12913 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12914 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12915 r.task.taskId, r.shortComponentName);
12916
12917 r.startFreezingScreenLocked(r.app, 0);
12918
12919 try {
12920 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12921 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12922 changes, !andResume);
12923 // Note: don't need to call pauseIfSleepingLocked() here, because
12924 // the caller will only pass in 'andResume' if this activity is
12925 // currently resumed, which implies we aren't sleeping.
12926 } catch (RemoteException e) {
12927 return false;
12928 }
12929
12930 if (andResume) {
12931 r.results = null;
12932 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012933 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012934 }
12935
12936 return true;
12937 }
12938
12939 /**
12940 * Make sure the given activity matches the current configuration. Returns
12941 * false if the activity had to be destroyed. Returns true if the
12942 * configuration is the same, or the activity will remain running as-is
12943 * for whatever reason. Ensures the HistoryRecord is updated with the
12944 * correct configuration and all other bookkeeping is handled.
12945 */
12946 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12947 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012948 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12949 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012950
12951 // Short circuit: if the two configurations are the exact same
12952 // object (the common case), then there is nothing to do.
12953 Configuration newConfig = mConfiguration;
12954 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012955 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12956 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012957 return true;
12958 }
12959
12960 // We don't worry about activities that are finishing.
12961 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012962 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012963 "Configuration doesn't matter in finishing " + r);
12964 r.stopFreezingScreenLocked(false);
12965 return true;
12966 }
12967
12968 // Okay we now are going to make this activity have the new config.
12969 // But then we need to figure out how it needs to deal with that.
12970 Configuration oldConfig = r.configuration;
12971 r.configuration = newConfig;
12972
12973 // If the activity isn't currently running, just leave the new
12974 // configuration and it will pick that up next time it starts.
12975 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012976 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012977 "Configuration doesn't matter not running " + r);
12978 r.stopFreezingScreenLocked(false);
12979 return true;
12980 }
12981
12982 // If the activity isn't persistent, there is a chance we will
12983 // need to restart it.
12984 if (!r.persistent) {
12985
12986 // Figure out what has changed between the two configurations.
12987 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012988 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
12989 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012990 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012991 + Integer.toHexString(r.info.configChanges)
12992 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012993 }
12994 if ((changes&(~r.info.configChanges)) != 0) {
12995 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12996 r.configChangeFlags |= changes;
12997 r.startFreezingScreenLocked(r.app, globalChanges);
12998 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012999 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13000 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013001 destroyActivityLocked(r, true);
13002 } else if (r.state == ActivityState.PAUSING) {
13003 // A little annoying: we are waiting for this activity to
13004 // finish pausing. Let's not do anything now, but just
13005 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013006 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13007 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013008 r.configDestroy = true;
13009 return true;
13010 } else if (r.state == ActivityState.RESUMED) {
13011 // Try to optimize this case: the configuration is changing
13012 // and we need to restart the top, resumed activity.
13013 // Instead of doing the normal handshaking, just say
13014 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013015 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13016 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013017 relaunchActivityLocked(r, r.configChangeFlags, true);
13018 r.configChangeFlags = 0;
13019 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013020 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13021 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013022 relaunchActivityLocked(r, r.configChangeFlags, false);
13023 r.configChangeFlags = 0;
13024 }
13025
13026 // All done... tell the caller we weren't able to keep this
13027 // activity around.
13028 return false;
13029 }
13030 }
13031
13032 // Default case: the activity can handle this new configuration, so
13033 // hand it over. Note that we don't need to give it the new
13034 // configuration, since we always send configuration changes to all
13035 // process when they happen so it can just use whatever configuration
13036 // it last got.
13037 if (r.app != null && r.app.thread != null) {
13038 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013039 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013040 r.app.thread.scheduleActivityConfigurationChanged(r);
13041 } catch (RemoteException e) {
13042 // If process died, whatever.
13043 }
13044 }
13045 r.stopFreezingScreenLocked(false);
13046
13047 return true;
13048 }
13049
13050 /**
13051 * Save the locale. You must be inside a synchronized (this) block.
13052 */
13053 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13054 if(isDiff) {
13055 SystemProperties.set("user.language", l.getLanguage());
13056 SystemProperties.set("user.region", l.getCountry());
13057 }
13058
13059 if(isPersist) {
13060 SystemProperties.set("persist.sys.language", l.getLanguage());
13061 SystemProperties.set("persist.sys.country", l.getCountry());
13062 SystemProperties.set("persist.sys.localevar", l.getVariant());
13063 }
13064 }
13065
13066 // =========================================================
13067 // LIFETIME MANAGEMENT
13068 // =========================================================
13069
13070 private final int computeOomAdjLocked(
13071 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13072 if (mAdjSeq == app.adjSeq) {
13073 // This adjustment has already been computed.
13074 return app.curAdj;
13075 }
13076
13077 if (app.thread == null) {
13078 app.adjSeq = mAdjSeq;
13079 return (app.curAdj=EMPTY_APP_ADJ);
13080 }
13081
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013082 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13083 // The max adjustment doesn't allow this app to be anything
13084 // below foreground, so it is not worth doing work for it.
13085 app.adjType = "fixed";
13086 app.adjSeq = mAdjSeq;
13087 app.curRawAdj = app.maxAdj;
13088 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13089 return (app.curAdj=app.maxAdj);
13090 }
13091
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013092 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013093 app.adjSource = null;
13094 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013095
The Android Open Source Project4df24232009-03-05 14:34:35 -080013096 // Determine the importance of the process, starting with most
13097 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013098 int adj;
13099 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013100 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013101 // The last app on the list is the foreground app.
13102 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013103 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013104 } else if (app.instrumentationClass != null) {
13105 // Don't want to kill running instrumentation.
13106 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013107 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013108 } else if (app.persistentActivities > 0) {
13109 // Special persistent activities... shouldn't be used these days.
13110 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013111 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013112 } else if (app.curReceiver != null ||
13113 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13114 // An app that is currently receiving a broadcast also
13115 // counts as being in the foreground.
13116 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013117 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013118 } else if (app.executingServices.size() > 0) {
13119 // An app that is currently executing a service callback also
13120 // counts as being in the foreground.
13121 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013122 app.adjType = "exec-service";
13123 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013124 // The user is aware of this app, so make it visible.
13125 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013126 app.adjType = "foreground-service";
13127 } else if (app.forcingToForeground != null) {
13128 // The user is aware of this app, so make it visible.
13129 adj = VISIBLE_APP_ADJ;
13130 app.adjType = "force-foreground";
13131 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013132 } else if (app == mHomeProcess) {
13133 // This process is hosting what we currently consider to be the
13134 // home app, so we don't want to let it go into the background.
13135 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013136 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013137 } else if ((N=app.activities.size()) != 0) {
13138 // This app is in the background with paused activities.
13139 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013140 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013141 for (int j=0; j<N; j++) {
13142 if (((HistoryRecord)app.activities.get(j)).visible) {
13143 // This app has a visible activity!
13144 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013145 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013146 break;
13147 }
13148 }
13149 } else {
13150 // A very not-needed process.
13151 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013152 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013153 }
13154
The Android Open Source Project4df24232009-03-05 14:34:35 -080013155 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013156 // there are applications dependent on our services or providers, but
13157 // this gives us a baseline and makes sure we don't get into an
13158 // infinite recursion.
13159 app.adjSeq = mAdjSeq;
13160 app.curRawAdj = adj;
13161 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13162
Christopher Tate6fa95972009-06-05 18:43:55 -070013163 if (mBackupTarget != null && app == mBackupTarget.app) {
13164 // If possible we want to avoid killing apps while they're being backed up
13165 if (adj > BACKUP_APP_ADJ) {
13166 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13167 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013168 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013169 }
13170 }
13171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013172 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013173 final long now = SystemClock.uptimeMillis();
13174 // This process is more important if the top activity is
13175 // bound to the service.
13176 Iterator jt = app.services.iterator();
13177 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13178 ServiceRecord s = (ServiceRecord)jt.next();
13179 if (s.startRequested) {
13180 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13181 // This service has seen some activity within
13182 // recent memory, so we will keep its process ahead
13183 // of the background processes.
13184 if (adj > SECONDARY_SERVER_ADJ) {
13185 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013186 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013187 }
13188 }
13189 }
13190 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13191 Iterator<ConnectionRecord> kt
13192 = s.connections.values().iterator();
13193 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13194 // XXX should compute this based on the max of
13195 // all connected clients.
13196 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013197 if (cr.binding.client == app) {
13198 // Binding to ourself is not interesting.
13199 continue;
13200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013201 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13202 ProcessRecord client = cr.binding.client;
13203 int myHiddenAdj = hiddenAdj;
13204 if (myHiddenAdj > client.hiddenAdj) {
13205 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13206 myHiddenAdj = client.hiddenAdj;
13207 } else {
13208 myHiddenAdj = VISIBLE_APP_ADJ;
13209 }
13210 }
13211 int clientAdj = computeOomAdjLocked(
13212 client, myHiddenAdj, TOP_APP);
13213 if (adj > clientAdj) {
13214 adj = clientAdj > VISIBLE_APP_ADJ
13215 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013216 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013217 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13218 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013219 app.adjSource = cr.binding.client;
13220 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013221 }
13222 }
13223 HistoryRecord a = cr.activity;
13224 //if (a != null) {
13225 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13226 //}
13227 if (a != null && adj > FOREGROUND_APP_ADJ &&
13228 (a.state == ActivityState.RESUMED
13229 || a.state == ActivityState.PAUSING)) {
13230 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013231 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013232 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13233 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013234 app.adjSource = a;
13235 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013236 }
13237 }
13238 }
13239 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013240
13241 // Finally, f this process has active services running in it, we
13242 // would like to avoid killing it unless it would prevent the current
13243 // application from running. By default we put the process in
13244 // with the rest of the background processes; as we scan through
13245 // its services we may bump it up from there.
13246 if (adj > hiddenAdj) {
13247 adj = hiddenAdj;
13248 app.adjType = "bg-services";
13249 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013250 }
13251
13252 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013253 Iterator jt = app.pubProviders.values().iterator();
13254 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13255 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13256 if (cpr.clients.size() != 0) {
13257 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13258 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13259 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013260 if (client == app) {
13261 // Being our own client is not interesting.
13262 continue;
13263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013264 int myHiddenAdj = hiddenAdj;
13265 if (myHiddenAdj > client.hiddenAdj) {
13266 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13267 myHiddenAdj = client.hiddenAdj;
13268 } else {
13269 myHiddenAdj = FOREGROUND_APP_ADJ;
13270 }
13271 }
13272 int clientAdj = computeOomAdjLocked(
13273 client, myHiddenAdj, TOP_APP);
13274 if (adj > clientAdj) {
13275 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013276 ? clientAdj : FOREGROUND_APP_ADJ;
13277 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013278 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13279 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013280 app.adjSource = client;
13281 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013282 }
13283 }
13284 }
13285 // If the provider has external (non-framework) process
13286 // dependencies, ensure that its adjustment is at least
13287 // FOREGROUND_APP_ADJ.
13288 if (cpr.externals != 0) {
13289 if (adj > FOREGROUND_APP_ADJ) {
13290 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013291 app.adjType = "provider";
13292 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013293 }
13294 }
13295 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013296
13297 // Finally, if this process has published any content providers,
13298 // then its adjustment makes it at least as important as any of the
13299 // processes using those providers, and no less important than
13300 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13301 if (adj > CONTENT_PROVIDER_ADJ) {
13302 adj = CONTENT_PROVIDER_ADJ;
13303 app.adjType = "pub-providers";
13304 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013305 }
13306
13307 app.curRawAdj = adj;
13308
13309 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13310 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13311 if (adj > app.maxAdj) {
13312 adj = app.maxAdj;
13313 }
13314
13315 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013316 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013317 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13318 : Process.THREAD_GROUP_DEFAULT;
13319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013320 return adj;
13321 }
13322
13323 /**
13324 * Ask a given process to GC right now.
13325 */
13326 final void performAppGcLocked(ProcessRecord app) {
13327 try {
13328 app.lastRequestedGc = SystemClock.uptimeMillis();
13329 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013330 if (app.reportLowMemory) {
13331 app.reportLowMemory = false;
13332 app.thread.scheduleLowMemory();
13333 } else {
13334 app.thread.processInBackground();
13335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013336 }
13337 } catch (Exception e) {
13338 // whatever.
13339 }
13340 }
13341
13342 /**
13343 * Returns true if things are idle enough to perform GCs.
13344 */
13345 private final boolean canGcNow() {
13346 return mParallelBroadcasts.size() == 0
13347 && mOrderedBroadcasts.size() == 0
13348 && (mSleeping || (mResumedActivity != null &&
13349 mResumedActivity.idle));
13350 }
13351
13352 /**
13353 * Perform GCs on all processes that are waiting for it, but only
13354 * if things are idle.
13355 */
13356 final void performAppGcsLocked() {
13357 final int N = mProcessesToGc.size();
13358 if (N <= 0) {
13359 return;
13360 }
13361 if (canGcNow()) {
13362 while (mProcessesToGc.size() > 0) {
13363 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013364 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13365 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13366 <= SystemClock.uptimeMillis()) {
13367 // To avoid spamming the system, we will GC processes one
13368 // at a time, waiting a few seconds between each.
13369 performAppGcLocked(proc);
13370 scheduleAppGcsLocked();
13371 return;
13372 } else {
13373 // It hasn't been long enough since we last GCed this
13374 // process... put it in the list to wait for its time.
13375 addProcessToGcListLocked(proc);
13376 break;
13377 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013378 }
13379 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013380
13381 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013382 }
13383 }
13384
13385 /**
13386 * If all looks good, perform GCs on all processes waiting for them.
13387 */
13388 final void performAppGcsIfAppropriateLocked() {
13389 if (canGcNow()) {
13390 performAppGcsLocked();
13391 return;
13392 }
13393 // Still not idle, wait some more.
13394 scheduleAppGcsLocked();
13395 }
13396
13397 /**
13398 * Schedule the execution of all pending app GCs.
13399 */
13400 final void scheduleAppGcsLocked() {
13401 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013402
13403 if (mProcessesToGc.size() > 0) {
13404 // Schedule a GC for the time to the next process.
13405 ProcessRecord proc = mProcessesToGc.get(0);
13406 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13407
13408 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13409 long now = SystemClock.uptimeMillis();
13410 if (when < (now+GC_TIMEOUT)) {
13411 when = now + GC_TIMEOUT;
13412 }
13413 mHandler.sendMessageAtTime(msg, when);
13414 }
13415 }
13416
13417 /**
13418 * Add a process to the array of processes waiting to be GCed. Keeps the
13419 * list in sorted order by the last GC time. The process can't already be
13420 * on the list.
13421 */
13422 final void addProcessToGcListLocked(ProcessRecord proc) {
13423 boolean added = false;
13424 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13425 if (mProcessesToGc.get(i).lastRequestedGc <
13426 proc.lastRequestedGc) {
13427 added = true;
13428 mProcessesToGc.add(i+1, proc);
13429 break;
13430 }
13431 }
13432 if (!added) {
13433 mProcessesToGc.add(0, proc);
13434 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013435 }
13436
13437 /**
13438 * Set up to ask a process to GC itself. This will either do it
13439 * immediately, or put it on the list of processes to gc the next
13440 * time things are idle.
13441 */
13442 final void scheduleAppGcLocked(ProcessRecord app) {
13443 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013444 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013445 return;
13446 }
13447 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013448 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013449 scheduleAppGcsLocked();
13450 }
13451 }
13452
13453 private final boolean updateOomAdjLocked(
13454 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13455 app.hiddenAdj = hiddenAdj;
13456
13457 if (app.thread == null) {
13458 return true;
13459 }
13460
13461 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013463 if (app.pid != 0 && app.pid != MY_PID) {
13464 if (app.curRawAdj != app.setRawAdj) {
13465 if (app.curRawAdj > FOREGROUND_APP_ADJ
13466 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13467 // If this app is transitioning from foreground to
13468 // non-foreground, have it do a gc.
13469 scheduleAppGcLocked(app);
13470 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13471 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13472 // Likewise do a gc when an app is moving in to the
13473 // background (such as a service stopping).
13474 scheduleAppGcLocked(app);
13475 }
13476 app.setRawAdj = app.curRawAdj;
13477 }
13478 if (adj != app.setAdj) {
13479 if (Process.setOomAdj(app.pid, adj)) {
13480 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13481 TAG, "Set app " + app.processName +
13482 " oom adj to " + adj);
13483 app.setAdj = adj;
13484 } else {
13485 return false;
13486 }
13487 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013488 if (app.setSchedGroup != app.curSchedGroup) {
13489 app.setSchedGroup = app.curSchedGroup;
13490 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13491 "Setting process group of " + app.processName
13492 + " to " + app.curSchedGroup);
13493 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013494 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013495 try {
13496 Process.setProcessGroup(app.pid, app.curSchedGroup);
13497 } catch (Exception e) {
13498 Log.w(TAG, "Failed setting process group of " + app.pid
13499 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013500 e.printStackTrace();
13501 } finally {
13502 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013503 }
13504 }
13505 if (false) {
13506 if (app.thread != null) {
13507 try {
13508 app.thread.setSchedulingGroup(app.curSchedGroup);
13509 } catch (RemoteException e) {
13510 }
13511 }
13512 }
13513 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013514 }
13515
13516 return true;
13517 }
13518
13519 private final HistoryRecord resumedAppLocked() {
13520 HistoryRecord resumedActivity = mResumedActivity;
13521 if (resumedActivity == null || resumedActivity.app == null) {
13522 resumedActivity = mPausingActivity;
13523 if (resumedActivity == null || resumedActivity.app == null) {
13524 resumedActivity = topRunningActivityLocked(null);
13525 }
13526 }
13527 return resumedActivity;
13528 }
13529
13530 private final boolean updateOomAdjLocked(ProcessRecord app) {
13531 final HistoryRecord TOP_ACT = resumedAppLocked();
13532 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13533 int curAdj = app.curAdj;
13534 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13535 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13536
13537 mAdjSeq++;
13538
13539 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13540 if (res) {
13541 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13542 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13543 if (nowHidden != wasHidden) {
13544 // Changed to/from hidden state, so apps after it in the LRU
13545 // list may also be changed.
13546 updateOomAdjLocked();
13547 }
13548 }
13549 return res;
13550 }
13551
13552 private final boolean updateOomAdjLocked() {
13553 boolean didOomAdj = true;
13554 final HistoryRecord TOP_ACT = resumedAppLocked();
13555 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13556
13557 if (false) {
13558 RuntimeException e = new RuntimeException();
13559 e.fillInStackTrace();
13560 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13561 }
13562
13563 mAdjSeq++;
13564
13565 // First try updating the OOM adjustment for each of the
13566 // application processes based on their current state.
13567 int i = mLRUProcesses.size();
13568 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13569 while (i > 0) {
13570 i--;
13571 ProcessRecord app = mLRUProcesses.get(i);
13572 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13573 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13574 && app.curAdj == curHiddenAdj) {
13575 curHiddenAdj++;
13576 }
13577 } else {
13578 didOomAdj = false;
13579 }
13580 }
13581
13582 // todo: for now pretend like OOM ADJ didn't work, because things
13583 // aren't behaving as expected on Linux -- it's not killing processes.
13584 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13585 }
13586
13587 private final void trimApplications() {
13588 synchronized (this) {
13589 int i;
13590
13591 // First remove any unused application processes whose package
13592 // has been removed.
13593 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13594 final ProcessRecord app = mRemovedProcesses.get(i);
13595 if (app.activities.size() == 0
13596 && app.curReceiver == null && app.services.size() == 0) {
13597 Log.i(
13598 TAG, "Exiting empty application process "
13599 + app.processName + " ("
13600 + (app.thread != null ? app.thread.asBinder() : null)
13601 + ")\n");
13602 if (app.pid > 0 && app.pid != MY_PID) {
13603 Process.killProcess(app.pid);
13604 } else {
13605 try {
13606 app.thread.scheduleExit();
13607 } catch (Exception e) {
13608 // Ignore exceptions.
13609 }
13610 }
13611 cleanUpApplicationRecordLocked(app, false, -1);
13612 mRemovedProcesses.remove(i);
13613
13614 if (app.persistent) {
13615 if (app.persistent) {
13616 addAppLocked(app.info);
13617 }
13618 }
13619 }
13620 }
13621
13622 // Now try updating the OOM adjustment for each of the
13623 // application processes based on their current state.
13624 // If the setOomAdj() API is not supported, then go with our
13625 // back-up plan...
13626 if (!updateOomAdjLocked()) {
13627
13628 // Count how many processes are running services.
13629 int numServiceProcs = 0;
13630 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13631 final ProcessRecord app = mLRUProcesses.get(i);
13632
13633 if (app.persistent || app.services.size() != 0
13634 || app.curReceiver != null
13635 || app.persistentActivities > 0) {
13636 // Don't count processes holding services against our
13637 // maximum process count.
13638 if (localLOGV) Log.v(
13639 TAG, "Not trimming app " + app + " with services: "
13640 + app.services);
13641 numServiceProcs++;
13642 }
13643 }
13644
13645 int curMaxProcs = mProcessLimit;
13646 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13647 if (mAlwaysFinishActivities) {
13648 curMaxProcs = 1;
13649 }
13650 curMaxProcs += numServiceProcs;
13651
13652 // Quit as many processes as we can to get down to the desired
13653 // process count. First remove any processes that no longer
13654 // have activites running in them.
13655 for ( i=0;
13656 i<mLRUProcesses.size()
13657 && mLRUProcesses.size() > curMaxProcs;
13658 i++) {
13659 final ProcessRecord app = mLRUProcesses.get(i);
13660 // Quit an application only if it is not currently
13661 // running any activities.
13662 if (!app.persistent && app.activities.size() == 0
13663 && app.curReceiver == null && app.services.size() == 0) {
13664 Log.i(
13665 TAG, "Exiting empty application process "
13666 + app.processName + " ("
13667 + (app.thread != null ? app.thread.asBinder() : null)
13668 + ")\n");
13669 if (app.pid > 0 && app.pid != MY_PID) {
13670 Process.killProcess(app.pid);
13671 } else {
13672 try {
13673 app.thread.scheduleExit();
13674 } catch (Exception e) {
13675 // Ignore exceptions.
13676 }
13677 }
13678 // todo: For now we assume the application is not buggy
13679 // or evil, and will quit as a result of our request.
13680 // Eventually we need to drive this off of the death
13681 // notification, and kill the process if it takes too long.
13682 cleanUpApplicationRecordLocked(app, false, i);
13683 i--;
13684 }
13685 }
13686
13687 // If we still have too many processes, now from the least
13688 // recently used process we start finishing activities.
13689 if (Config.LOGV) Log.v(
13690 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13691 " of " + curMaxProcs + " processes");
13692 for ( i=0;
13693 i<mLRUProcesses.size()
13694 && mLRUProcesses.size() > curMaxProcs;
13695 i++) {
13696 final ProcessRecord app = mLRUProcesses.get(i);
13697 // Quit the application only if we have a state saved for
13698 // all of its activities.
13699 boolean canQuit = !app.persistent && app.curReceiver == null
13700 && app.services.size() == 0
13701 && app.persistentActivities == 0;
13702 int NUMA = app.activities.size();
13703 int j;
13704 if (Config.LOGV) Log.v(
13705 TAG, "Looking to quit " + app.processName);
13706 for (j=0; j<NUMA && canQuit; j++) {
13707 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13708 if (Config.LOGV) Log.v(
13709 TAG, " " + r.intent.getComponent().flattenToShortString()
13710 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13711 canQuit = (r.haveState || !r.stateNotNeeded)
13712 && !r.visible && r.stopped;
13713 }
13714 if (canQuit) {
13715 // Finish all of the activities, and then the app itself.
13716 for (j=0; j<NUMA; j++) {
13717 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13718 if (!r.finishing) {
13719 destroyActivityLocked(r, false);
13720 }
13721 r.resultTo = null;
13722 }
13723 Log.i(TAG, "Exiting application process "
13724 + app.processName + " ("
13725 + (app.thread != null ? app.thread.asBinder() : null)
13726 + ")\n");
13727 if (app.pid > 0 && app.pid != MY_PID) {
13728 Process.killProcess(app.pid);
13729 } else {
13730 try {
13731 app.thread.scheduleExit();
13732 } catch (Exception e) {
13733 // Ignore exceptions.
13734 }
13735 }
13736 // todo: For now we assume the application is not buggy
13737 // or evil, and will quit as a result of our request.
13738 // Eventually we need to drive this off of the death
13739 // notification, and kill the process if it takes too long.
13740 cleanUpApplicationRecordLocked(app, false, i);
13741 i--;
13742 //dump();
13743 }
13744 }
13745
13746 }
13747
13748 int curMaxActivities = MAX_ACTIVITIES;
13749 if (mAlwaysFinishActivities) {
13750 curMaxActivities = 1;
13751 }
13752
13753 // Finally, if there are too many activities now running, try to
13754 // finish as many as we can to get back down to the limit.
13755 for ( i=0;
13756 i<mLRUActivities.size()
13757 && mLRUActivities.size() > curMaxActivities;
13758 i++) {
13759 final HistoryRecord r
13760 = (HistoryRecord)mLRUActivities.get(i);
13761
13762 // We can finish this one if we have its icicle saved and
13763 // it is not persistent.
13764 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13765 && r.stopped && !r.persistent && !r.finishing) {
13766 final int origSize = mLRUActivities.size();
13767 destroyActivityLocked(r, true);
13768
13769 // This will remove it from the LRU list, so keep
13770 // our index at the same value. Note that this check to
13771 // see if the size changes is just paranoia -- if
13772 // something unexpected happens, we don't want to end up
13773 // in an infinite loop.
13774 if (origSize > mLRUActivities.size()) {
13775 i--;
13776 }
13777 }
13778 }
13779 }
13780 }
13781
13782 /** This method sends the specified signal to each of the persistent apps */
13783 public void signalPersistentProcesses(int sig) throws RemoteException {
13784 if (sig != Process.SIGNAL_USR1) {
13785 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13786 }
13787
13788 synchronized (this) {
13789 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13790 != PackageManager.PERMISSION_GRANTED) {
13791 throw new SecurityException("Requires permission "
13792 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13793 }
13794
13795 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13796 ProcessRecord r = mLRUProcesses.get(i);
13797 if (r.thread != null && r.persistent) {
13798 Process.sendSignal(r.pid, sig);
13799 }
13800 }
13801 }
13802 }
13803
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013804 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013805 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013806
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013807 try {
13808 synchronized (this) {
13809 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13810 // its own permission.
13811 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13812 != PackageManager.PERMISSION_GRANTED) {
13813 throw new SecurityException("Requires permission "
13814 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013815 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013816
13817 if (start && fd == null) {
13818 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013819 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013820
13821 ProcessRecord proc = null;
13822 try {
13823 int pid = Integer.parseInt(process);
13824 synchronized (mPidsSelfLocked) {
13825 proc = mPidsSelfLocked.get(pid);
13826 }
13827 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013828 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013829
13830 if (proc == null) {
13831 HashMap<String, SparseArray<ProcessRecord>> all
13832 = mProcessNames.getMap();
13833 SparseArray<ProcessRecord> procs = all.get(process);
13834 if (procs != null && procs.size() > 0) {
13835 proc = procs.valueAt(0);
13836 }
13837 }
13838
13839 if (proc == null || proc.thread == null) {
13840 throw new IllegalArgumentException("Unknown process: " + process);
13841 }
13842
13843 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13844 if (isSecure) {
13845 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13846 throw new SecurityException("Process not debuggable: " + proc);
13847 }
13848 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013849
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013850 proc.thread.profilerControl(start, path, fd);
13851 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013852 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013853 }
13854 } catch (RemoteException e) {
13855 throw new IllegalStateException("Process disappeared");
13856 } finally {
13857 if (fd != null) {
13858 try {
13859 fd.close();
13860 } catch (IOException e) {
13861 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013862 }
13863 }
13864 }
13865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013866 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13867 public void monitor() {
13868 synchronized (this) { }
13869 }
13870}