blob: 9e9552aec479b4951ad51aecf781e93a2639f148 [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));
Magnus Edlund7bb25812010-02-24 15:45:06 +01001908 if (app != null && app.pid > 0) {
1909 if (!knownToBeDead || app.thread == null) {
1910 return app;
1911 } else {
1912 // An application record is attached to a previous process,
1913 // clean it up now.
1914 handleAppDiedLocked(app, true);
1915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 }
Magnus Edlund7bb25812010-02-24 15:45:06 +01001917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918 String hostingNameStr = hostingName != null
1919 ? hostingName.flattenToShortString() : null;
1920
1921 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1922 // If we are in the background, then check to see if this process
1923 // is bad. If so, we will just silently fail.
1924 if (mBadProcesses.get(info.processName, info.uid) != null) {
1925 return null;
1926 }
1927 } else {
1928 // When the user is explicitly starting a process, then clear its
1929 // crash count so that we won't make it bad until they see at
1930 // least one crash dialog again, and make the process good again
1931 // if it had been bad.
1932 mProcessCrashTimes.remove(info.processName, info.uid);
1933 if (mBadProcesses.get(info.processName, info.uid) != null) {
1934 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1935 info.processName);
1936 mBadProcesses.remove(info.processName, info.uid);
1937 if (app != null) {
1938 app.bad = false;
1939 }
1940 }
1941 }
1942
1943 if (app == null) {
1944 app = newProcessRecordLocked(null, info, processName);
1945 mProcessNames.put(processName, info.uid, app);
1946 } else {
1947 // If this is a new package in the process, add the package to the list
1948 app.addPackage(info.packageName);
1949 }
1950
1951 // If the system is not ready yet, then hold off on starting this
1952 // process until it is.
1953 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001954 && !isAllowedWhileBooting(info)
1955 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 if (!mProcessesOnHold.contains(app)) {
1957 mProcessesOnHold.add(app);
1958 }
1959 return app;
1960 }
1961
1962 startProcessLocked(app, hostingType, hostingNameStr);
1963 return (app.pid != 0) ? app : null;
1964 }
1965
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001966 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1967 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1968 }
1969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 private final void startProcessLocked(ProcessRecord app,
1971 String hostingType, String hostingNameStr) {
1972 if (app.pid > 0 && app.pid != MY_PID) {
1973 synchronized (mPidsSelfLocked) {
1974 mPidsSelfLocked.remove(app.pid);
1975 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1976 }
1977 app.pid = 0;
1978 }
1979
1980 mProcessesOnHold.remove(app);
1981
1982 updateCpuStats();
1983
1984 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1985 mProcDeaths[0] = 0;
1986
1987 try {
1988 int uid = app.info.uid;
1989 int[] gids = null;
1990 try {
1991 gids = mContext.getPackageManager().getPackageGids(
1992 app.info.packageName);
1993 } catch (PackageManager.NameNotFoundException e) {
1994 Log.w(TAG, "Unable to retrieve gids", e);
1995 }
1996 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1997 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1998 && mTopComponent != null
1999 && app.processName.equals(mTopComponent.getPackageName())) {
2000 uid = 0;
2001 }
2002 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
2003 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
2004 uid = 0;
2005 }
2006 }
2007 int debugFlags = 0;
2008 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
2009 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
2010 }
2011 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
2012 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
2013 }
2014 if ("1".equals(SystemProperties.get("debug.assert"))) {
2015 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2016 }
2017 int pid = Process.start("android.app.ActivityThread",
2018 mSimpleProcessManagement ? app.processName : null, uid, uid,
2019 gids, debugFlags, null);
2020 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2021 synchronized (bs) {
2022 if (bs.isOnBattery()) {
2023 app.batteryStats.incStartsLocked();
2024 }
2025 }
2026
2027 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2028 app.processName, hostingType,
2029 hostingNameStr != null ? hostingNameStr : "");
2030
2031 if (app.persistent) {
2032 Watchdog.getInstance().processStarted(app, app.processName, pid);
2033 }
2034
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002035 StringBuilder buf = mStringBuilder;
2036 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 buf.append("Start proc ");
2038 buf.append(app.processName);
2039 buf.append(" for ");
2040 buf.append(hostingType);
2041 if (hostingNameStr != null) {
2042 buf.append(" ");
2043 buf.append(hostingNameStr);
2044 }
2045 buf.append(": pid=");
2046 buf.append(pid);
2047 buf.append(" uid=");
2048 buf.append(uid);
2049 buf.append(" gids={");
2050 if (gids != null) {
2051 for (int gi=0; gi<gids.length; gi++) {
2052 if (gi != 0) buf.append(", ");
2053 buf.append(gids[gi]);
2054
2055 }
2056 }
2057 buf.append("}");
2058 Log.i(TAG, buf.toString());
2059 if (pid == 0 || pid == MY_PID) {
2060 // Processes are being emulated with threads.
2061 app.pid = MY_PID;
2062 app.removed = false;
2063 mStartingProcesses.add(app);
2064 } else if (pid > 0) {
2065 app.pid = pid;
2066 app.removed = false;
2067 synchronized (mPidsSelfLocked) {
2068 this.mPidsSelfLocked.put(pid, app);
2069 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2070 msg.obj = app;
2071 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2072 }
2073 } else {
2074 app.pid = 0;
2075 RuntimeException e = new RuntimeException(
2076 "Failure starting process " + app.processName
2077 + ": returned pid=" + pid);
2078 Log.e(TAG, e.getMessage(), e);
2079 }
2080 } catch (RuntimeException e) {
2081 // XXX do better error recovery.
2082 app.pid = 0;
2083 Log.e(TAG, "Failure starting process " + app.processName, e);
2084 }
2085 }
2086
2087 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2088 if (mPausingActivity != null) {
2089 RuntimeException e = new RuntimeException();
2090 Log.e(TAG, "Trying to pause when pause is already pending for "
2091 + mPausingActivity, e);
2092 }
2093 HistoryRecord prev = mResumedActivity;
2094 if (prev == null) {
2095 RuntimeException e = new RuntimeException();
2096 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2097 resumeTopActivityLocked(null);
2098 return;
2099 }
2100 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2101 mResumedActivity = null;
2102 mPausingActivity = prev;
2103 mLastPausedActivity = prev;
2104 prev.state = ActivityState.PAUSING;
2105 prev.task.touchActiveTime();
2106
2107 updateCpuStats();
2108
2109 if (prev.app != null && prev.app.thread != null) {
2110 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2111 try {
2112 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2113 System.identityHashCode(prev),
2114 prev.shortComponentName);
2115 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2116 prev.configChangeFlags);
2117 updateUsageStats(prev, false);
2118 } catch (Exception e) {
2119 // Ignore exception, if process died other code will cleanup.
2120 Log.w(TAG, "Exception thrown during pause", e);
2121 mPausingActivity = null;
2122 mLastPausedActivity = null;
2123 }
2124 } else {
2125 mPausingActivity = null;
2126 mLastPausedActivity = null;
2127 }
2128
2129 // If we are not going to sleep, we want to ensure the device is
2130 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002131 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 mLaunchingActivity.acquire();
2133 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2134 // To be safe, don't allow the wake lock to be held for too long.
2135 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2136 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2137 }
2138 }
2139
2140
2141 if (mPausingActivity != null) {
2142 // Have the window manager pause its key dispatching until the new
2143 // activity has started. If we're pausing the activity just because
2144 // the screen is being turned off and the UI is sleeping, don't interrupt
2145 // key dispatch; the same activity will pick it up again on wakeup.
2146 if (!uiSleeping) {
2147 prev.pauseKeyDispatchingLocked();
2148 } else {
2149 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2150 }
2151
2152 // Schedule a pause timeout in case the app doesn't respond.
2153 // We don't give it much time because this directly impacts the
2154 // responsiveness seen by the user.
2155 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2156 msg.obj = prev;
2157 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2158 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2159 } else {
2160 // This activity failed to schedule the
2161 // pause, so just treat it as being paused now.
2162 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2163 resumeTopActivityLocked(null);
2164 }
2165 }
2166
2167 private final void completePauseLocked() {
2168 HistoryRecord prev = mPausingActivity;
2169 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2170
2171 if (prev != null) {
2172 if (prev.finishing) {
2173 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2174 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2175 } else if (prev.app != null) {
2176 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2177 if (prev.waitingVisible) {
2178 prev.waitingVisible = false;
2179 mWaitingVisibleActivities.remove(prev);
2180 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2181 TAG, "Complete pause, no longer waiting: " + prev);
2182 }
2183 if (prev.configDestroy) {
2184 // The previous is being paused because the configuration
2185 // is changing, which means it is actually stopping...
2186 // To juggle the fact that we are also starting a new
2187 // instance right now, we need to first completely stop
2188 // the current instance before starting the new one.
2189 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2190 destroyActivityLocked(prev, true);
2191 } else {
2192 mStoppingActivities.add(prev);
2193 if (mStoppingActivities.size() > 3) {
2194 // If we already have a few activities waiting to stop,
2195 // then give up on things going idle and start clearing
2196 // them out.
2197 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2198 Message msg = Message.obtain();
2199 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2200 mHandler.sendMessage(msg);
2201 }
2202 }
2203 } else {
2204 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2205 prev = null;
2206 }
2207 mPausingActivity = null;
2208 }
2209
Dianne Hackborn55280a92009-05-07 15:53:46 -07002210 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 resumeTopActivityLocked(prev);
2212 } else {
2213 if (mGoingToSleep.isHeld()) {
2214 mGoingToSleep.release();
2215 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002216 if (mShuttingDown) {
2217 notifyAll();
2218 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 }
2220
2221 if (prev != null) {
2222 prev.resumeKeyDispatchingLocked();
2223 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002224
2225 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2226 long diff = 0;
2227 synchronized (mProcessStatsThread) {
2228 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2229 }
2230 if (diff > 0) {
2231 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2232 synchronized (bsi) {
2233 BatteryStatsImpl.Uid.Proc ps =
2234 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2235 prev.info.packageName);
2236 if (ps != null) {
2237 ps.addForegroundTimeLocked(diff);
2238 }
2239 }
2240 }
2241 }
2242 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002243 }
2244
2245 /**
2246 * Once we know that we have asked an application to put an activity in
2247 * the resumed state (either by launching it or explicitly telling it),
2248 * this function updates the rest of our state to match that fact.
2249 */
2250 private final void completeResumeLocked(HistoryRecord next) {
2251 next.idle = false;
2252 next.results = null;
2253 next.newIntents = null;
2254
2255 // schedule an idle timeout in case the app doesn't do it for us.
2256 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2257 msg.obj = next;
2258 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2259
2260 if (false) {
2261 // The activity was never told to pause, so just keep
2262 // things going as-is. To maintain our own state,
2263 // we need to emulate it coming back and saying it is
2264 // idle.
2265 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2266 msg.obj = next;
2267 mHandler.sendMessage(msg);
2268 }
2269
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002270 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002272 next.thumbnail = null;
2273 setFocusedActivityLocked(next);
2274 next.resumeKeyDispatchingLocked();
2275 ensureActivitiesVisibleLocked(null, 0);
2276 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002277 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002278
2279 // Mark the point when the activity is resuming
2280 // TODO: To be more accurate, the mark should be before the onCreate,
2281 // not after the onResume. But for subsequent starts, onResume is fine.
2282 if (next.app != null) {
2283 synchronized (mProcessStatsThread) {
2284 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2285 }
2286 } else {
2287 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2288 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002289 }
2290
2291 /**
2292 * Make sure that all activities that need to be visible (that is, they
2293 * currently can be seen by the user) actually are.
2294 */
2295 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2296 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2297 if (DEBUG_VISBILITY) Log.v(
2298 TAG, "ensureActivitiesVisible behind " + top
2299 + " configChanges=0x" + Integer.toHexString(configChanges));
2300
2301 // If the top activity is not fullscreen, then we need to
2302 // make sure any activities under it are now visible.
2303 final int count = mHistory.size();
2304 int i = count-1;
2305 while (mHistory.get(i) != top) {
2306 i--;
2307 }
2308 HistoryRecord r;
2309 boolean behindFullscreen = false;
2310 for (; i>=0; i--) {
2311 r = (HistoryRecord)mHistory.get(i);
2312 if (DEBUG_VISBILITY) Log.v(
2313 TAG, "Make visible? " + r + " finishing=" + r.finishing
2314 + " state=" + r.state);
2315 if (r.finishing) {
2316 continue;
2317 }
2318
2319 final boolean doThisProcess = onlyThisProcess == null
2320 || onlyThisProcess.equals(r.processName);
2321
2322 // First: if this is not the current activity being started, make
2323 // sure it matches the current configuration.
2324 if (r != starting && doThisProcess) {
2325 ensureActivityConfigurationLocked(r, 0);
2326 }
2327
2328 if (r.app == null || r.app.thread == null) {
2329 if (onlyThisProcess == null
2330 || onlyThisProcess.equals(r.processName)) {
2331 // This activity needs to be visible, but isn't even
2332 // running... get it started, but don't resume it
2333 // at this point.
2334 if (DEBUG_VISBILITY) Log.v(
2335 TAG, "Start and freeze screen for " + r);
2336 if (r != starting) {
2337 r.startFreezingScreenLocked(r.app, configChanges);
2338 }
2339 if (!r.visible) {
2340 if (DEBUG_VISBILITY) Log.v(
2341 TAG, "Starting and making visible: " + r);
2342 mWindowManager.setAppVisibility(r, true);
2343 }
2344 if (r != starting) {
2345 startSpecificActivityLocked(r, false, false);
2346 }
2347 }
2348
2349 } else if (r.visible) {
2350 // If this activity is already visible, then there is nothing
2351 // else to do here.
2352 if (DEBUG_VISBILITY) Log.v(
2353 TAG, "Skipping: already visible at " + r);
2354 r.stopFreezingScreenLocked(false);
2355
2356 } else if (onlyThisProcess == null) {
2357 // This activity is not currently visible, but is running.
2358 // Tell it to become visible.
2359 r.visible = true;
2360 if (r.state != ActivityState.RESUMED && r != starting) {
2361 // If this activity is paused, tell it
2362 // to now show its window.
2363 if (DEBUG_VISBILITY) Log.v(
2364 TAG, "Making visible and scheduling visibility: " + r);
2365 try {
2366 mWindowManager.setAppVisibility(r, true);
2367 r.app.thread.scheduleWindowVisibility(r, true);
2368 r.stopFreezingScreenLocked(false);
2369 } catch (Exception e) {
2370 // Just skip on any failure; we'll make it
2371 // visible when it next restarts.
2372 Log.w(TAG, "Exception thrown making visibile: "
2373 + r.intent.getComponent(), e);
2374 }
2375 }
2376 }
2377
2378 // Aggregate current change flags.
2379 configChanges |= r.configChangeFlags;
2380
2381 if (r.fullscreen) {
2382 // At this point, nothing else needs to be shown
2383 if (DEBUG_VISBILITY) Log.v(
2384 TAG, "Stopping: fullscreen at " + r);
2385 behindFullscreen = true;
2386 i--;
2387 break;
2388 }
2389 }
2390
2391 // Now for any activities that aren't visible to the user, make
2392 // sure they no longer are keeping the screen frozen.
2393 while (i >= 0) {
2394 r = (HistoryRecord)mHistory.get(i);
2395 if (DEBUG_VISBILITY) Log.v(
2396 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2397 + " state=" + r.state
2398 + " behindFullscreen=" + behindFullscreen);
2399 if (!r.finishing) {
2400 if (behindFullscreen) {
2401 if (r.visible) {
2402 if (DEBUG_VISBILITY) Log.v(
2403 TAG, "Making invisible: " + r);
2404 r.visible = false;
2405 try {
2406 mWindowManager.setAppVisibility(r, false);
2407 if ((r.state == ActivityState.STOPPING
2408 || r.state == ActivityState.STOPPED)
2409 && r.app != null && r.app.thread != null) {
2410 if (DEBUG_VISBILITY) Log.v(
2411 TAG, "Scheduling invisibility: " + r);
2412 r.app.thread.scheduleWindowVisibility(r, false);
2413 }
2414 } catch (Exception e) {
2415 // Just skip on any failure; we'll make it
2416 // visible when it next restarts.
2417 Log.w(TAG, "Exception thrown making hidden: "
2418 + r.intent.getComponent(), e);
2419 }
2420 } else {
2421 if (DEBUG_VISBILITY) Log.v(
2422 TAG, "Already invisible: " + r);
2423 }
2424 } else if (r.fullscreen) {
2425 if (DEBUG_VISBILITY) Log.v(
2426 TAG, "Now behindFullscreen: " + r);
2427 behindFullscreen = true;
2428 }
2429 }
2430 i--;
2431 }
2432 }
2433
2434 /**
2435 * Version of ensureActivitiesVisible that can easily be called anywhere.
2436 */
2437 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2438 int configChanges) {
2439 HistoryRecord r = topRunningActivityLocked(null);
2440 if (r != null) {
2441 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2442 }
2443 }
2444
2445 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2446 if (resumed) {
2447 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2448 } else {
2449 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2450 }
2451 }
2452
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002453 private boolean startHomeActivityLocked() {
2454 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2455 && mTopAction == null) {
2456 // We are running in factory test mode, but unable to find
2457 // the factory test app, so just sit around displaying the
2458 // error message and don't try to start anything.
2459 return false;
2460 }
2461 Intent intent = new Intent(
2462 mTopAction,
2463 mTopData != null ? Uri.parse(mTopData) : null);
2464 intent.setComponent(mTopComponent);
2465 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2466 intent.addCategory(Intent.CATEGORY_HOME);
2467 }
2468 ActivityInfo aInfo =
2469 intent.resolveActivityInfo(mContext.getPackageManager(),
2470 STOCK_PM_FLAGS);
2471 if (aInfo != null) {
2472 intent.setComponent(new ComponentName(
2473 aInfo.applicationInfo.packageName, aInfo.name));
2474 // Don't do this if the home app is currently being
2475 // instrumented.
2476 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2477 aInfo.applicationInfo.uid);
2478 if (app == null || app.instrumentationClass == null) {
2479 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2480 startActivityLocked(null, intent, null, null, 0, aInfo,
2481 null, null, 0, 0, 0, false, false);
2482 }
2483 }
2484
2485
2486 return true;
2487 }
2488
2489 /**
2490 * Starts the "new version setup screen" if appropriate.
2491 */
2492 private void startSetupActivityLocked() {
2493 // Only do this once per boot.
2494 if (mCheckedForSetup) {
2495 return;
2496 }
2497
2498 // We will show this screen if the current one is a different
2499 // version than the last one shown, and we are not running in
2500 // low-level factory test mode.
2501 final ContentResolver resolver = mContext.getContentResolver();
2502 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2503 Settings.Secure.getInt(resolver,
2504 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2505 mCheckedForSetup = true;
2506
2507 // See if we should be showing the platform update setup UI.
2508 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2509 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2510 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2511
2512 // We don't allow third party apps to replace this.
2513 ResolveInfo ri = null;
2514 for (int i=0; ris != null && i<ris.size(); i++) {
2515 if ((ris.get(i).activityInfo.applicationInfo.flags
2516 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2517 ri = ris.get(i);
2518 break;
2519 }
2520 }
2521
2522 if (ri != null) {
2523 String vers = ri.activityInfo.metaData != null
2524 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2525 : null;
2526 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2527 vers = ri.activityInfo.applicationInfo.metaData.getString(
2528 Intent.METADATA_SETUP_VERSION);
2529 }
2530 String lastVers = Settings.Secure.getString(
2531 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2532 if (vers != null && !vers.equals(lastVers)) {
2533 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2534 intent.setComponent(new ComponentName(
2535 ri.activityInfo.packageName, ri.activityInfo.name));
2536 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2537 null, null, 0, 0, 0, false, false);
2538 }
2539 }
2540 }
2541 }
2542
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002543 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002544 //Log.i(TAG, "**** REPORT RESUME: " + r);
2545
2546 final int identHash = System.identityHashCode(r);
2547 updateUsageStats(r, true);
2548
2549 int i = mWatchers.beginBroadcast();
2550 while (i > 0) {
2551 i--;
2552 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2553 if (w != null) {
2554 try {
2555 w.activityResuming(identHash);
2556 } catch (RemoteException e) {
2557 }
2558 }
2559 }
2560 mWatchers.finishBroadcast();
2561 }
2562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002563 /**
2564 * Ensure that the top activity in the stack is resumed.
2565 *
2566 * @param prev The previously resumed activity, for when in the process
2567 * of pausing; can be null to call from elsewhere.
2568 *
2569 * @return Returns true if something is being resumed, or false if
2570 * nothing happened.
2571 */
2572 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2573 // Find the first activity that is not finishing.
2574 HistoryRecord next = topRunningActivityLocked(null);
2575
2576 // Remember how we'll process this pause/resume situation, and ensure
2577 // that the state is reset however we wind up proceeding.
2578 final boolean userLeaving = mUserLeaving;
2579 mUserLeaving = false;
2580
2581 if (next == null) {
2582 // There are no more activities! Let's just start up the
2583 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002584 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002585 }
2586
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002587 next.delayedResume = false;
2588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589 // If the top activity is the resumed one, nothing to do.
2590 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2591 // Make sure we have executed any pending transitions, since there
2592 // should be nothing left to do at this point.
2593 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002594 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002595 return false;
2596 }
2597
2598 // If we are sleeping, and there is no resumed activity, and the top
2599 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002600 if ((mSleeping || mShuttingDown)
2601 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002602 // Make sure we have executed any pending transitions, since there
2603 // should be nothing left to do at this point.
2604 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002605 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002606 return false;
2607 }
2608
2609 // The activity may be waiting for stop, but that is no longer
2610 // appropriate for it.
2611 mStoppingActivities.remove(next);
2612 mWaitingVisibleActivities.remove(next);
2613
2614 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2615
2616 // If we are currently pausing an activity, then don't do anything
2617 // until that is done.
2618 if (mPausingActivity != null) {
2619 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2620 return false;
2621 }
2622
2623 // We need to start pausing the current activity so the top one
2624 // can be resumed...
2625 if (mResumedActivity != null) {
2626 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2627 startPausingLocked(userLeaving, false);
2628 return true;
2629 }
2630
2631 if (prev != null && prev != next) {
2632 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2633 prev.waitingVisible = true;
2634 mWaitingVisibleActivities.add(prev);
2635 if (DEBUG_SWITCH) Log.v(
2636 TAG, "Resuming top, waiting visible to hide: " + prev);
2637 } else {
2638 // The next activity is already visible, so hide the previous
2639 // activity's windows right now so we can show the new one ASAP.
2640 // We only do this if the previous is finishing, which should mean
2641 // it is on top of the one being resumed so hiding it quickly
2642 // is good. Otherwise, we want to do the normal route of allowing
2643 // the resumed activity to be shown so we can decide if the
2644 // previous should actually be hidden depending on whether the
2645 // new one is found to be full-screen or not.
2646 if (prev.finishing) {
2647 mWindowManager.setAppVisibility(prev, false);
2648 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2649 + prev + ", waitingVisible="
2650 + (prev != null ? prev.waitingVisible : null)
2651 + ", nowVisible=" + next.nowVisible);
2652 } else {
2653 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2654 + prev + ", waitingVisible="
2655 + (prev != null ? prev.waitingVisible : null)
2656 + ", nowVisible=" + next.nowVisible);
2657 }
2658 }
2659 }
2660
2661 // We are starting up the next activity, so tell the window manager
2662 // that the previous one will be hidden soon. This way it can know
2663 // to ignore it when computing the desired screen orientation.
2664 if (prev != null) {
2665 if (prev.finishing) {
2666 if (DEBUG_TRANSITION) Log.v(TAG,
2667 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002668 if (mNoAnimActivities.contains(prev)) {
2669 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2670 } else {
2671 mWindowManager.prepareAppTransition(prev.task == next.task
2672 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2673 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2674 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 mWindowManager.setAppWillBeHidden(prev);
2676 mWindowManager.setAppVisibility(prev, false);
2677 } else {
2678 if (DEBUG_TRANSITION) Log.v(TAG,
2679 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002680 if (mNoAnimActivities.contains(next)) {
2681 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2682 } else {
2683 mWindowManager.prepareAppTransition(prev.task == next.task
2684 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2685 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 }
2688 if (false) {
2689 mWindowManager.setAppWillBeHidden(prev);
2690 mWindowManager.setAppVisibility(prev, false);
2691 }
2692 } else if (mHistory.size() > 1) {
2693 if (DEBUG_TRANSITION) Log.v(TAG,
2694 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002695 if (mNoAnimActivities.contains(next)) {
2696 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2697 } else {
2698 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2699 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002700 }
2701
2702 if (next.app != null && next.app.thread != null) {
2703 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2704
2705 // This activity is now becoming visible.
2706 mWindowManager.setAppVisibility(next, true);
2707
2708 HistoryRecord lastResumedActivity = mResumedActivity;
2709 ActivityState lastState = next.state;
2710
2711 updateCpuStats();
2712
2713 next.state = ActivityState.RESUMED;
2714 mResumedActivity = next;
2715 next.task.touchActiveTime();
2716 updateLRUListLocked(next.app, true);
2717 updateLRUListLocked(next);
2718
2719 // Have the window manager re-evaluate the orientation of
2720 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002721 boolean updated;
2722 synchronized (this) {
2723 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2724 mConfiguration,
2725 next.mayFreezeScreenLocked(next.app) ? next : null);
2726 if (config != null) {
2727 /*
2728 * Explicitly restore the locale to the one from the
2729 * old configuration, since the one that comes back from
2730 * the window manager has the default (boot) locale.
2731 *
2732 * It looks like previously the locale picker only worked
2733 * by coincidence: usually it would do its setting of
2734 * the locale after the activity transition, so it didn't
2735 * matter that this lost it. With the synchronized
2736 * block now keeping them from happening at the same time,
2737 * this one always would happen second and undo what the
2738 * locale picker had just done.
2739 */
2740 config.locale = mConfiguration.locale;
2741 next.frozenBeforeDestroy = true;
2742 }
2743 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002745 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002746 // The configuration update wasn't able to keep the existing
2747 // instance of the activity, and instead started a new one.
2748 // We should be all done, but let's just make sure our activity
2749 // is still at the top and schedule another run if something
2750 // weird happened.
2751 HistoryRecord nextNext = topRunningActivityLocked(null);
2752 if (DEBUG_SWITCH) Log.i(TAG,
2753 "Activity config changed during resume: " + next
2754 + ", new next: " + nextNext);
2755 if (nextNext != next) {
2756 // Do over!
2757 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2758 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002759 setFocusedActivityLocked(next);
2760 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002761 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002762 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002763 return true;
2764 }
2765
2766 try {
2767 // Deliver all pending results.
2768 ArrayList a = next.results;
2769 if (a != null) {
2770 final int N = a.size();
2771 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002772 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002773 TAG, "Delivering results to " + next
2774 + ": " + a);
2775 next.app.thread.scheduleSendResult(next, a);
2776 }
2777 }
2778
2779 if (next.newIntents != null) {
2780 next.app.thread.scheduleNewIntent(next.newIntents, next);
2781 }
2782
2783 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2784 System.identityHashCode(next),
2785 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002786
2787 next.app.thread.scheduleResumeActivity(next,
2788 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002790 pauseIfSleepingLocked();
2791
2792 } catch (Exception e) {
2793 // Whoops, need to restart this activity!
2794 next.state = lastState;
2795 mResumedActivity = lastResumedActivity;
2796 if (Config.LOGD) Log.d(TAG,
2797 "Restarting because process died: " + next);
2798 if (!next.hasBeenLaunched) {
2799 next.hasBeenLaunched = true;
2800 } else {
2801 if (SHOW_APP_STARTING_ICON) {
2802 mWindowManager.setAppStartingWindow(
2803 next, next.packageName, next.theme,
2804 next.nonLocalizedLabel,
2805 next.labelRes, next.icon, null, true);
2806 }
2807 }
2808 startSpecificActivityLocked(next, true, false);
2809 return true;
2810 }
2811
2812 // From this point on, if something goes wrong there is no way
2813 // to recover the activity.
2814 try {
2815 next.visible = true;
2816 completeResumeLocked(next);
2817 } catch (Exception e) {
2818 // If any exception gets thrown, toss away this
2819 // activity and try the next one.
2820 Log.w(TAG, "Exception thrown during resume of " + next, e);
2821 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2822 "resume-exception");
2823 return true;
2824 }
2825
2826 // Didn't need to use the icicle, and it is now out of date.
2827 next.icicle = null;
2828 next.haveState = false;
2829 next.stopped = false;
2830
2831 } else {
2832 // Whoops, need to restart this activity!
2833 if (!next.hasBeenLaunched) {
2834 next.hasBeenLaunched = true;
2835 } else {
2836 if (SHOW_APP_STARTING_ICON) {
2837 mWindowManager.setAppStartingWindow(
2838 next, next.packageName, next.theme,
2839 next.nonLocalizedLabel,
2840 next.labelRes, next.icon, null, true);
2841 }
2842 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2843 }
2844 startSpecificActivityLocked(next, true, true);
2845 }
2846
2847 return true;
2848 }
2849
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002850 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2851 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002852 final int NH = mHistory.size();
2853
2854 int addPos = -1;
2855
2856 if (!newTask) {
2857 // If starting in an existing task, find where that is...
2858 HistoryRecord next = null;
2859 boolean startIt = true;
2860 for (int i = NH-1; i >= 0; i--) {
2861 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2862 if (p.finishing) {
2863 continue;
2864 }
2865 if (p.task == r.task) {
2866 // Here it is! Now, if this is not yet visible to the
2867 // user, then just add it without starting; it will
2868 // get started when the user navigates back to it.
2869 addPos = i+1;
2870 if (!startIt) {
2871 mHistory.add(addPos, r);
2872 r.inHistory = true;
2873 r.task.numActivities++;
2874 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2875 r.info.screenOrientation, r.fullscreen);
2876 if (VALIDATE_TOKENS) {
2877 mWindowManager.validateAppTokens(mHistory);
2878 }
2879 return;
2880 }
2881 break;
2882 }
2883 if (p.fullscreen) {
2884 startIt = false;
2885 }
2886 next = p;
2887 }
2888 }
2889
2890 // Place a new activity at top of stack, so it is next to interact
2891 // with the user.
2892 if (addPos < 0) {
2893 addPos = mHistory.size();
2894 }
2895
2896 // If we are not placing the new activity frontmost, we do not want
2897 // to deliver the onUserLeaving callback to the actual frontmost
2898 // activity
2899 if (addPos < NH) {
2900 mUserLeaving = false;
2901 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2902 }
2903
2904 // Slot the activity into the history stack and proceed
2905 mHistory.add(addPos, r);
2906 r.inHistory = true;
2907 r.frontOfTask = newTask;
2908 r.task.numActivities++;
2909 if (NH > 0) {
2910 // We want to show the starting preview window if we are
2911 // switching to a new task, or the next activity's process is
2912 // not currently running.
2913 boolean showStartingIcon = newTask;
2914 ProcessRecord proc = r.app;
2915 if (proc == null) {
2916 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2917 }
2918 if (proc == null || proc.thread == null) {
2919 showStartingIcon = true;
2920 }
2921 if (DEBUG_TRANSITION) Log.v(TAG,
2922 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002923 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2924 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2925 mNoAnimActivities.add(r);
2926 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2927 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2928 mNoAnimActivities.remove(r);
2929 } else {
2930 mWindowManager.prepareAppTransition(newTask
2931 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2932 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2933 mNoAnimActivities.remove(r);
2934 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 mWindowManager.addAppToken(
2936 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2937 boolean doShow = true;
2938 if (newTask) {
2939 // Even though this activity is starting fresh, we still need
2940 // to reset it to make sure we apply affinities to move any
2941 // existing activities from other tasks in to it.
2942 // If the caller has requested that the target task be
2943 // reset, then do so.
2944 if ((r.intent.getFlags()
2945 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2946 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002947 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 }
2949 }
2950 if (SHOW_APP_STARTING_ICON && doShow) {
2951 // Figure out if we are transitioning from another activity that is
2952 // "has the same starting icon" as the next one. This allows the
2953 // window manager to keep the previous window it had previously
2954 // created, if it still had one.
2955 HistoryRecord prev = mResumedActivity;
2956 if (prev != null) {
2957 // We don't want to reuse the previous starting preview if:
2958 // (1) The current activity is in a different task.
2959 if (prev.task != r.task) prev = null;
2960 // (2) The current activity is already displayed.
2961 else if (prev.nowVisible) prev = null;
2962 }
2963 mWindowManager.setAppStartingWindow(
2964 r, r.packageName, r.theme, r.nonLocalizedLabel,
2965 r.labelRes, r.icon, prev, showStartingIcon);
2966 }
2967 } else {
2968 // If this is the first activity, don't do any fancy animations,
2969 // because there is nothing for it to animate on top of.
2970 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2971 r.info.screenOrientation, r.fullscreen);
2972 }
2973 if (VALIDATE_TOKENS) {
2974 mWindowManager.validateAppTokens(mHistory);
2975 }
2976
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002977 if (doResume) {
2978 resumeTopActivityLocked(null);
2979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 }
2981
2982 /**
2983 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002984 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2985 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002986 * an instance of that activity in the stack and, if found, finish all
2987 * activities on top of it and return the instance.
2988 *
2989 * @param newR Description of the new activity being started.
2990 * @return Returns the old activity that should be continue to be used,
2991 * or null if none was found.
2992 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002993 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002994 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002995 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002996
2997 // First find the requested task.
2998 while (i > 0) {
2999 i--;
3000 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3001 if (r.task.taskId == taskId) {
3002 i++;
3003 break;
3004 }
3005 }
3006
3007 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003008 while (i > 0) {
3009 i--;
3010 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3011 if (r.finishing) {
3012 continue;
3013 }
3014 if (r.task.taskId != taskId) {
3015 return null;
3016 }
3017 if (r.realActivity.equals(newR.realActivity)) {
3018 // Here it is! Now finish everything in front...
3019 HistoryRecord ret = r;
3020 if (doClear) {
3021 while (i < (mHistory.size()-1)) {
3022 i++;
3023 r = (HistoryRecord)mHistory.get(i);
3024 if (r.finishing) {
3025 continue;
3026 }
3027 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
3028 null, "clear")) {
3029 i--;
3030 }
3031 }
3032 }
3033
3034 // Finally, if this is a normal launch mode (that is, not
3035 // expecting onNewIntent()), then we will finish the current
3036 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003037 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3038 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003039 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003040 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003041 if (index >= 0) {
3042 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3043 null, "clear");
3044 }
3045 return null;
3046 }
3047 }
3048
3049 return ret;
3050 }
3051 }
3052
3053 return null;
3054 }
3055
3056 /**
3057 * Find the activity in the history stack within the given task. Returns
3058 * the index within the history at which it's found, or < 0 if not found.
3059 */
3060 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3061 int i = mHistory.size();
3062 while (i > 0) {
3063 i--;
3064 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3065 if (candidate.task.taskId != task) {
3066 break;
3067 }
3068 if (candidate.realActivity.equals(r.realActivity)) {
3069 return i;
3070 }
3071 }
3072
3073 return -1;
3074 }
3075
3076 /**
3077 * Reorder the history stack so that the activity at the given index is
3078 * brought to the front.
3079 */
3080 private final HistoryRecord moveActivityToFrontLocked(int where) {
3081 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3082 int top = mHistory.size();
3083 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3084 mHistory.add(top, newTop);
3085 oldTop.frontOfTask = false;
3086 newTop.frontOfTask = true;
3087 return newTop;
3088 }
3089
3090 /**
3091 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3092 * method will be called at the proper time.
3093 */
3094 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3095 boolean sent = false;
3096 if (r.state == ActivityState.RESUMED
3097 && r.app != null && r.app.thread != null) {
3098 try {
3099 ArrayList<Intent> ar = new ArrayList<Intent>();
3100 ar.add(new Intent(intent));
3101 r.app.thread.scheduleNewIntent(ar, r);
3102 sent = true;
3103 } catch (Exception e) {
3104 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3105 }
3106 }
3107 if (!sent) {
3108 r.addNewIntentLocked(new Intent(intent));
3109 }
3110 }
3111
3112 private final void logStartActivity(int tag, HistoryRecord r,
3113 TaskRecord task) {
3114 EventLog.writeEvent(tag,
3115 System.identityHashCode(r), task.taskId,
3116 r.shortComponentName, r.intent.getAction(),
3117 r.intent.getType(), r.intent.getDataString(),
3118 r.intent.getFlags());
3119 }
3120
3121 private final int startActivityLocked(IApplicationThread caller,
3122 Intent intent, String resolvedType,
3123 Uri[] grantedUriPermissions,
3124 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3125 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003126 int callingPid, int callingUid, boolean onlyIfNeeded,
3127 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128 Log.i(TAG, "Starting activity: " + intent);
3129
3130 HistoryRecord sourceRecord = null;
3131 HistoryRecord resultRecord = null;
3132 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003133 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003134 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003135 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3136 if (index >= 0) {
3137 sourceRecord = (HistoryRecord)mHistory.get(index);
3138 if (requestCode >= 0 && !sourceRecord.finishing) {
3139 resultRecord = sourceRecord;
3140 }
3141 }
3142 }
3143
3144 int launchFlags = intent.getFlags();
3145
3146 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3147 && sourceRecord != null) {
3148 // Transfer the result target from the source activity to the new
3149 // one being started, including any failures.
3150 if (requestCode >= 0) {
3151 return START_FORWARD_AND_REQUEST_CONFLICT;
3152 }
3153 resultRecord = sourceRecord.resultTo;
3154 resultWho = sourceRecord.resultWho;
3155 requestCode = sourceRecord.requestCode;
3156 sourceRecord.resultTo = null;
3157 if (resultRecord != null) {
3158 resultRecord.removeResultsLocked(
3159 sourceRecord, resultWho, requestCode);
3160 }
3161 }
3162
3163 int err = START_SUCCESS;
3164
3165 if (intent.getComponent() == null) {
3166 // We couldn't find a class that can handle the given Intent.
3167 // That's the end of that!
3168 err = START_INTENT_NOT_RESOLVED;
3169 }
3170
3171 if (err == START_SUCCESS && aInfo == null) {
3172 // We couldn't find the specific class specified in the Intent.
3173 // Also the end of the line.
3174 err = START_CLASS_NOT_FOUND;
3175 }
3176
3177 ProcessRecord callerApp = null;
3178 if (err == START_SUCCESS && caller != null) {
3179 callerApp = getRecordForAppLocked(caller);
3180 if (callerApp != null) {
3181 callingPid = callerApp.pid;
3182 callingUid = callerApp.info.uid;
3183 } else {
3184 Log.w(TAG, "Unable to find app for caller " + caller
3185 + " (pid=" + callingPid + ") when starting: "
3186 + intent.toString());
3187 err = START_PERMISSION_DENIED;
3188 }
3189 }
3190
3191 if (err != START_SUCCESS) {
3192 if (resultRecord != null) {
3193 sendActivityResultLocked(-1,
3194 resultRecord, resultWho, requestCode,
3195 Activity.RESULT_CANCELED, null);
3196 }
3197 return err;
3198 }
3199
3200 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3201 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3202 if (perm != PackageManager.PERMISSION_GRANTED) {
3203 if (resultRecord != null) {
3204 sendActivityResultLocked(-1,
3205 resultRecord, resultWho, requestCode,
3206 Activity.RESULT_CANCELED, null);
3207 }
3208 String msg = "Permission Denial: starting " + intent.toString()
3209 + " from " + callerApp + " (pid=" + callingPid
3210 + ", uid=" + callingUid + ")"
3211 + " requires " + aInfo.permission;
3212 Log.w(TAG, msg);
3213 throw new SecurityException(msg);
3214 }
3215
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003216 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 boolean abort = false;
3218 try {
3219 // The Intent we give to the watcher has the extra data
3220 // stripped off, since it can contain private information.
3221 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003222 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 aInfo.applicationInfo.packageName);
3224 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003225 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003226 }
3227
3228 if (abort) {
3229 if (resultRecord != null) {
3230 sendActivityResultLocked(-1,
3231 resultRecord, resultWho, requestCode,
3232 Activity.RESULT_CANCELED, null);
3233 }
3234 // We pretend to the caller that it was really started, but
3235 // they will just get a cancel result.
3236 return START_SUCCESS;
3237 }
3238 }
3239
3240 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3241 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003242 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003244 if (mResumedActivity == null
3245 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3246 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3247 PendingActivityLaunch pal = new PendingActivityLaunch();
3248 pal.r = r;
3249 pal.sourceRecord = sourceRecord;
3250 pal.grantedUriPermissions = grantedUriPermissions;
3251 pal.grantedMode = grantedMode;
3252 pal.onlyIfNeeded = onlyIfNeeded;
3253 mPendingActivityLaunches.add(pal);
3254 return START_SWITCHES_CANCELED;
3255 }
3256 }
3257
3258 if (mDidAppSwitch) {
3259 // This is the second allowed switch since we stopped switches,
3260 // so now just generally allow switches. Use case: user presses
3261 // home (switches disabled, switch to home, mDidAppSwitch now true);
3262 // user taps a home icon (coming from home so allowed, we hit here
3263 // and now allow anyone to switch again).
3264 mAppSwitchesAllowedTime = 0;
3265 } else {
3266 mDidAppSwitch = true;
3267 }
3268
3269 doPendingActivityLaunchesLocked(false);
3270
3271 return startActivityUncheckedLocked(r, sourceRecord,
3272 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3273 }
3274
3275 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3276 final int N = mPendingActivityLaunches.size();
3277 if (N <= 0) {
3278 return;
3279 }
3280 for (int i=0; i<N; i++) {
3281 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3282 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3283 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3284 doResume && i == (N-1));
3285 }
3286 mPendingActivityLaunches.clear();
3287 }
3288
3289 private final int startActivityUncheckedLocked(HistoryRecord r,
3290 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3291 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3292 final Intent intent = r.intent;
3293 final int callingUid = r.launchedFromUid;
3294
3295 int launchFlags = intent.getFlags();
3296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 // We'll invoke onUserLeaving before onPause only if the launching
3298 // activity did not explicitly state that this is an automated launch.
3299 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3300 if (DEBUG_USER_LEAVING) Log.v(TAG,
3301 "startActivity() => mUserLeaving=" + mUserLeaving);
3302
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003303 // If the caller has asked not to resume at this point, we make note
3304 // of this in the record so that we can skip it when trying to find
3305 // the top running activity.
3306 if (!doResume) {
3307 r.delayedResume = true;
3308 }
3309
3310 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3311 != 0 ? r : null;
3312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003313 // If the onlyIfNeeded flag is set, then we can do this if the activity
3314 // being launched is the same as the one making the call... or, as
3315 // a special case, if we do not know the caller then we count the
3316 // current top activity as the caller.
3317 if (onlyIfNeeded) {
3318 HistoryRecord checkedCaller = sourceRecord;
3319 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003320 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321 }
3322 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3323 // Caller is not the same as launcher, so always needed.
3324 onlyIfNeeded = false;
3325 }
3326 }
3327
3328 if (grantedUriPermissions != null && callingUid > 0) {
3329 for (int i=0; i<grantedUriPermissions.length; i++) {
3330 grantUriPermissionLocked(callingUid, r.packageName,
3331 grantedUriPermissions[i], grantedMode, r);
3332 }
3333 }
3334
3335 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3336 intent, r);
3337
3338 if (sourceRecord == null) {
3339 // This activity is not being started from another... in this
3340 // case we -always- start a new task.
3341 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3342 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3343 + intent);
3344 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3345 }
3346 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3347 // The original activity who is starting us is running as a single
3348 // instance... this new activity it is starting must go on its
3349 // own task.
3350 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3351 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3352 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3353 // The activity being started is a single instance... it always
3354 // gets launched into its own task.
3355 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3356 }
3357
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003358 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 // For whatever reason this activity is being launched into a new
3360 // task... yet the caller has requested a result back. Well, that
3361 // is pretty messed up, so instead immediately send back a cancel
3362 // and let the new task continue launched as normal without a
3363 // dependency on its originator.
3364 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3365 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003366 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 Activity.RESULT_CANCELED, null);
3368 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 }
3370
3371 boolean addingToTask = false;
3372 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3373 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3374 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3375 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3376 // If bring to front is requested, and no result is requested, and
3377 // we can find a task that was started with this same
3378 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003379 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003380 // See if there is a task to bring to the front. If this is
3381 // a SINGLE_INSTANCE activity, there can be one and only one
3382 // instance of it in the history, and it is always in its own
3383 // unique task, so we do a special search.
3384 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3385 ? findTaskLocked(intent, r.info)
3386 : findActivityLocked(intent, r.info);
3387 if (taskTop != null) {
3388 if (taskTop.task.intent == null) {
3389 // This task was started because of movement of
3390 // the activity based on affinity... now that we
3391 // are actually launching it, we can assign the
3392 // base intent.
3393 taskTop.task.setIntent(intent, r.info);
3394 }
3395 // If the target task is not in the front, then we need
3396 // to bring it to the front... except... well, with
3397 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3398 // to have the same behavior as if a new instance was
3399 // being started, which means not bringing it to the front
3400 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003401 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003402 if (curTop.task != taskTop.task) {
3403 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3404 boolean callerAtFront = sourceRecord == null
3405 || curTop.task == sourceRecord.task;
3406 if (callerAtFront) {
3407 // We really do want to push this one into the
3408 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003409 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003410 }
3411 }
3412 // If the caller has requested that the target task be
3413 // reset, then do so.
3414 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3415 taskTop = resetTaskIfNeededLocked(taskTop, r);
3416 }
3417 if (onlyIfNeeded) {
3418 // We don't need to start a new activity, and
3419 // the client said not to do anything if that
3420 // is the case, so this is it! And for paranoia, make
3421 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003422 if (doResume) {
3423 resumeTopActivityLocked(null);
3424 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003425 return START_RETURN_INTENT_TO_CALLER;
3426 }
3427 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3428 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3429 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3430 // In this situation we want to remove all activities
3431 // from the task up to the one being started. In most
3432 // cases this means we are resetting the task to its
3433 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003434 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003435 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 if (top != null) {
3437 if (top.frontOfTask) {
3438 // Activity aliases may mean we use different
3439 // intents for the top activity, so make sure
3440 // the task now has the identity of the new
3441 // intent.
3442 top.task.setIntent(r.intent, r.info);
3443 }
3444 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3445 deliverNewIntentLocked(top, r.intent);
3446 } else {
3447 // A special case: we need to
3448 // start the activity because it is not currently
3449 // running, and the caller has asked to clear the
3450 // current task to have this activity at the top.
3451 addingToTask = true;
3452 // Now pretend like this activity is being started
3453 // by the top of its task, so it is put in the
3454 // right place.
3455 sourceRecord = taskTop;
3456 }
3457 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3458 // In this case the top activity on the task is the
3459 // same as the one being launched, so we take that
3460 // as a request to bring the task to the foreground.
3461 // If the top activity in the task is the root
3462 // activity, deliver this new intent to it if it
3463 // desires.
3464 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3465 && taskTop.realActivity.equals(r.realActivity)) {
3466 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3467 if (taskTop.frontOfTask) {
3468 taskTop.task.setIntent(r.intent, r.info);
3469 }
3470 deliverNewIntentLocked(taskTop, r.intent);
3471 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3472 // In this case we are launching the root activity
3473 // of the task, but with a different intent. We
3474 // should start a new instance on top.
3475 addingToTask = true;
3476 sourceRecord = taskTop;
3477 }
3478 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3479 // In this case an activity is being launched in to an
3480 // existing task, without resetting that task. This
3481 // is typically the situation of launching an activity
3482 // from a notification or shortcut. We want to place
3483 // the new activity on top of the current task.
3484 addingToTask = true;
3485 sourceRecord = taskTop;
3486 } else if (!taskTop.task.rootWasReset) {
3487 // In this case we are launching in to an existing task
3488 // that has not yet been started from its front door.
3489 // The current task has been brought to the front.
3490 // Ideally, we'd probably like to place this new task
3491 // at the bottom of its stack, but that's a little hard
3492 // to do with the current organization of the code so
3493 // for now we'll just drop it.
3494 taskTop.task.setIntent(r.intent, r.info);
3495 }
3496 if (!addingToTask) {
3497 // We didn't do anything... but it was needed (a.k.a., client
3498 // don't use that intent!) And for paranoia, make
3499 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003500 if (doResume) {
3501 resumeTopActivityLocked(null);
3502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003503 return START_TASK_TO_FRONT;
3504 }
3505 }
3506 }
3507 }
3508
3509 //String uri = r.intent.toURI();
3510 //Intent intent2 = new Intent(uri);
3511 //Log.i(TAG, "Given intent: " + r.intent);
3512 //Log.i(TAG, "URI is: " + uri);
3513 //Log.i(TAG, "To intent: " + intent2);
3514
3515 if (r.packageName != null) {
3516 // If the activity being launched is the same as the one currently
3517 // at the top, then we need to check if it should only be launched
3518 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003519 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3520 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 if (top.realActivity.equals(r.realActivity)) {
3522 if (top.app != null && top.app.thread != null) {
3523 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3524 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3525 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3526 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3527 // For paranoia, make sure we have correctly
3528 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003529 if (doResume) {
3530 resumeTopActivityLocked(null);
3531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 if (onlyIfNeeded) {
3533 // We don't need to start a new activity, and
3534 // the client said not to do anything if that
3535 // is the case, so this is it!
3536 return START_RETURN_INTENT_TO_CALLER;
3537 }
3538 deliverNewIntentLocked(top, r.intent);
3539 return START_DELIVERED_TO_TOP;
3540 }
3541 }
3542 }
3543 }
3544
3545 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003546 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003547 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003548 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 Activity.RESULT_CANCELED, null);
3550 }
3551 return START_CLASS_NOT_FOUND;
3552 }
3553
3554 boolean newTask = false;
3555
3556 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003557 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003558 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3559 // todo: should do better management of integers.
3560 mCurTask++;
3561 if (mCurTask <= 0) {
3562 mCurTask = 1;
3563 }
3564 r.task = new TaskRecord(mCurTask, r.info, intent,
3565 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3566 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3567 + " in new task " + r.task);
3568 newTask = true;
Josh Bartel7f208742010-02-25 11:01:44 -06003569 addRecentTaskLocked(r.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003570
3571 } else if (sourceRecord != null) {
3572 if (!addingToTask &&
3573 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3574 // In this case, we are adding the activity to an existing
3575 // task, but the caller has asked to clear that task if the
3576 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003577 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003578 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003579 if (top != null) {
3580 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3581 deliverNewIntentLocked(top, r.intent);
3582 // For paranoia, make sure we have correctly
3583 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003584 if (doResume) {
3585 resumeTopActivityLocked(null);
3586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003587 return START_DELIVERED_TO_TOP;
3588 }
3589 } else if (!addingToTask &&
3590 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3591 // In this case, we are launching an activity in our own task
3592 // that may already be running somewhere in the history, and
3593 // we want to shuffle it to the front of the stack if so.
3594 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3595 if (where >= 0) {
3596 HistoryRecord top = moveActivityToFrontLocked(where);
3597 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3598 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003599 if (doResume) {
3600 resumeTopActivityLocked(null);
3601 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003602 return START_DELIVERED_TO_TOP;
3603 }
3604 }
3605 // An existing activity is starting this new activity, so we want
3606 // to keep the new one in the same task as the one that is starting
3607 // it.
3608 r.task = sourceRecord.task;
3609 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3610 + " in existing task " + r.task);
3611
3612 } else {
3613 // This not being started from an existing activity, and not part
3614 // of a new task... just put it in the top task, though these days
3615 // this case should never happen.
3616 final int N = mHistory.size();
3617 HistoryRecord prev =
3618 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3619 r.task = prev != null
3620 ? prev.task
3621 : new TaskRecord(mCurTask, r.info, intent,
3622 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3623 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3624 + " in new guessed " + r.task);
3625 }
3626 if (newTask) {
3627 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3628 }
3629 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003630 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003631 return START_SUCCESS;
3632 }
3633
3634 public final int startActivity(IApplicationThread caller,
3635 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3636 int grantedMode, IBinder resultTo,
3637 String resultWho, int requestCode, boolean onlyIfNeeded,
3638 boolean debug) {
3639 // Refuse possible leaked file descriptors
3640 if (intent != null && intent.hasFileDescriptors()) {
3641 throw new IllegalArgumentException("File descriptors passed in Intent");
3642 }
3643
The Android Open Source Project4df24232009-03-05 14:34:35 -08003644 final boolean componentSpecified = intent.getComponent() != null;
3645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003646 // Don't modify the client's object!
3647 intent = new Intent(intent);
3648
3649 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 ActivityInfo aInfo;
3651 try {
3652 ResolveInfo rInfo =
3653 ActivityThread.getPackageManager().resolveIntent(
3654 intent, resolvedType,
3655 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003656 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003657 aInfo = rInfo != null ? rInfo.activityInfo : null;
3658 } catch (RemoteException e) {
3659 aInfo = null;
3660 }
3661
3662 if (aInfo != null) {
3663 // Store the found target back into the intent, because now that
3664 // we have it we never want to do this again. For example, if the
3665 // user navigates back to this point in the history, we should
3666 // always restart the exact same activity.
3667 intent.setComponent(new ComponentName(
3668 aInfo.applicationInfo.packageName, aInfo.name));
3669
3670 // Don't debug things in the system process
3671 if (debug) {
3672 if (!aInfo.processName.equals("system")) {
3673 setDebugApp(aInfo.processName, true, false);
3674 }
3675 }
3676 }
3677
3678 synchronized(this) {
3679 final long origId = Binder.clearCallingIdentity();
3680 int res = startActivityLocked(caller, intent, resolvedType,
3681 grantedUriPermissions, grantedMode, aInfo,
3682 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003683 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003684 Binder.restoreCallingIdentity(origId);
3685 return res;
3686 }
3687 }
3688
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003689 public int startActivityIntentSender(IApplicationThread caller,
3690 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003691 IBinder resultTo, String resultWho, int requestCode,
3692 int flagsMask, int flagsValues) {
3693 // Refuse possible leaked file descriptors
3694 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3695 throw new IllegalArgumentException("File descriptors passed in Intent");
3696 }
3697
3698 IIntentSender sender = intent.getTarget();
3699 if (!(sender instanceof PendingIntentRecord)) {
3700 throw new IllegalArgumentException("Bad PendingIntent object");
3701 }
3702
3703 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003704
3705 synchronized (this) {
3706 // If this is coming from the currently resumed activity, it is
3707 // effectively saying that app switches are allowed at this point.
3708 if (mResumedActivity != null
3709 && mResumedActivity.info.applicationInfo.uid ==
3710 Binder.getCallingUid()) {
3711 mAppSwitchesAllowedTime = 0;
3712 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003713 }
3714
3715 return pir.sendInner(0, fillInIntent, resolvedType,
3716 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3717 }
3718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003719 public boolean startNextMatchingActivity(IBinder callingActivity,
3720 Intent intent) {
3721 // Refuse possible leaked file descriptors
3722 if (intent != null && intent.hasFileDescriptors() == true) {
3723 throw new IllegalArgumentException("File descriptors passed in Intent");
3724 }
3725
3726 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003727 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003728 if (index < 0) {
3729 return false;
3730 }
3731 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3732 if (r.app == null || r.app.thread == null) {
3733 // The caller is not running... d'oh!
3734 return false;
3735 }
3736 intent = new Intent(intent);
3737 // The caller is not allowed to change the data.
3738 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3739 // And we are resetting to find the next component...
3740 intent.setComponent(null);
3741
3742 ActivityInfo aInfo = null;
3743 try {
3744 List<ResolveInfo> resolves =
3745 ActivityThread.getPackageManager().queryIntentActivities(
3746 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003747 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003748
3749 // Look for the original activity in the list...
3750 final int N = resolves != null ? resolves.size() : 0;
3751 for (int i=0; i<N; i++) {
3752 ResolveInfo rInfo = resolves.get(i);
3753 if (rInfo.activityInfo.packageName.equals(r.packageName)
3754 && rInfo.activityInfo.name.equals(r.info.name)) {
3755 // We found the current one... the next matching is
3756 // after it.
3757 i++;
3758 if (i<N) {
3759 aInfo = resolves.get(i).activityInfo;
3760 }
3761 break;
3762 }
3763 }
3764 } catch (RemoteException e) {
3765 }
3766
3767 if (aInfo == null) {
3768 // Nobody who is next!
3769 return false;
3770 }
3771
3772 intent.setComponent(new ComponentName(
3773 aInfo.applicationInfo.packageName, aInfo.name));
3774 intent.setFlags(intent.getFlags()&~(
3775 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3776 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3777 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3778 Intent.FLAG_ACTIVITY_NEW_TASK));
3779
3780 // Okay now we need to start the new activity, replacing the
3781 // currently running activity. This is a little tricky because
3782 // we want to start the new one as if the current one is finished,
3783 // but not finish the current one first so that there is no flicker.
3784 // And thus...
3785 final boolean wasFinishing = r.finishing;
3786 r.finishing = true;
3787
3788 // Propagate reply information over to the new activity.
3789 final HistoryRecord resultTo = r.resultTo;
3790 final String resultWho = r.resultWho;
3791 final int requestCode = r.requestCode;
3792 r.resultTo = null;
3793 if (resultTo != null) {
3794 resultTo.removeResultsLocked(r, resultWho, requestCode);
3795 }
3796
3797 final long origId = Binder.clearCallingIdentity();
3798 // XXX we are not dealing with propagating grantedUriPermissions...
3799 // those are not yet exposed to user code, so there is no need.
3800 int res = startActivityLocked(r.app.thread, intent,
3801 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003802 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 Binder.restoreCallingIdentity(origId);
3804
3805 r.finishing = wasFinishing;
3806 if (res != START_SUCCESS) {
3807 return false;
3808 }
3809 return true;
3810 }
3811 }
3812
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003813 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003814 Intent intent, String resolvedType, IBinder resultTo,
3815 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003816
3817 // This is so super not safe, that only the system (or okay root)
3818 // can do it.
3819 final int callingUid = Binder.getCallingUid();
3820 if (callingUid != 0 && callingUid != Process.myUid()) {
3821 throw new SecurityException(
3822 "startActivityInPackage only available to the system");
3823 }
3824
The Android Open Source Project4df24232009-03-05 14:34:35 -08003825 final boolean componentSpecified = intent.getComponent() != null;
3826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 // Don't modify the client's object!
3828 intent = new Intent(intent);
3829
3830 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003831 ActivityInfo aInfo;
3832 try {
3833 ResolveInfo rInfo =
3834 ActivityThread.getPackageManager().resolveIntent(
3835 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003836 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837 aInfo = rInfo != null ? rInfo.activityInfo : null;
3838 } catch (RemoteException e) {
3839 aInfo = null;
3840 }
3841
3842 if (aInfo != null) {
3843 // Store the found target back into the intent, because now that
3844 // we have it we never want to do this again. For example, if the
3845 // user navigates back to this point in the history, we should
3846 // always restart the exact same activity.
3847 intent.setComponent(new ComponentName(
3848 aInfo.applicationInfo.packageName, aInfo.name));
3849 }
3850
3851 synchronized(this) {
3852 return startActivityLocked(null, intent, resolvedType,
3853 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003854 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003855 }
3856 }
3857
Josh Bartel7f208742010-02-25 11:01:44 -06003858 private final void addRecentTaskLocked(TaskRecord task) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003859 // Remove any existing entries that are the same kind of task.
3860 int N = mRecentTasks.size();
3861 for (int i=0; i<N; i++) {
3862 TaskRecord tr = mRecentTasks.get(i);
3863 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3864 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3865 mRecentTasks.remove(i);
3866 i--;
3867 N--;
3868 if (task.intent == null) {
3869 // If the new recent task we are adding is not fully
3870 // specified, then replace it with the existing recent task.
3871 task = tr;
3872 }
3873 }
3874 }
3875 if (N >= MAX_RECENT_TASKS) {
3876 mRecentTasks.remove(N-1);
3877 }
3878 mRecentTasks.add(0, task);
3879 }
3880
3881 public void setRequestedOrientation(IBinder token,
3882 int requestedOrientation) {
3883 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003884 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885 if (index < 0) {
3886 return;
3887 }
3888 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3889 final long origId = Binder.clearCallingIdentity();
3890 mWindowManager.setAppOrientation(r, requestedOrientation);
3891 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003892 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003893 r.mayFreezeScreenLocked(r.app) ? r : null);
3894 if (config != null) {
3895 r.frozenBeforeDestroy = true;
3896 if (!updateConfigurationLocked(config, r)) {
3897 resumeTopActivityLocked(null);
3898 }
3899 }
3900 Binder.restoreCallingIdentity(origId);
3901 }
3902 }
3903
3904 public int getRequestedOrientation(IBinder token) {
3905 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003906 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003907 if (index < 0) {
3908 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3909 }
3910 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3911 return mWindowManager.getAppOrientation(r);
3912 }
3913 }
3914
3915 private final void stopActivityLocked(HistoryRecord r) {
3916 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3917 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3918 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3919 if (!r.finishing) {
3920 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3921 "no-history");
3922 }
3923 } else if (r.app != null && r.app.thread != null) {
3924 if (mFocusedActivity == r) {
3925 setFocusedActivityLocked(topRunningActivityLocked(null));
3926 }
3927 r.resumeKeyDispatchingLocked();
3928 try {
3929 r.stopped = false;
3930 r.state = ActivityState.STOPPING;
3931 if (DEBUG_VISBILITY) Log.v(
3932 TAG, "Stopping visible=" + r.visible + " for " + r);
3933 if (!r.visible) {
3934 mWindowManager.setAppVisibility(r, false);
3935 }
3936 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3937 } catch (Exception e) {
3938 // Maybe just ignore exceptions here... if the process
3939 // has crashed, our death notification will clean things
3940 // up.
3941 Log.w(TAG, "Exception thrown during pause", e);
3942 // Just in case, assume it to be stopped.
3943 r.stopped = true;
3944 r.state = ActivityState.STOPPED;
3945 if (r.configDestroy) {
3946 destroyActivityLocked(r, true);
3947 }
3948 }
3949 }
3950 }
3951
3952 /**
3953 * @return Returns true if the activity is being finished, false if for
3954 * some reason it is being left as-is.
3955 */
3956 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3957 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003958 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003959 TAG, "Finishing activity: token=" + token
3960 + ", result=" + resultCode + ", data=" + resultData);
3961
Dianne Hackborn75b03852009-06-12 15:43:26 -07003962 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003963 if (index < 0) {
3964 return false;
3965 }
3966 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3967
3968 // Is this the last activity left?
3969 boolean lastActivity = true;
3970 for (int i=mHistory.size()-1; i>=0; i--) {
3971 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3972 if (!p.finishing && p != r) {
3973 lastActivity = false;
3974 break;
3975 }
3976 }
3977
3978 // If this is the last activity, but it is the home activity, then
3979 // just don't finish it.
3980 if (lastActivity) {
3981 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3982 return false;
3983 }
3984 }
3985
3986 finishActivityLocked(r, index, resultCode, resultData, reason);
3987 return true;
3988 }
3989
3990 /**
3991 * @return Returns true if this activity has been removed from the history
3992 * list, or false if it is still in the list and will be removed later.
3993 */
3994 private final boolean finishActivityLocked(HistoryRecord r, int index,
3995 int resultCode, Intent resultData, String reason) {
3996 if (r.finishing) {
3997 Log.w(TAG, "Duplicate finish request for " + r);
3998 return false;
3999 }
4000
4001 r.finishing = true;
4002 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
4003 System.identityHashCode(r),
4004 r.task.taskId, r.shortComponentName, reason);
4005 r.task.numActivities--;
4006 if (r.frontOfTask && index < (mHistory.size()-1)) {
4007 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
4008 if (next.task == r.task) {
4009 next.frontOfTask = true;
4010 }
4011 }
4012
4013 r.pauseKeyDispatchingLocked();
4014 if (mFocusedActivity == r) {
4015 setFocusedActivityLocked(topRunningActivityLocked(null));
4016 }
4017
4018 // send the result
4019 HistoryRecord resultTo = r.resultTo;
4020 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07004021 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
4022 + " who=" + r.resultWho + " req=" + r.requestCode
4023 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004024 if (r.info.applicationInfo.uid > 0) {
4025 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
4026 r.packageName, resultData, r);
4027 }
4028 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
4029 resultData);
4030 r.resultTo = null;
4031 }
Chris Tate8a7dc172009-03-24 20:11:42 -07004032 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033
4034 // Make sure this HistoryRecord is not holding on to other resources,
4035 // because clients have remote IPC references to this object so we
4036 // can't assume that will go away and want to avoid circular IPC refs.
4037 r.results = null;
4038 r.pendingResults = null;
4039 r.newIntents = null;
4040 r.icicle = null;
4041
4042 if (mPendingThumbnails.size() > 0) {
4043 // There are clients waiting to receive thumbnails so, in case
4044 // this is an activity that someone is waiting for, add it
4045 // to the pending list so we can correctly update the clients.
4046 mCancelledThumbnails.add(r);
4047 }
4048
4049 if (mResumedActivity == r) {
4050 boolean endTask = index <= 0
4051 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4052 if (DEBUG_TRANSITION) Log.v(TAG,
4053 "Prepare close transition: finishing " + r);
4054 mWindowManager.prepareAppTransition(endTask
4055 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4056 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4057
4058 // Tell window manager to prepare for this one to be removed.
4059 mWindowManager.setAppVisibility(r, false);
4060
4061 if (mPausingActivity == null) {
4062 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4063 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4064 startPausingLocked(false, false);
4065 }
4066
4067 } else if (r.state != ActivityState.PAUSING) {
4068 // If the activity is PAUSING, we will complete the finish once
4069 // it is done pausing; else we can just directly finish it here.
4070 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4071 return finishCurrentActivityLocked(r, index,
4072 FINISH_AFTER_PAUSE) == null;
4073 } else {
4074 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4075 }
4076
4077 return false;
4078 }
4079
4080 private static final int FINISH_IMMEDIATELY = 0;
4081 private static final int FINISH_AFTER_PAUSE = 1;
4082 private static final int FINISH_AFTER_VISIBLE = 2;
4083
4084 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4085 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004086 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004087 if (index < 0) {
4088 return null;
4089 }
4090
4091 return finishCurrentActivityLocked(r, index, mode);
4092 }
4093
4094 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4095 int index, int mode) {
4096 // First things first: if this activity is currently visible,
4097 // and the resumed activity is not yet visible, then hold off on
4098 // finishing until the resumed one becomes visible.
4099 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4100 if (!mStoppingActivities.contains(r)) {
4101 mStoppingActivities.add(r);
4102 if (mStoppingActivities.size() > 3) {
4103 // If we already have a few activities waiting to stop,
4104 // then give up on things going idle and start clearing
4105 // them out.
4106 Message msg = Message.obtain();
4107 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4108 mHandler.sendMessage(msg);
4109 }
4110 }
4111 r.state = ActivityState.STOPPING;
4112 updateOomAdjLocked();
4113 return r;
4114 }
4115
4116 // make sure the record is cleaned out of other places.
4117 mStoppingActivities.remove(r);
4118 mWaitingVisibleActivities.remove(r);
4119 if (mResumedActivity == r) {
4120 mResumedActivity = null;
4121 }
4122 final ActivityState prevState = r.state;
4123 r.state = ActivityState.FINISHING;
4124
4125 if (mode == FINISH_IMMEDIATELY
4126 || prevState == ActivityState.STOPPED
4127 || prevState == ActivityState.INITIALIZING) {
4128 // If this activity is already stopped, we can just finish
4129 // it right now.
4130 return destroyActivityLocked(r, true) ? null : r;
4131 } else {
4132 // Need to go through the full pause cycle to get this
4133 // activity into the stopped state and then finish it.
4134 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4135 mFinishingActivities.add(r);
4136 resumeTopActivityLocked(null);
4137 }
4138 return r;
4139 }
4140
4141 /**
4142 * This is the internal entry point for handling Activity.finish().
4143 *
4144 * @param token The Binder token referencing the Activity we want to finish.
4145 * @param resultCode Result code, if any, from this Activity.
4146 * @param resultData Result data (Intent), if any, from this Activity.
4147 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004148 * @return Returns true if the activity successfully finished, or false if it is still running.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004149 */
4150 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4151 // Refuse possible leaked file descriptors
4152 if (resultData != null && resultData.hasFileDescriptors() == true) {
4153 throw new IllegalArgumentException("File descriptors passed in Intent");
4154 }
4155
4156 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004157 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004158 // Find the first activity that is not finishing.
4159 HistoryRecord next = topRunningActivityLocked(token, 0);
4160 if (next != null) {
4161 // ask watcher if this is allowed
4162 boolean resumeOK = true;
4163 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004164 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004165 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004166 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004167 }
4168
4169 if (!resumeOK) {
4170 return false;
4171 }
4172 }
4173 }
4174 final long origId = Binder.clearCallingIdentity();
4175 boolean res = requestFinishActivityLocked(token, resultCode,
4176 resultData, "app-request");
4177 Binder.restoreCallingIdentity(origId);
4178 return res;
4179 }
4180 }
4181
4182 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4183 String resultWho, int requestCode, int resultCode, Intent data) {
4184
4185 if (callingUid > 0) {
4186 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4187 data, r);
4188 }
4189
The Android Open Source Project10592532009-03-18 17:39:46 -07004190 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4191 + " : who=" + resultWho + " req=" + requestCode
4192 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004193 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4194 try {
4195 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4196 list.add(new ResultInfo(resultWho, requestCode,
4197 resultCode, data));
4198 r.app.thread.scheduleSendResult(r, list);
4199 return;
4200 } catch (Exception e) {
4201 Log.w(TAG, "Exception thrown sending result to " + r, e);
4202 }
4203 }
4204
4205 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4206 }
4207
4208 public final void finishSubActivity(IBinder token, String resultWho,
4209 int requestCode) {
4210 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004211 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004212 if (index < 0) {
4213 return;
4214 }
4215 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4216
4217 final long origId = Binder.clearCallingIdentity();
4218
4219 int i;
4220 for (i=mHistory.size()-1; i>=0; i--) {
4221 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4222 if (r.resultTo == self && r.requestCode == requestCode) {
4223 if ((r.resultWho == null && resultWho == null) ||
4224 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4225 finishActivityLocked(r, i,
4226 Activity.RESULT_CANCELED, null, "request-sub");
4227 }
4228 }
4229 }
4230
4231 Binder.restoreCallingIdentity(origId);
4232 }
4233 }
4234
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004235 public void overridePendingTransition(IBinder token, String packageName,
4236 int enterAnim, int exitAnim) {
4237 synchronized(this) {
4238 int index = indexOfTokenLocked(token);
4239 if (index < 0) {
4240 return;
4241 }
4242 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4243
4244 final long origId = Binder.clearCallingIdentity();
4245
4246 if (self.state == ActivityState.RESUMED
4247 || self.state == ActivityState.PAUSING) {
4248 mWindowManager.overridePendingAppTransition(packageName,
4249 enterAnim, exitAnim);
4250 }
4251
4252 Binder.restoreCallingIdentity(origId);
4253 }
4254 }
4255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004256 /**
4257 * Perform clean-up of service connections in an activity record.
4258 */
4259 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4260 // Throw away any services that have been bound by this activity.
4261 if (r.connections != null) {
4262 Iterator<ConnectionRecord> it = r.connections.iterator();
4263 while (it.hasNext()) {
4264 ConnectionRecord c = it.next();
4265 removeConnectionLocked(c, null, r);
4266 }
4267 r.connections = null;
4268 }
4269 }
4270
4271 /**
4272 * Perform the common clean-up of an activity record. This is called both
4273 * as part of destroyActivityLocked() (when destroying the client-side
4274 * representation) and cleaning things up as a result of its hosting
4275 * processing going away, in which case there is no remaining client-side
4276 * state to destroy so only the cleanup here is needed.
4277 */
4278 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4279 if (mResumedActivity == r) {
4280 mResumedActivity = null;
4281 }
4282 if (mFocusedActivity == r) {
4283 mFocusedActivity = null;
4284 }
4285
4286 r.configDestroy = false;
4287 r.frozenBeforeDestroy = false;
4288
4289 // Make sure this record is no longer in the pending finishes list.
4290 // This could happen, for example, if we are trimming activities
4291 // down to the max limit while they are still waiting to finish.
4292 mFinishingActivities.remove(r);
4293 mWaitingVisibleActivities.remove(r);
4294
4295 // Remove any pending results.
4296 if (r.finishing && r.pendingResults != null) {
4297 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4298 PendingIntentRecord rec = apr.get();
4299 if (rec != null) {
4300 cancelIntentSenderLocked(rec, false);
4301 }
4302 }
4303 r.pendingResults = null;
4304 }
4305
4306 if (cleanServices) {
4307 cleanUpActivityServicesLocked(r);
4308 }
4309
4310 if (mPendingThumbnails.size() > 0) {
4311 // There are clients waiting to receive thumbnails so, in case
4312 // this is an activity that someone is waiting for, add it
4313 // to the pending list so we can correctly update the clients.
4314 mCancelledThumbnails.add(r);
4315 }
4316
4317 // Get rid of any pending idle timeouts.
4318 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4319 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4320 }
4321
4322 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4323 if (r.state != ActivityState.DESTROYED) {
4324 mHistory.remove(r);
4325 r.inHistory = false;
4326 r.state = ActivityState.DESTROYED;
4327 mWindowManager.removeAppToken(r);
4328 if (VALIDATE_TOKENS) {
4329 mWindowManager.validateAppTokens(mHistory);
4330 }
4331 cleanUpActivityServicesLocked(r);
4332 removeActivityUriPermissionsLocked(r);
4333 }
4334 }
4335
4336 /**
4337 * Destroy the current CLIENT SIDE instance of an activity. This may be
4338 * called both when actually finishing an activity, or when performing
4339 * a configuration switch where we destroy the current client-side object
4340 * but then create a new client-side object for this same HistoryRecord.
4341 */
4342 private final boolean destroyActivityLocked(HistoryRecord r,
4343 boolean removeFromApp) {
4344 if (DEBUG_SWITCH) Log.v(
4345 TAG, "Removing activity: token=" + r
4346 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4347 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4348 System.identityHashCode(r),
4349 r.task.taskId, r.shortComponentName);
4350
4351 boolean removedFromHistory = false;
4352
4353 cleanUpActivityLocked(r, false);
4354
4355 if (r.app != null) {
4356 if (removeFromApp) {
4357 int idx = r.app.activities.indexOf(r);
4358 if (idx >= 0) {
4359 r.app.activities.remove(idx);
4360 }
4361 if (r.persistent) {
4362 decPersistentCountLocked(r.app);
4363 }
4364 }
4365
4366 boolean skipDestroy = false;
4367
4368 try {
4369 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4370 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4371 r.configChangeFlags);
4372 } catch (Exception e) {
4373 // We can just ignore exceptions here... if the process
4374 // has crashed, our death notification will clean things
4375 // up.
4376 //Log.w(TAG, "Exception thrown during finish", e);
4377 if (r.finishing) {
4378 removeActivityFromHistoryLocked(r);
4379 removedFromHistory = true;
4380 skipDestroy = true;
4381 }
4382 }
4383
4384 r.app = null;
4385 r.nowVisible = false;
4386
4387 if (r.finishing && !skipDestroy) {
4388 r.state = ActivityState.DESTROYING;
4389 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4390 msg.obj = r;
4391 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4392 } else {
4393 r.state = ActivityState.DESTROYED;
4394 }
4395 } else {
4396 // remove this record from the history.
4397 if (r.finishing) {
4398 removeActivityFromHistoryLocked(r);
4399 removedFromHistory = true;
4400 } else {
4401 r.state = ActivityState.DESTROYED;
4402 }
4403 }
4404
4405 r.configChangeFlags = 0;
4406
4407 if (!mLRUActivities.remove(r)) {
4408 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4409 }
4410
4411 return removedFromHistory;
4412 }
4413
4414 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4415 ProcessRecord app)
4416 {
4417 int i = list.size();
4418 if (localLOGV) Log.v(
4419 TAG, "Removing app " + app + " from list " + list
4420 + " with " + i + " entries");
4421 while (i > 0) {
4422 i--;
4423 HistoryRecord r = (HistoryRecord)list.get(i);
4424 if (localLOGV) Log.v(
4425 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4426 if (r.app == app) {
4427 if (localLOGV) Log.v(TAG, "Removing this entry!");
4428 list.remove(i);
4429 }
4430 }
4431 }
4432
4433 /**
4434 * Main function for removing an existing process from the activity manager
4435 * as a result of that process going away. Clears out all connections
4436 * to the process.
4437 */
4438 private final void handleAppDiedLocked(ProcessRecord app,
4439 boolean restarting) {
4440 cleanUpApplicationRecordLocked(app, restarting, -1);
4441 if (!restarting) {
4442 mLRUProcesses.remove(app);
4443 }
4444
4445 // Just in case...
4446 if (mPausingActivity != null && mPausingActivity.app == app) {
4447 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4448 mPausingActivity = null;
4449 }
4450 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4451 mLastPausedActivity = null;
4452 }
4453
4454 // Remove this application's activities from active lists.
4455 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4456 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4457 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4458 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4459
4460 boolean atTop = true;
4461 boolean hasVisibleActivities = false;
4462
4463 // Clean out the history list.
4464 int i = mHistory.size();
4465 if (localLOGV) Log.v(
4466 TAG, "Removing app " + app + " from history with " + i + " entries");
4467 while (i > 0) {
4468 i--;
4469 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4470 if (localLOGV) Log.v(
4471 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4472 if (r.app == app) {
4473 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4474 if (localLOGV) Log.v(
4475 TAG, "Removing this entry! frozen=" + r.haveState
4476 + " finishing=" + r.finishing);
4477 mHistory.remove(i);
4478
4479 r.inHistory = false;
4480 mWindowManager.removeAppToken(r);
4481 if (VALIDATE_TOKENS) {
4482 mWindowManager.validateAppTokens(mHistory);
4483 }
4484 removeActivityUriPermissionsLocked(r);
4485
4486 } else {
4487 // We have the current state for this activity, so
4488 // it can be restarted later when needed.
4489 if (localLOGV) Log.v(
4490 TAG, "Keeping entry, setting app to null");
4491 if (r.visible) {
4492 hasVisibleActivities = true;
4493 }
4494 r.app = null;
4495 r.nowVisible = false;
4496 if (!r.haveState) {
4497 r.icicle = null;
4498 }
4499 }
4500
4501 cleanUpActivityLocked(r, true);
4502 r.state = ActivityState.STOPPED;
4503 }
4504 atTop = false;
4505 }
4506
4507 app.activities.clear();
4508
4509 if (app.instrumentationClass != null) {
4510 Log.w(TAG, "Crash of app " + app.processName
4511 + " running instrumentation " + app.instrumentationClass);
4512 Bundle info = new Bundle();
4513 info.putString("shortMsg", "Process crashed.");
4514 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4515 }
4516
4517 if (!restarting) {
4518 if (!resumeTopActivityLocked(null)) {
4519 // If there was nothing to resume, and we are not already
4520 // restarting this process, but there is a visible activity that
4521 // is hosted by the process... then make sure all visible
4522 // activities are running, taking care of restarting this
4523 // process.
4524 if (hasVisibleActivities) {
4525 ensureActivitiesVisibleLocked(null, 0);
4526 }
4527 }
4528 }
4529 }
4530
4531 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4532 IBinder threadBinder = thread.asBinder();
4533
4534 // Find the application record.
4535 int count = mLRUProcesses.size();
4536 int i;
4537 for (i=0; i<count; i++) {
4538 ProcessRecord rec = mLRUProcesses.get(i);
4539 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4540 return i;
4541 }
4542 }
4543 return -1;
4544 }
4545
4546 private final ProcessRecord getRecordForAppLocked(
4547 IApplicationThread thread) {
4548 if (thread == null) {
4549 return null;
4550 }
4551
4552 int appIndex = getLRURecordIndexForAppLocked(thread);
4553 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4554 }
4555
4556 private final void appDiedLocked(ProcessRecord app, int pid,
4557 IApplicationThread thread) {
4558
4559 mProcDeaths[0]++;
4560
Magnus Edlund7bb25812010-02-24 15:45:06 +01004561 // Clean up already done if the process has been re-started.
4562 if (app.pid == pid && app.thread != null &&
4563 app.thread.asBinder() == thread.asBinder()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004564 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4565 + ") has died.");
4566 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4567 if (localLOGV) Log.v(
4568 TAG, "Dying app: " + app + ", pid: " + pid
4569 + ", thread: " + thread.asBinder());
4570 boolean doLowMem = app.instrumentationClass == null;
4571 handleAppDiedLocked(app, false);
4572
4573 if (doLowMem) {
4574 // If there are no longer any background processes running,
4575 // and the app that died was not running instrumentation,
4576 // then tell everyone we are now low on memory.
4577 boolean haveBg = false;
4578 int count = mLRUProcesses.size();
4579 int i;
4580 for (i=0; i<count; i++) {
4581 ProcessRecord rec = mLRUProcesses.get(i);
4582 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4583 haveBg = true;
4584 break;
4585 }
4586 }
4587
4588 if (!haveBg) {
4589 Log.i(TAG, "Low Memory: No more background processes.");
4590 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004591 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004592 for (i=0; i<count; i++) {
4593 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004594 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004595 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4596 // The low memory report is overriding any current
4597 // state for a GC request. Make sure to do
4598 // visible/foreground processes first.
4599 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4600 rec.lastRequestedGc = 0;
4601 } else {
4602 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004603 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004604 rec.reportLowMemory = true;
4605 rec.lastLowMemory = now;
4606 mProcessesToGc.remove(rec);
4607 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 }
4609 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004610 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004611 }
4612 }
Magnus Edlund7bb25812010-02-24 15:45:06 +01004613 } else if (app.pid != pid) {
4614 // A new process has already been started.
4615 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4616 + ") has died and restarted (pid " + app.pid + ").");
4617 EventLog.writeEvent(LOG_AM_PROCESS_DIED, pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004618 } else if (Config.LOGD) {
4619 Log.d(TAG, "Received spurious death notification for thread "
4620 + thread.asBinder());
4621 }
4622 }
4623
4624 final String readFile(String filename) {
4625 try {
4626 FileInputStream fs = new FileInputStream(filename);
4627 byte[] inp = new byte[8192];
4628 int size = fs.read(inp);
4629 fs.close();
4630 return new String(inp, 0, 0, size);
4631 } catch (java.io.IOException e) {
4632 }
4633 return "";
4634 }
4635
4636 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004637 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004638 if (app.notResponding || app.crashing) {
4639 return;
4640 }
4641
4642 // Log the ANR to the event log.
4643 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4644
4645 // If we are on a secure build and the application is not interesting to the user (it is
4646 // not visible or in the background), just kill it instead of displaying a dialog.
4647 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4648 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4649 Process.killProcess(app.pid);
4650 return;
4651 }
4652
4653 // DeviceMonitor.start();
4654
4655 String processInfo = null;
4656 if (MONITOR_CPU_USAGE) {
4657 updateCpuStatsNow();
4658 synchronized (mProcessStatsThread) {
4659 processInfo = mProcessStats.printCurrentState();
4660 }
4661 }
4662
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004663 StringBuilder info = mStringBuilder;
4664 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004665 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004666 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004667 if (reportedActivity != null && reportedActivity.app != null) {
4668 info.append(" (last in ");
4669 info.append(reportedActivity.app.processName);
4670 info.append(")");
4671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004672 if (annotation != null) {
4673 info.append("\nAnnotation: ");
4674 info.append(annotation);
4675 }
4676 if (MONITOR_CPU_USAGE) {
4677 info.append("\nCPU usage:\n");
4678 info.append(processInfo);
4679 }
4680 Log.i(TAG, info.toString());
4681
4682 // The application is not responding. Dump as many thread traces as we can.
4683 boolean fileDump = prepareTraceFile(true);
4684 if (!fileDump) {
4685 // Dumping traces to the log, just dump the process that isn't responding so
4686 // we don't overflow the log
4687 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4688 } else {
4689 // Dumping traces to a file so dump all active processes we know about
4690 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004691 // First, these are the most important processes.
4692 final int[] imppids = new int[3];
4693 int i=0;
4694 imppids[0] = app.pid;
4695 i++;
4696 if (reportedActivity != null && reportedActivity.app != null
4697 && reportedActivity.app.thread != null
4698 && reportedActivity.app.pid != app.pid) {
4699 imppids[i] = reportedActivity.app.pid;
4700 i++;
4701 }
4702 imppids[i] = Process.myPid();
4703 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4704 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4705 synchronized (this) {
4706 try {
4707 wait(200);
4708 } catch (InterruptedException e) {
4709 }
4710 }
4711 }
4712 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004713 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004714 boolean done = false;
4715 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4716 if (imppids[j] == r.pid) {
4717 done = true;
4718 break;
4719 }
4720 }
4721 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004722 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004723 synchronized (this) {
4724 try {
4725 wait(200);
4726 } catch (InterruptedException e) {
4727 }
4728 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004729 }
4730 }
4731 }
4732 }
4733
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004734 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004735 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004736 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004737 app.pid, info.toString());
4738 if (res != 0) {
4739 if (res < 0) {
4740 // wait until the SIGQUIT has had a chance to process before killing the
4741 // process.
4742 try {
4743 wait(2000);
4744 } catch (InterruptedException e) {
4745 }
4746
4747 Process.killProcess(app.pid);
4748 return;
4749 }
4750 }
4751 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004752 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004753 }
4754 }
4755
4756 makeAppNotRespondingLocked(app,
4757 activity != null ? activity.shortComponentName : null,
4758 annotation != null ? "ANR " + annotation : "ANR",
4759 info.toString(), null);
4760 Message msg = Message.obtain();
4761 HashMap map = new HashMap();
4762 msg.what = SHOW_NOT_RESPONDING_MSG;
4763 msg.obj = map;
4764 map.put("app", app);
4765 if (activity != null) {
4766 map.put("activity", activity);
4767 }
4768
4769 mHandler.sendMessage(msg);
4770 return;
4771 }
4772
4773 /**
4774 * If a stack trace file has been configured, prepare the filesystem
4775 * by creating the directory if it doesn't exist and optionally
4776 * removing the old trace file.
4777 *
4778 * @param removeExisting If set, the existing trace file will be removed.
4779 * @return Returns true if the trace file preparations succeeded
4780 */
4781 public static boolean prepareTraceFile(boolean removeExisting) {
4782 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4783 boolean fileReady = false;
4784 if (!TextUtils.isEmpty(tracesPath)) {
4785 File f = new File(tracesPath);
4786 if (!f.exists()) {
4787 // Ensure the enclosing directory exists
4788 File dir = f.getParentFile();
4789 if (!dir.exists()) {
4790 fileReady = dir.mkdirs();
4791 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004792 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004793 } else if (dir.isDirectory()) {
4794 fileReady = true;
4795 }
4796 } else if (removeExisting) {
4797 // Remove the previous traces file, so we don't fill the disk.
4798 // The VM will recreate it
4799 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4800 fileReady = f.delete();
4801 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004802
4803 if (removeExisting) {
4804 try {
4805 f.createNewFile();
4806 FileUtils.setPermissions(f.getAbsolutePath(),
4807 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4808 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4809 fileReady = true;
4810 } catch (IOException e) {
4811 Log.w(TAG, "Unable to make ANR traces file", e);
4812 }
4813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004814 }
4815
4816 return fileReady;
4817 }
4818
4819
4820 private final void decPersistentCountLocked(ProcessRecord app)
4821 {
4822 app.persistentActivities--;
4823 if (app.persistentActivities > 0) {
4824 // Still more of 'em...
4825 return;
4826 }
4827 if (app.persistent) {
4828 // Ah, but the application itself is persistent. Whatever!
4829 return;
4830 }
4831
4832 // App is no longer persistent... make sure it and the ones
4833 // following it in the LRU list have the correc oom_adj.
4834 updateOomAdjLocked();
4835 }
4836
4837 public void setPersistent(IBinder token, boolean isPersistent) {
4838 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4839 != PackageManager.PERMISSION_GRANTED) {
4840 String msg = "Permission Denial: setPersistent() from pid="
4841 + Binder.getCallingPid()
4842 + ", uid=" + Binder.getCallingUid()
4843 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4844 Log.w(TAG, msg);
4845 throw new SecurityException(msg);
4846 }
4847
4848 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004849 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004850 if (index < 0) {
4851 return;
4852 }
4853 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4854 ProcessRecord app = r.app;
4855
4856 if (localLOGV) Log.v(
4857 TAG, "Setting persistence " + isPersistent + ": " + r);
4858
4859 if (isPersistent) {
4860 if (r.persistent) {
4861 // Okay okay, I heard you already!
4862 if (localLOGV) Log.v(TAG, "Already persistent!");
4863 return;
4864 }
4865 r.persistent = true;
4866 app.persistentActivities++;
4867 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4868 if (app.persistentActivities > 1) {
4869 // We aren't the first...
4870 if (localLOGV) Log.v(TAG, "Not the first!");
4871 return;
4872 }
4873 if (app.persistent) {
4874 // This would be redundant.
4875 if (localLOGV) Log.v(TAG, "App is persistent!");
4876 return;
4877 }
4878
4879 // App is now persistent... make sure it and the ones
4880 // following it now have the correct oom_adj.
4881 final long origId = Binder.clearCallingIdentity();
4882 updateOomAdjLocked();
4883 Binder.restoreCallingIdentity(origId);
4884
4885 } else {
4886 if (!r.persistent) {
4887 // Okay okay, I heard you already!
4888 return;
4889 }
4890 r.persistent = false;
4891 final long origId = Binder.clearCallingIdentity();
4892 decPersistentCountLocked(app);
4893 Binder.restoreCallingIdentity(origId);
4894
4895 }
4896 }
4897 }
4898
4899 public boolean clearApplicationUserData(final String packageName,
4900 final IPackageDataObserver observer) {
4901 int uid = Binder.getCallingUid();
4902 int pid = Binder.getCallingPid();
4903 long callingId = Binder.clearCallingIdentity();
4904 try {
4905 IPackageManager pm = ActivityThread.getPackageManager();
4906 int pkgUid = -1;
4907 synchronized(this) {
4908 try {
4909 pkgUid = pm.getPackageUid(packageName);
4910 } catch (RemoteException e) {
4911 }
4912 if (pkgUid == -1) {
4913 Log.w(TAG, "Invalid packageName:" + packageName);
4914 return false;
4915 }
4916 if (uid == pkgUid || checkComponentPermission(
4917 android.Manifest.permission.CLEAR_APP_USER_DATA,
4918 pid, uid, -1)
4919 == PackageManager.PERMISSION_GRANTED) {
4920 restartPackageLocked(packageName, pkgUid);
4921 } else {
4922 throw new SecurityException(pid+" does not have permission:"+
4923 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4924 "for process:"+packageName);
4925 }
4926 }
4927
4928 try {
4929 //clear application user data
4930 pm.clearApplicationUserData(packageName, observer);
4931 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4932 Uri.fromParts("package", packageName, null));
4933 intent.putExtra(Intent.EXTRA_UID, pkgUid);
Josh Bartel2ecce342010-02-25 10:55:48 -06004934 synchronized (this) {
4935 broadcastIntentLocked(null, null, intent,
4936 null, null, 0, null, null, null,
4937 false, false, MY_PID, Process.SYSTEM_UID);
4938 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004939 } catch (RemoteException e) {
4940 }
4941 } finally {
4942 Binder.restoreCallingIdentity(callingId);
4943 }
4944 return true;
4945 }
4946
4947 public void restartPackage(final String packageName) {
4948 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4949 != PackageManager.PERMISSION_GRANTED) {
4950 String msg = "Permission Denial: restartPackage() from pid="
4951 + Binder.getCallingPid()
4952 + ", uid=" + Binder.getCallingUid()
4953 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4954 Log.w(TAG, msg);
4955 throw new SecurityException(msg);
4956 }
4957
4958 long callingId = Binder.clearCallingIdentity();
4959 try {
4960 IPackageManager pm = ActivityThread.getPackageManager();
4961 int pkgUid = -1;
4962 synchronized(this) {
4963 try {
4964 pkgUid = pm.getPackageUid(packageName);
4965 } catch (RemoteException e) {
4966 }
4967 if (pkgUid == -1) {
4968 Log.w(TAG, "Invalid packageName: " + packageName);
4969 return;
4970 }
4971 restartPackageLocked(packageName, pkgUid);
4972 }
4973 } finally {
4974 Binder.restoreCallingIdentity(callingId);
4975 }
4976 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004977
4978 /*
4979 * The pkg name and uid have to be specified.
4980 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4981 */
4982 public void killApplicationWithUid(String pkg, int uid) {
4983 if (pkg == null) {
4984 return;
4985 }
4986 // Make sure the uid is valid.
4987 if (uid < 0) {
4988 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4989 return;
4990 }
4991 int callerUid = Binder.getCallingUid();
4992 // Only the system server can kill an application
4993 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004994 // Post an aysnc message to kill the application
4995 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4996 msg.arg1 = uid;
4997 msg.arg2 = 0;
4998 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004999 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07005000 } else {
5001 throw new SecurityException(callerUid + " cannot kill pkg: " +
5002 pkg);
5003 }
5004 }
5005
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005006 public void closeSystemDialogs(String reason) {
5007 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
5008 if (reason != null) {
5009 intent.putExtra("reason", reason);
5010 }
5011
5012 final int uid = Binder.getCallingUid();
5013 final long origId = Binder.clearCallingIdentity();
5014 synchronized (this) {
5015 int i = mWatchers.beginBroadcast();
5016 while (i > 0) {
5017 i--;
5018 IActivityWatcher w = mWatchers.getBroadcastItem(i);
5019 if (w != null) {
5020 try {
5021 w.closingSystemDialogs(reason);
5022 } catch (RemoteException e) {
5023 }
5024 }
5025 }
5026 mWatchers.finishBroadcast();
5027
Dianne Hackbornffa42482009-09-23 22:20:11 -07005028 mWindowManager.closeSystemDialogs(reason);
5029
5030 for (i=mHistory.size()-1; i>=0; i--) {
5031 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5032 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
5033 finishActivityLocked(r, i,
5034 Activity.RESULT_CANCELED, null, "close-sys");
5035 }
5036 }
5037
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005038 broadcastIntentLocked(null, null, intent, null,
5039 null, 0, null, null, null, false, false, -1, uid);
5040 }
5041 Binder.restoreCallingIdentity(origId);
5042 }
5043
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005044 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005045 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005046 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5047 for (int i=pids.length-1; i>=0; i--) {
5048 infos[i] = new Debug.MemoryInfo();
5049 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005050 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005051 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005052 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005053
5054 public void killApplicationProcess(String processName, int uid) {
5055 if (processName == null) {
5056 return;
5057 }
5058
5059 int callerUid = Binder.getCallingUid();
5060 // Only the system server can kill an application
5061 if (callerUid == Process.SYSTEM_UID) {
5062 synchronized (this) {
5063 ProcessRecord app = getProcessRecordLocked(processName, uid);
5064 if (app != null) {
5065 try {
5066 app.thread.scheduleSuicide();
5067 } catch (RemoteException e) {
5068 // If the other end already died, then our work here is done.
5069 }
5070 } else {
5071 Log.w(TAG, "Process/uid not found attempting kill of "
5072 + processName + " / " + uid);
5073 }
5074 }
5075 } else {
5076 throw new SecurityException(callerUid + " cannot kill app process: " +
5077 processName);
5078 }
5079 }
5080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005081 private void restartPackageLocked(final String packageName, int uid) {
5082 uninstallPackageLocked(packageName, uid, false);
5083 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5084 Uri.fromParts("package", packageName, null));
5085 intent.putExtra(Intent.EXTRA_UID, uid);
5086 broadcastIntentLocked(null, null, intent,
5087 null, null, 0, null, null, null,
5088 false, false, MY_PID, Process.SYSTEM_UID);
5089 }
5090
5091 private final void uninstallPackageLocked(String name, int uid,
5092 boolean callerWillRestart) {
5093 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5094
5095 int i, N;
5096
5097 final String procNamePrefix = name + ":";
5098 if (uid < 0) {
5099 try {
5100 uid = ActivityThread.getPackageManager().getPackageUid(name);
5101 } catch (RemoteException e) {
5102 }
5103 }
5104
5105 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5106 while (badApps.hasNext()) {
5107 SparseArray<Long> ba = badApps.next();
5108 if (ba.get(uid) != null) {
5109 badApps.remove();
5110 }
5111 }
5112
5113 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5114
5115 // Remove all processes this package may have touched: all with the
5116 // same UID (except for the system or root user), and all whose name
5117 // matches the package name.
5118 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5119 final int NA = apps.size();
5120 for (int ia=0; ia<NA; ia++) {
5121 ProcessRecord app = apps.valueAt(ia);
5122 if (app.removed) {
5123 procs.add(app);
5124 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5125 || app.processName.equals(name)
5126 || app.processName.startsWith(procNamePrefix)) {
5127 app.removed = true;
5128 procs.add(app);
5129 }
5130 }
5131 }
5132
5133 N = procs.size();
5134 for (i=0; i<N; i++) {
5135 removeProcessLocked(procs.get(i), callerWillRestart);
5136 }
5137
5138 for (i=mHistory.size()-1; i>=0; i--) {
5139 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5140 if (r.packageName.equals(name)) {
5141 if (Config.LOGD) Log.d(
5142 TAG, " Force finishing activity "
5143 + r.intent.getComponent().flattenToShortString());
5144 if (r.app != null) {
5145 r.app.removed = true;
5146 }
5147 r.app = null;
5148 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5149 }
5150 }
5151
5152 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5153 for (ServiceRecord service : mServices.values()) {
5154 if (service.packageName.equals(name)) {
5155 if (service.app != null) {
5156 service.app.removed = true;
5157 }
5158 service.app = null;
5159 services.add(service);
5160 }
5161 }
5162
5163 N = services.size();
5164 for (i=0; i<N; i++) {
5165 bringDownServiceLocked(services.get(i), true);
5166 }
5167
5168 resumeTopActivityLocked(null);
5169 }
5170
5171 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5172 final String name = app.processName;
5173 final int uid = app.info.uid;
5174 if (Config.LOGD) Log.d(
5175 TAG, "Force removing process " + app + " (" + name
5176 + "/" + uid + ")");
5177
5178 mProcessNames.remove(name, uid);
5179 boolean needRestart = false;
5180 if (app.pid > 0 && app.pid != MY_PID) {
5181 int pid = app.pid;
5182 synchronized (mPidsSelfLocked) {
5183 mPidsSelfLocked.remove(pid);
5184 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5185 }
5186 handleAppDiedLocked(app, true);
5187 mLRUProcesses.remove(app);
5188 Process.killProcess(pid);
5189
5190 if (app.persistent) {
5191 if (!callerWillRestart) {
5192 addAppLocked(app.info);
5193 } else {
5194 needRestart = true;
5195 }
5196 }
5197 } else {
5198 mRemovedProcesses.add(app);
5199 }
5200
5201 return needRestart;
5202 }
5203
5204 private final void processStartTimedOutLocked(ProcessRecord app) {
5205 final int pid = app.pid;
5206 boolean gone = false;
5207 synchronized (mPidsSelfLocked) {
5208 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5209 if (knownApp != null && knownApp.thread == null) {
5210 mPidsSelfLocked.remove(pid);
5211 gone = true;
5212 }
5213 }
5214
5215 if (gone) {
5216 Log.w(TAG, "Process " + app + " failed to attach");
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005217 EventLog.writeEvent(LOG_AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
5218 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005219 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005220 // Take care of any launching providers waiting for this process.
5221 checkAppInLaunchingProvidersLocked(app, true);
5222 // Take care of any services that are waiting for the process.
5223 for (int i=0; i<mPendingServices.size(); i++) {
5224 ServiceRecord sr = mPendingServices.get(i);
5225 if (app.info.uid == sr.appInfo.uid
5226 && app.processName.equals(sr.processName)) {
5227 Log.w(TAG, "Forcing bringing down service: " + sr);
5228 mPendingServices.remove(i);
5229 i--;
5230 bringDownServiceLocked(sr, true);
5231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005232 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005233 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005234 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5235 Log.w(TAG, "Unattached app died before backup, skipping");
5236 try {
5237 IBackupManager bm = IBackupManager.Stub.asInterface(
5238 ServiceManager.getService(Context.BACKUP_SERVICE));
5239 bm.agentDisconnected(app.info.packageName);
5240 } catch (RemoteException e) {
5241 // Can't happen; the backup manager is local
5242 }
5243 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005244 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5245 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5246 mPendingBroadcast = null;
5247 scheduleBroadcastsLocked();
5248 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005249 } else {
5250 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5251 }
5252 }
5253
5254 private final boolean attachApplicationLocked(IApplicationThread thread,
5255 int pid) {
5256
5257 // Find the application record that is being attached... either via
5258 // the pid if we are running in multiple processes, or just pull the
5259 // next app record if we are emulating process with anonymous threads.
5260 ProcessRecord app;
5261 if (pid != MY_PID && pid >= 0) {
5262 synchronized (mPidsSelfLocked) {
5263 app = mPidsSelfLocked.get(pid);
5264 }
5265 } else if (mStartingProcesses.size() > 0) {
5266 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005267 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005268 } else {
5269 app = null;
5270 }
5271
5272 if (app == null) {
5273 Log.w(TAG, "No pending application record for pid " + pid
5274 + " (IApplicationThread " + thread + "); dropping process");
5275 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5276 if (pid > 0 && pid != MY_PID) {
5277 Process.killProcess(pid);
5278 } else {
5279 try {
5280 thread.scheduleExit();
5281 } catch (Exception e) {
5282 // Ignore exceptions.
5283 }
5284 }
5285 return false;
5286 }
5287
5288 // If this application record is still attached to a previous
5289 // process, clean it up now.
5290 if (app.thread != null) {
5291 handleAppDiedLocked(app, true);
5292 }
5293
5294 // Tell the process all about itself.
5295
5296 if (localLOGV) Log.v(
5297 TAG, "Binding process pid " + pid + " to record " + app);
5298
5299 String processName = app.processName;
5300 try {
5301 thread.asBinder().linkToDeath(new AppDeathRecipient(
5302 app, pid, thread), 0);
5303 } catch (RemoteException e) {
5304 app.resetPackageList();
5305 startProcessLocked(app, "link fail", processName);
5306 return false;
5307 }
5308
5309 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5310
5311 app.thread = thread;
5312 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005313 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005314 app.forcingToForeground = null;
5315 app.foregroundServices = false;
5316 app.debugging = false;
5317
5318 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5319
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005320 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5321 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005322
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005323 if (!normalMode) {
5324 Log.i(TAG, "Launching preboot mode app: " + app);
5325 }
5326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005327 if (localLOGV) Log.v(
5328 TAG, "New app record " + app
5329 + " thread=" + thread.asBinder() + " pid=" + pid);
5330 try {
5331 int testMode = IApplicationThread.DEBUG_OFF;
5332 if (mDebugApp != null && mDebugApp.equals(processName)) {
5333 testMode = mWaitForDebugger
5334 ? IApplicationThread.DEBUG_WAIT
5335 : IApplicationThread.DEBUG_ON;
5336 app.debugging = true;
5337 if (mDebugTransient) {
5338 mDebugApp = mOrigDebugApp;
5339 mWaitForDebugger = mOrigWaitForDebugger;
5340 }
5341 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005342
Christopher Tate181fafa2009-05-14 11:12:14 -07005343 // If the app is being launched for restore or full backup, set it up specially
5344 boolean isRestrictedBackupMode = false;
5345 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5346 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5347 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5348 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005349
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005350 ensurePackageDexOpt(app.instrumentationInfo != null
5351 ? app.instrumentationInfo.packageName
5352 : app.info.packageName);
5353 if (app.instrumentationClass != null) {
5354 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005355 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005356 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5357 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005358 thread.bindApplication(processName, app.instrumentationInfo != null
5359 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005360 app.instrumentationClass, app.instrumentationProfileFile,
5361 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005362 isRestrictedBackupMode || !normalMode,
5363 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005364 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005365 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005366 } catch (Exception e) {
5367 // todo: Yikes! What should we do? For now we will try to
5368 // start another process, but that could easily get us in
5369 // an infinite loop of restarting processes...
5370 Log.w(TAG, "Exception thrown during bind!", e);
5371
5372 app.resetPackageList();
5373 startProcessLocked(app, "bind fail", processName);
5374 return false;
5375 }
5376
5377 // Remove this record from the list of starting applications.
5378 mPersistentStartingProcesses.remove(app);
5379 mProcessesOnHold.remove(app);
5380
5381 boolean badApp = false;
5382 boolean didSomething = false;
5383
5384 // See if the top visible activity is waiting to run in this process...
5385 HistoryRecord hr = topRunningActivityLocked(null);
5386 if (hr != null) {
5387 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5388 && processName.equals(hr.processName)) {
5389 try {
5390 if (realStartActivityLocked(hr, app, true, true)) {
5391 didSomething = true;
5392 }
5393 } catch (Exception e) {
5394 Log.w(TAG, "Exception in new application when starting activity "
5395 + hr.intent.getComponent().flattenToShortString(), e);
5396 badApp = true;
5397 }
5398 } else {
5399 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5400 }
5401 }
5402
5403 // Find any services that should be running in this process...
5404 if (!badApp && mPendingServices.size() > 0) {
5405 ServiceRecord sr = null;
5406 try {
5407 for (int i=0; i<mPendingServices.size(); i++) {
5408 sr = mPendingServices.get(i);
5409 if (app.info.uid != sr.appInfo.uid
5410 || !processName.equals(sr.processName)) {
5411 continue;
5412 }
5413
5414 mPendingServices.remove(i);
5415 i--;
5416 realStartServiceLocked(sr, app);
5417 didSomething = true;
5418 }
5419 } catch (Exception e) {
5420 Log.w(TAG, "Exception in new application when starting service "
5421 + sr.shortName, e);
5422 badApp = true;
5423 }
5424 }
5425
5426 // Check if the next broadcast receiver is in this process...
5427 BroadcastRecord br = mPendingBroadcast;
5428 if (!badApp && br != null && br.curApp == app) {
5429 try {
5430 mPendingBroadcast = null;
5431 processCurBroadcastLocked(br, app);
5432 didSomething = true;
5433 } catch (Exception e) {
5434 Log.w(TAG, "Exception in new application when starting receiver "
5435 + br.curComponent.flattenToShortString(), e);
5436 badApp = true;
5437 logBroadcastReceiverDiscard(br);
5438 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5439 br.resultExtras, br.resultAbort, true);
5440 scheduleBroadcastsLocked();
Magnus Edlund7bb25812010-02-24 15:45:06 +01005441 // We need to reset the state if we fails to start the receiver.
5442 br.state = BroadcastRecord.IDLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005443 }
5444 }
5445
Christopher Tate181fafa2009-05-14 11:12:14 -07005446 // Check whether the next backup agent is in this process...
5447 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5448 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005449 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005450 try {
5451 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5452 } catch (Exception e) {
5453 Log.w(TAG, "Exception scheduling backup agent creation: ");
5454 e.printStackTrace();
5455 }
5456 }
5457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005458 if (badApp) {
5459 // todo: Also need to kill application to deal with all
5460 // kinds of exceptions.
5461 handleAppDiedLocked(app, false);
5462 return false;
5463 }
5464
5465 if (!didSomething) {
5466 updateOomAdjLocked();
5467 }
5468
5469 return true;
5470 }
5471
5472 public final void attachApplication(IApplicationThread thread) {
5473 synchronized (this) {
5474 int callingPid = Binder.getCallingPid();
5475 final long origId = Binder.clearCallingIdentity();
5476 attachApplicationLocked(thread, callingPid);
5477 Binder.restoreCallingIdentity(origId);
5478 }
5479 }
5480
Dianne Hackborne88846e2009-09-30 21:34:25 -07005481 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005482 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005483 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005484 Binder.restoreCallingIdentity(origId);
5485 }
5486
5487 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5488 boolean remove) {
5489 int N = mStoppingActivities.size();
5490 if (N <= 0) return null;
5491
5492 ArrayList<HistoryRecord> stops = null;
5493
5494 final boolean nowVisible = mResumedActivity != null
5495 && mResumedActivity.nowVisible
5496 && !mResumedActivity.waitingVisible;
5497 for (int i=0; i<N; i++) {
5498 HistoryRecord s = mStoppingActivities.get(i);
5499 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5500 + nowVisible + " waitingVisible=" + s.waitingVisible
5501 + " finishing=" + s.finishing);
5502 if (s.waitingVisible && nowVisible) {
5503 mWaitingVisibleActivities.remove(s);
5504 s.waitingVisible = false;
5505 if (s.finishing) {
5506 // If this activity is finishing, it is sitting on top of
5507 // everyone else but we now know it is no longer needed...
5508 // so get rid of it. Otherwise, we need to go through the
5509 // normal flow and hide it once we determine that it is
5510 // hidden by the activities in front of it.
5511 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5512 mWindowManager.setAppVisibility(s, false);
5513 }
5514 }
5515 if (!s.waitingVisible && remove) {
5516 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5517 if (stops == null) {
5518 stops = new ArrayList<HistoryRecord>();
5519 }
5520 stops.add(s);
5521 mStoppingActivities.remove(i);
5522 N--;
5523 i--;
5524 }
5525 }
5526
5527 return stops;
5528 }
5529
5530 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005531 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5532 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005533 mWindowManager.enableScreenAfterBoot();
5534 }
5535
Dianne Hackborne88846e2009-09-30 21:34:25 -07005536 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5537 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005538 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5539
5540 ArrayList<HistoryRecord> stops = null;
5541 ArrayList<HistoryRecord> finishes = null;
5542 ArrayList<HistoryRecord> thumbnails = null;
5543 int NS = 0;
5544 int NF = 0;
5545 int NT = 0;
5546 IApplicationThread sendThumbnail = null;
5547 boolean booting = false;
5548 boolean enableScreen = false;
5549
5550 synchronized (this) {
5551 if (token != null) {
5552 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5553 }
5554
5555 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005556 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005557 if (index >= 0) {
5558 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5559
Dianne Hackborne88846e2009-09-30 21:34:25 -07005560 // This is a hack to semi-deal with a race condition
5561 // in the client where it can be constructed with a
5562 // newer configuration from when we asked it to launch.
5563 // We'll update with whatever configuration it now says
5564 // it used to launch.
5565 if (config != null) {
5566 r.configuration = config;
5567 }
5568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005569 // No longer need to keep the device awake.
5570 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5571 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5572 mLaunchingActivity.release();
5573 }
5574
5575 // We are now idle. If someone is waiting for a thumbnail from
5576 // us, we can now deliver.
5577 r.idle = true;
5578 scheduleAppGcsLocked();
5579 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5580 sendThumbnail = r.app.thread;
5581 r.thumbnailNeeded = false;
5582 }
5583
5584 // If this activity is fullscreen, set up to hide those under it.
5585
5586 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5587 ensureActivitiesVisibleLocked(null, 0);
5588
5589 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5590 if (!mBooted && !fromTimeout) {
5591 mBooted = true;
5592 enableScreen = true;
5593 }
5594 }
5595
5596 // Atomically retrieve all of the other things to do.
5597 stops = processStoppingActivitiesLocked(true);
5598 NS = stops != null ? stops.size() : 0;
5599 if ((NF=mFinishingActivities.size()) > 0) {
5600 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5601 mFinishingActivities.clear();
5602 }
5603 if ((NT=mCancelledThumbnails.size()) > 0) {
5604 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5605 mCancelledThumbnails.clear();
5606 }
5607
5608 booting = mBooting;
5609 mBooting = false;
5610 }
5611
5612 int i;
5613
5614 // Send thumbnail if requested.
5615 if (sendThumbnail != null) {
5616 try {
5617 sendThumbnail.requestThumbnail(token);
5618 } catch (Exception e) {
5619 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5620 sendPendingThumbnail(null, token, null, null, true);
5621 }
5622 }
5623
5624 // Stop any activities that are scheduled to do so but have been
5625 // waiting for the next one to start.
5626 for (i=0; i<NS; i++) {
5627 HistoryRecord r = (HistoryRecord)stops.get(i);
5628 synchronized (this) {
5629 if (r.finishing) {
5630 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5631 } else {
5632 stopActivityLocked(r);
5633 }
5634 }
5635 }
5636
5637 // Finish any activities that are scheduled to do so but have been
5638 // waiting for the next one to start.
5639 for (i=0; i<NF; i++) {
5640 HistoryRecord r = (HistoryRecord)finishes.get(i);
5641 synchronized (this) {
5642 destroyActivityLocked(r, true);
5643 }
5644 }
5645
5646 // Report back to any thumbnail receivers.
5647 for (i=0; i<NT; i++) {
5648 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5649 sendPendingThumbnail(r, null, null, null, true);
5650 }
5651
5652 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005653 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005654 }
5655
5656 trimApplications();
5657 //dump();
5658 //mWindowManager.dump();
5659
5660 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005661 enableScreenAfterBoot();
5662 }
5663 }
5664
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005665 final void finishBooting() {
5666 // Ensure that any processes we had put on hold are now started
5667 // up.
5668 final int NP = mProcessesOnHold.size();
5669 if (NP > 0) {
5670 ArrayList<ProcessRecord> procs =
5671 new ArrayList<ProcessRecord>(mProcessesOnHold);
5672 for (int ip=0; ip<NP; ip++) {
Josh Bartel2ecce342010-02-25 10:55:48 -06005673 synchronized (this) {
5674 this.startProcessLocked(procs.get(ip), "on-hold", null);
5675 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005676 }
5677 }
5678 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5679 // Tell anyone interested that we are done booting!
5680 synchronized (this) {
5681 broadcastIntentLocked(null, null,
5682 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5683 null, null, 0, null, null,
5684 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5685 false, false, MY_PID, Process.SYSTEM_UID);
5686 }
5687 }
5688 }
5689
5690 final void ensureBootCompleted() {
5691 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005692 boolean enableScreen;
5693 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005694 booting = mBooting;
5695 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005696 enableScreen = !mBooted;
5697 mBooted = true;
5698 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005699
5700 if (booting) {
5701 finishBooting();
5702 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005703
5704 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005705 enableScreenAfterBoot();
5706 }
5707 }
5708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005709 public final void activityPaused(IBinder token, Bundle icicle) {
5710 // Refuse possible leaked file descriptors
5711 if (icicle != null && icicle.hasFileDescriptors()) {
5712 throw new IllegalArgumentException("File descriptors passed in Bundle");
5713 }
5714
5715 final long origId = Binder.clearCallingIdentity();
5716 activityPaused(token, icicle, false);
5717 Binder.restoreCallingIdentity(origId);
5718 }
5719
5720 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5721 if (DEBUG_PAUSE) Log.v(
5722 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5723 + ", timeout=" + timeout);
5724
5725 HistoryRecord r = null;
5726
5727 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005728 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005729 if (index >= 0) {
5730 r = (HistoryRecord)mHistory.get(index);
5731 if (!timeout) {
5732 r.icicle = icicle;
5733 r.haveState = true;
5734 }
5735 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5736 if (mPausingActivity == r) {
5737 r.state = ActivityState.PAUSED;
5738 completePauseLocked();
5739 } else {
5740 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5741 System.identityHashCode(r), r.shortComponentName,
5742 mPausingActivity != null
5743 ? mPausingActivity.shortComponentName : "(none)");
5744 }
5745 }
5746 }
5747 }
5748
5749 public final void activityStopped(IBinder token, Bitmap thumbnail,
5750 CharSequence description) {
5751 if (localLOGV) Log.v(
5752 TAG, "Activity stopped: token=" + token);
5753
5754 HistoryRecord r = null;
5755
5756 final long origId = Binder.clearCallingIdentity();
5757
5758 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005759 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005760 if (index >= 0) {
5761 r = (HistoryRecord)mHistory.get(index);
5762 r.thumbnail = thumbnail;
5763 r.description = description;
5764 r.stopped = true;
5765 r.state = ActivityState.STOPPED;
5766 if (!r.finishing) {
5767 if (r.configDestroy) {
5768 destroyActivityLocked(r, true);
5769 resumeTopActivityLocked(null);
5770 }
5771 }
5772 }
5773 }
5774
5775 if (r != null) {
5776 sendPendingThumbnail(r, null, null, null, false);
5777 }
5778
5779 trimApplications();
5780
5781 Binder.restoreCallingIdentity(origId);
5782 }
5783
5784 public final void activityDestroyed(IBinder token) {
5785 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5786 synchronized (this) {
5787 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5788
Dianne Hackborn75b03852009-06-12 15:43:26 -07005789 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005790 if (index >= 0) {
5791 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5792 if (r.state == ActivityState.DESTROYING) {
5793 final long origId = Binder.clearCallingIdentity();
5794 removeActivityFromHistoryLocked(r);
5795 Binder.restoreCallingIdentity(origId);
5796 }
5797 }
5798 }
5799 }
5800
5801 public String getCallingPackage(IBinder token) {
5802 synchronized (this) {
5803 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005804 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005805 }
5806 }
5807
5808 public ComponentName getCallingActivity(IBinder token) {
5809 synchronized (this) {
5810 HistoryRecord r = getCallingRecordLocked(token);
5811 return r != null ? r.intent.getComponent() : null;
5812 }
5813 }
5814
5815 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005816 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005817 if (index >= 0) {
5818 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5819 if (r != null) {
5820 return r.resultTo;
5821 }
5822 }
5823 return null;
5824 }
5825
5826 public ComponentName getActivityClassForToken(IBinder token) {
5827 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005828 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005829 if (index >= 0) {
5830 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5831 return r.intent.getComponent();
5832 }
5833 return null;
5834 }
5835 }
5836
5837 public String getPackageForToken(IBinder token) {
5838 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005839 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005840 if (index >= 0) {
5841 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5842 return r.packageName;
5843 }
5844 return null;
5845 }
5846 }
5847
5848 public IIntentSender getIntentSender(int type,
5849 String packageName, IBinder token, String resultWho,
5850 int requestCode, Intent intent, String resolvedType, int flags) {
5851 // Refuse possible leaked file descriptors
5852 if (intent != null && intent.hasFileDescriptors() == true) {
5853 throw new IllegalArgumentException("File descriptors passed in Intent");
5854 }
5855
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005856 if (type == INTENT_SENDER_BROADCAST) {
5857 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5858 throw new IllegalArgumentException(
5859 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5860 }
5861 }
5862
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005863 synchronized(this) {
5864 int callingUid = Binder.getCallingUid();
5865 try {
5866 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5867 Process.supportsProcesses()) {
5868 int uid = ActivityThread.getPackageManager()
5869 .getPackageUid(packageName);
5870 if (uid != Binder.getCallingUid()) {
5871 String msg = "Permission Denial: getIntentSender() from pid="
5872 + Binder.getCallingPid()
5873 + ", uid=" + Binder.getCallingUid()
5874 + ", (need uid=" + uid + ")"
5875 + " is not allowed to send as package " + packageName;
5876 Log.w(TAG, msg);
5877 throw new SecurityException(msg);
5878 }
5879 }
5880 } catch (RemoteException e) {
5881 throw new SecurityException(e);
5882 }
5883 HistoryRecord activity = null;
5884 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005885 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005886 if (index < 0) {
5887 return null;
5888 }
5889 activity = (HistoryRecord)mHistory.get(index);
5890 if (activity.finishing) {
5891 return null;
5892 }
5893 }
5894
5895 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5896 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5897 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5898 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5899 |PendingIntent.FLAG_UPDATE_CURRENT);
5900
5901 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5902 type, packageName, activity, resultWho,
5903 requestCode, intent, resolvedType, flags);
5904 WeakReference<PendingIntentRecord> ref;
5905 ref = mIntentSenderRecords.get(key);
5906 PendingIntentRecord rec = ref != null ? ref.get() : null;
5907 if (rec != null) {
5908 if (!cancelCurrent) {
5909 if (updateCurrent) {
5910 rec.key.requestIntent.replaceExtras(intent);
5911 }
5912 return rec;
5913 }
5914 rec.canceled = true;
5915 mIntentSenderRecords.remove(key);
5916 }
5917 if (noCreate) {
5918 return rec;
5919 }
5920 rec = new PendingIntentRecord(this, key, callingUid);
5921 mIntentSenderRecords.put(key, rec.ref);
5922 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5923 if (activity.pendingResults == null) {
5924 activity.pendingResults
5925 = new HashSet<WeakReference<PendingIntentRecord>>();
5926 }
5927 activity.pendingResults.add(rec.ref);
5928 }
5929 return rec;
5930 }
5931 }
5932
5933 public void cancelIntentSender(IIntentSender sender) {
5934 if (!(sender instanceof PendingIntentRecord)) {
5935 return;
5936 }
5937 synchronized(this) {
5938 PendingIntentRecord rec = (PendingIntentRecord)sender;
5939 try {
5940 int uid = ActivityThread.getPackageManager()
5941 .getPackageUid(rec.key.packageName);
5942 if (uid != Binder.getCallingUid()) {
5943 String msg = "Permission Denial: cancelIntentSender() from pid="
5944 + Binder.getCallingPid()
5945 + ", uid=" + Binder.getCallingUid()
5946 + " is not allowed to cancel packges "
5947 + rec.key.packageName;
5948 Log.w(TAG, msg);
5949 throw new SecurityException(msg);
5950 }
5951 } catch (RemoteException e) {
5952 throw new SecurityException(e);
5953 }
5954 cancelIntentSenderLocked(rec, true);
5955 }
5956 }
5957
5958 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5959 rec.canceled = true;
5960 mIntentSenderRecords.remove(rec.key);
5961 if (cleanActivity && rec.key.activity != null) {
5962 rec.key.activity.pendingResults.remove(rec.ref);
5963 }
5964 }
5965
5966 public String getPackageForIntentSender(IIntentSender pendingResult) {
5967 if (!(pendingResult instanceof PendingIntentRecord)) {
5968 return null;
5969 }
5970 synchronized(this) {
5971 try {
5972 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5973 return res.key.packageName;
5974 } catch (ClassCastException e) {
5975 }
5976 }
5977 return null;
5978 }
5979
5980 public void setProcessLimit(int max) {
5981 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5982 "setProcessLimit()");
5983 mProcessLimit = max;
5984 }
5985
5986 public int getProcessLimit() {
5987 return mProcessLimit;
5988 }
5989
5990 void foregroundTokenDied(ForegroundToken token) {
5991 synchronized (ActivityManagerService.this) {
5992 synchronized (mPidsSelfLocked) {
5993 ForegroundToken cur
5994 = mForegroundProcesses.get(token.pid);
5995 if (cur != token) {
5996 return;
5997 }
5998 mForegroundProcesses.remove(token.pid);
5999 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
6000 if (pr == null) {
6001 return;
6002 }
6003 pr.forcingToForeground = null;
6004 pr.foregroundServices = false;
6005 }
6006 updateOomAdjLocked();
6007 }
6008 }
6009
6010 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
6011 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
6012 "setProcessForeground()");
6013 synchronized(this) {
6014 boolean changed = false;
6015
6016 synchronized (mPidsSelfLocked) {
6017 ProcessRecord pr = mPidsSelfLocked.get(pid);
6018 if (pr == null) {
6019 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
6020 return;
6021 }
6022 ForegroundToken oldToken = mForegroundProcesses.get(pid);
6023 if (oldToken != null) {
6024 oldToken.token.unlinkToDeath(oldToken, 0);
6025 mForegroundProcesses.remove(pid);
6026 pr.forcingToForeground = null;
6027 changed = true;
6028 }
6029 if (isForeground && token != null) {
6030 ForegroundToken newToken = new ForegroundToken() {
6031 public void binderDied() {
6032 foregroundTokenDied(this);
6033 }
6034 };
6035 newToken.pid = pid;
6036 newToken.token = token;
6037 try {
6038 token.linkToDeath(newToken, 0);
6039 mForegroundProcesses.put(pid, newToken);
6040 pr.forcingToForeground = token;
6041 changed = true;
6042 } catch (RemoteException e) {
6043 // If the process died while doing this, we will later
6044 // do the cleanup with the process death link.
6045 }
6046 }
6047 }
6048
6049 if (changed) {
6050 updateOomAdjLocked();
6051 }
6052 }
6053 }
6054
6055 // =========================================================
6056 // PERMISSIONS
6057 // =========================================================
6058
6059 static class PermissionController extends IPermissionController.Stub {
6060 ActivityManagerService mActivityManagerService;
6061 PermissionController(ActivityManagerService activityManagerService) {
6062 mActivityManagerService = activityManagerService;
6063 }
6064
6065 public boolean checkPermission(String permission, int pid, int uid) {
6066 return mActivityManagerService.checkPermission(permission, pid,
6067 uid) == PackageManager.PERMISSION_GRANTED;
6068 }
6069 }
6070
6071 /**
6072 * This can be called with or without the global lock held.
6073 */
6074 int checkComponentPermission(String permission, int pid, int uid,
6075 int reqUid) {
6076 // We might be performing an operation on behalf of an indirect binder
6077 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6078 // client identity accordingly before proceeding.
6079 Identity tlsIdentity = sCallerIdentity.get();
6080 if (tlsIdentity != null) {
6081 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6082 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6083 uid = tlsIdentity.uid;
6084 pid = tlsIdentity.pid;
6085 }
6086
6087 // Root, system server and our own process get to do everything.
6088 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6089 !Process.supportsProcesses()) {
6090 return PackageManager.PERMISSION_GRANTED;
6091 }
6092 // If the target requires a specific UID, always fail for others.
6093 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006094 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006095 return PackageManager.PERMISSION_DENIED;
6096 }
6097 if (permission == null) {
6098 return PackageManager.PERMISSION_GRANTED;
6099 }
6100 try {
6101 return ActivityThread.getPackageManager()
6102 .checkUidPermission(permission, uid);
6103 } catch (RemoteException e) {
6104 // Should never happen, but if it does... deny!
6105 Log.e(TAG, "PackageManager is dead?!?", e);
6106 }
6107 return PackageManager.PERMISSION_DENIED;
6108 }
6109
6110 /**
6111 * As the only public entry point for permissions checking, this method
6112 * can enforce the semantic that requesting a check on a null global
6113 * permission is automatically denied. (Internally a null permission
6114 * string is used when calling {@link #checkComponentPermission} in cases
6115 * when only uid-based security is needed.)
6116 *
6117 * This can be called with or without the global lock held.
6118 */
6119 public int checkPermission(String permission, int pid, int uid) {
6120 if (permission == null) {
6121 return PackageManager.PERMISSION_DENIED;
6122 }
6123 return checkComponentPermission(permission, pid, uid, -1);
6124 }
6125
6126 /**
6127 * Binder IPC calls go through the public entry point.
6128 * This can be called with or without the global lock held.
6129 */
6130 int checkCallingPermission(String permission) {
6131 return checkPermission(permission,
6132 Binder.getCallingPid(),
6133 Binder.getCallingUid());
6134 }
6135
6136 /**
6137 * This can be called with or without the global lock held.
6138 */
6139 void enforceCallingPermission(String permission, String func) {
6140 if (checkCallingPermission(permission)
6141 == PackageManager.PERMISSION_GRANTED) {
6142 return;
6143 }
6144
6145 String msg = "Permission Denial: " + func + " from pid="
6146 + Binder.getCallingPid()
6147 + ", uid=" + Binder.getCallingUid()
6148 + " requires " + permission;
6149 Log.w(TAG, msg);
6150 throw new SecurityException(msg);
6151 }
6152
6153 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6154 ProviderInfo pi, int uid, int modeFlags) {
6155 try {
6156 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6157 if ((pi.readPermission != null) &&
6158 (pm.checkUidPermission(pi.readPermission, uid)
6159 != PackageManager.PERMISSION_GRANTED)) {
6160 return false;
6161 }
6162 }
6163 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6164 if ((pi.writePermission != null) &&
6165 (pm.checkUidPermission(pi.writePermission, uid)
6166 != PackageManager.PERMISSION_GRANTED)) {
6167 return false;
6168 }
6169 }
6170 return true;
6171 } catch (RemoteException e) {
6172 return false;
6173 }
6174 }
6175
6176 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6177 int modeFlags) {
6178 // Root gets to do everything.
6179 if (uid == 0 || !Process.supportsProcesses()) {
6180 return true;
6181 }
6182 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6183 if (perms == null) return false;
6184 UriPermission perm = perms.get(uri);
6185 if (perm == null) return false;
6186 return (modeFlags&perm.modeFlags) == modeFlags;
6187 }
6188
6189 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6190 // Another redirected-binder-call permissions check as in
6191 // {@link checkComponentPermission}.
6192 Identity tlsIdentity = sCallerIdentity.get();
6193 if (tlsIdentity != null) {
6194 uid = tlsIdentity.uid;
6195 pid = tlsIdentity.pid;
6196 }
6197
6198 // Our own process gets to do everything.
6199 if (pid == MY_PID) {
6200 return PackageManager.PERMISSION_GRANTED;
6201 }
6202 synchronized(this) {
6203 return checkUriPermissionLocked(uri, uid, modeFlags)
6204 ? PackageManager.PERMISSION_GRANTED
6205 : PackageManager.PERMISSION_DENIED;
6206 }
6207 }
6208
6209 private void grantUriPermissionLocked(int callingUid,
6210 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6211 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6212 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6213 if (modeFlags == 0) {
6214 return;
6215 }
6216
6217 final IPackageManager pm = ActivityThread.getPackageManager();
6218
6219 // If this is not a content: uri, we can't do anything with it.
6220 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6221 return;
6222 }
6223
6224 String name = uri.getAuthority();
6225 ProviderInfo pi = null;
6226 ContentProviderRecord cpr
6227 = (ContentProviderRecord)mProvidersByName.get(name);
6228 if (cpr != null) {
6229 pi = cpr.info;
6230 } else {
6231 try {
6232 pi = pm.resolveContentProvider(name,
6233 PackageManager.GET_URI_PERMISSION_PATTERNS);
6234 } catch (RemoteException ex) {
6235 }
6236 }
6237 if (pi == null) {
6238 Log.w(TAG, "No content provider found for: " + name);
6239 return;
6240 }
6241
6242 int targetUid;
6243 try {
6244 targetUid = pm.getPackageUid(targetPkg);
6245 if (targetUid < 0) {
6246 return;
6247 }
6248 } catch (RemoteException ex) {
6249 return;
6250 }
6251
6252 // First... does the target actually need this permission?
6253 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6254 // No need to grant the target this permission.
6255 return;
6256 }
6257
6258 // Second... maybe someone else has already granted the
6259 // permission?
6260 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6261 // No need to grant the target this permission.
6262 return;
6263 }
6264
6265 // Third... is the provider allowing granting of URI permissions?
6266 if (!pi.grantUriPermissions) {
6267 throw new SecurityException("Provider " + pi.packageName
6268 + "/" + pi.name
6269 + " does not allow granting of Uri permissions (uri "
6270 + uri + ")");
6271 }
6272 if (pi.uriPermissionPatterns != null) {
6273 final int N = pi.uriPermissionPatterns.length;
6274 boolean allowed = false;
6275 for (int i=0; i<N; i++) {
6276 if (pi.uriPermissionPatterns[i] != null
6277 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6278 allowed = true;
6279 break;
6280 }
6281 }
6282 if (!allowed) {
6283 throw new SecurityException("Provider " + pi.packageName
6284 + "/" + pi.name
6285 + " does not allow granting of permission to path of Uri "
6286 + uri);
6287 }
6288 }
6289
6290 // Fourth... does the caller itself have permission to access
6291 // this uri?
6292 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6293 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6294 throw new SecurityException("Uid " + callingUid
6295 + " does not have permission to uri " + uri);
6296 }
6297 }
6298
6299 // Okay! So here we are: the caller has the assumed permission
6300 // to the uri, and the target doesn't. Let's now give this to
6301 // the target.
6302
6303 HashMap<Uri, UriPermission> targetUris
6304 = mGrantedUriPermissions.get(targetUid);
6305 if (targetUris == null) {
6306 targetUris = new HashMap<Uri, UriPermission>();
6307 mGrantedUriPermissions.put(targetUid, targetUris);
6308 }
6309
6310 UriPermission perm = targetUris.get(uri);
6311 if (perm == null) {
6312 perm = new UriPermission(targetUid, uri);
6313 targetUris.put(uri, perm);
6314
6315 }
6316 perm.modeFlags |= modeFlags;
6317 if (activity == null) {
6318 perm.globalModeFlags |= modeFlags;
6319 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6320 perm.readActivities.add(activity);
6321 if (activity.readUriPermissions == null) {
6322 activity.readUriPermissions = new HashSet<UriPermission>();
6323 }
6324 activity.readUriPermissions.add(perm);
6325 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6326 perm.writeActivities.add(activity);
6327 if (activity.writeUriPermissions == null) {
6328 activity.writeUriPermissions = new HashSet<UriPermission>();
6329 }
6330 activity.writeUriPermissions.add(perm);
6331 }
6332 }
6333
6334 private void grantUriPermissionFromIntentLocked(int callingUid,
6335 String targetPkg, Intent intent, HistoryRecord activity) {
6336 if (intent == null) {
6337 return;
6338 }
6339 Uri data = intent.getData();
6340 if (data == null) {
6341 return;
6342 }
6343 grantUriPermissionLocked(callingUid, targetPkg, data,
6344 intent.getFlags(), activity);
6345 }
6346
6347 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6348 Uri uri, int modeFlags) {
6349 synchronized(this) {
6350 final ProcessRecord r = getRecordForAppLocked(caller);
6351 if (r == null) {
6352 throw new SecurityException("Unable to find app for caller "
6353 + caller
6354 + " when granting permission to uri " + uri);
6355 }
6356 if (targetPkg == null) {
6357 Log.w(TAG, "grantUriPermission: null target");
6358 return;
6359 }
6360 if (uri == null) {
6361 Log.w(TAG, "grantUriPermission: null uri");
6362 return;
6363 }
6364
6365 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6366 null);
6367 }
6368 }
6369
6370 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6371 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6372 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6373 HashMap<Uri, UriPermission> perms
6374 = mGrantedUriPermissions.get(perm.uid);
6375 if (perms != null) {
6376 perms.remove(perm.uri);
6377 if (perms.size() == 0) {
6378 mGrantedUriPermissions.remove(perm.uid);
6379 }
6380 }
6381 }
6382 }
6383
6384 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6385 if (activity.readUriPermissions != null) {
6386 for (UriPermission perm : activity.readUriPermissions) {
6387 perm.readActivities.remove(activity);
6388 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6389 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6390 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6391 removeUriPermissionIfNeededLocked(perm);
6392 }
6393 }
6394 }
6395 if (activity.writeUriPermissions != null) {
6396 for (UriPermission perm : activity.writeUriPermissions) {
6397 perm.writeActivities.remove(activity);
6398 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6399 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6400 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6401 removeUriPermissionIfNeededLocked(perm);
6402 }
6403 }
6404 }
6405 }
6406
6407 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6408 int modeFlags) {
6409 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6410 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6411 if (modeFlags == 0) {
6412 return;
6413 }
6414
6415 final IPackageManager pm = ActivityThread.getPackageManager();
6416
6417 final String authority = uri.getAuthority();
6418 ProviderInfo pi = null;
6419 ContentProviderRecord cpr
6420 = (ContentProviderRecord)mProvidersByName.get(authority);
6421 if (cpr != null) {
6422 pi = cpr.info;
6423 } else {
6424 try {
6425 pi = pm.resolveContentProvider(authority,
6426 PackageManager.GET_URI_PERMISSION_PATTERNS);
6427 } catch (RemoteException ex) {
6428 }
6429 }
6430 if (pi == null) {
6431 Log.w(TAG, "No content provider found for: " + authority);
6432 return;
6433 }
6434
6435 // Does the caller have this permission on the URI?
6436 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6437 // Right now, if you are not the original owner of the permission,
6438 // you are not allowed to revoke it.
6439 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6440 throw new SecurityException("Uid " + callingUid
6441 + " does not have permission to uri " + uri);
6442 //}
6443 }
6444
6445 // Go through all of the permissions and remove any that match.
6446 final List<String> SEGMENTS = uri.getPathSegments();
6447 if (SEGMENTS != null) {
6448 final int NS = SEGMENTS.size();
6449 int N = mGrantedUriPermissions.size();
6450 for (int i=0; i<N; i++) {
6451 HashMap<Uri, UriPermission> perms
6452 = mGrantedUriPermissions.valueAt(i);
6453 Iterator<UriPermission> it = perms.values().iterator();
6454 toploop:
6455 while (it.hasNext()) {
6456 UriPermission perm = it.next();
6457 Uri targetUri = perm.uri;
6458 if (!authority.equals(targetUri.getAuthority())) {
6459 continue;
6460 }
6461 List<String> targetSegments = targetUri.getPathSegments();
6462 if (targetSegments == null) {
6463 continue;
6464 }
6465 if (targetSegments.size() < NS) {
6466 continue;
6467 }
6468 for (int j=0; j<NS; j++) {
6469 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6470 continue toploop;
6471 }
6472 }
6473 perm.clearModes(modeFlags);
6474 if (perm.modeFlags == 0) {
6475 it.remove();
6476 }
6477 }
6478 if (perms.size() == 0) {
6479 mGrantedUriPermissions.remove(
6480 mGrantedUriPermissions.keyAt(i));
6481 N--;
6482 i--;
6483 }
6484 }
6485 }
6486 }
6487
6488 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6489 int modeFlags) {
6490 synchronized(this) {
6491 final ProcessRecord r = getRecordForAppLocked(caller);
6492 if (r == null) {
6493 throw new SecurityException("Unable to find app for caller "
6494 + caller
6495 + " when revoking permission to uri " + uri);
6496 }
6497 if (uri == null) {
6498 Log.w(TAG, "revokeUriPermission: null uri");
6499 return;
6500 }
6501
6502 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6503 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6504 if (modeFlags == 0) {
6505 return;
6506 }
6507
6508 final IPackageManager pm = ActivityThread.getPackageManager();
6509
6510 final String authority = uri.getAuthority();
6511 ProviderInfo pi = null;
6512 ContentProviderRecord cpr
6513 = (ContentProviderRecord)mProvidersByName.get(authority);
6514 if (cpr != null) {
6515 pi = cpr.info;
6516 } else {
6517 try {
6518 pi = pm.resolveContentProvider(authority,
6519 PackageManager.GET_URI_PERMISSION_PATTERNS);
6520 } catch (RemoteException ex) {
6521 }
6522 }
6523 if (pi == null) {
6524 Log.w(TAG, "No content provider found for: " + authority);
6525 return;
6526 }
6527
6528 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6529 }
6530 }
6531
6532 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6533 synchronized (this) {
6534 ProcessRecord app =
6535 who != null ? getRecordForAppLocked(who) : null;
6536 if (app == null) return;
6537
6538 Message msg = Message.obtain();
6539 msg.what = WAIT_FOR_DEBUGGER_MSG;
6540 msg.obj = app;
6541 msg.arg1 = waiting ? 1 : 0;
6542 mHandler.sendMessage(msg);
6543 }
6544 }
6545
6546 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6547 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006548 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006549 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006550 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006551 }
6552
6553 // =========================================================
6554 // TASK MANAGEMENT
6555 // =========================================================
6556
6557 public List getTasks(int maxNum, int flags,
6558 IThumbnailReceiver receiver) {
6559 ArrayList list = new ArrayList();
6560
6561 PendingThumbnailsRecord pending = null;
6562 IApplicationThread topThumbnail = null;
6563 HistoryRecord topRecord = null;
6564
6565 synchronized(this) {
6566 if (localLOGV) Log.v(
6567 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6568 + ", receiver=" + receiver);
6569
6570 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6571 != PackageManager.PERMISSION_GRANTED) {
6572 if (receiver != null) {
6573 // If the caller wants to wait for pending thumbnails,
6574 // it ain't gonna get them.
6575 try {
6576 receiver.finished();
6577 } catch (RemoteException ex) {
6578 }
6579 }
6580 String msg = "Permission Denial: getTasks() from pid="
6581 + Binder.getCallingPid()
6582 + ", uid=" + Binder.getCallingUid()
6583 + " requires " + android.Manifest.permission.GET_TASKS;
6584 Log.w(TAG, msg);
6585 throw new SecurityException(msg);
6586 }
6587
6588 int pos = mHistory.size()-1;
6589 HistoryRecord next =
6590 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6591 HistoryRecord top = null;
6592 CharSequence topDescription = null;
6593 TaskRecord curTask = null;
6594 int numActivities = 0;
6595 int numRunning = 0;
6596 while (pos >= 0 && maxNum > 0) {
6597 final HistoryRecord r = next;
6598 pos--;
6599 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6600
6601 // Initialize state for next task if needed.
6602 if (top == null ||
6603 (top.state == ActivityState.INITIALIZING
6604 && top.task == r.task)) {
6605 top = r;
6606 topDescription = r.description;
6607 curTask = r.task;
6608 numActivities = numRunning = 0;
6609 }
6610
6611 // Add 'r' into the current task.
6612 numActivities++;
6613 if (r.app != null && r.app.thread != null) {
6614 numRunning++;
6615 }
6616 if (topDescription == null) {
6617 topDescription = r.description;
6618 }
6619
6620 if (localLOGV) Log.v(
6621 TAG, r.intent.getComponent().flattenToShortString()
6622 + ": task=" + r.task);
6623
6624 // If the next one is a different task, generate a new
6625 // TaskInfo entry for what we have.
6626 if (next == null || next.task != curTask) {
6627 ActivityManager.RunningTaskInfo ci
6628 = new ActivityManager.RunningTaskInfo();
6629 ci.id = curTask.taskId;
6630 ci.baseActivity = r.intent.getComponent();
6631 ci.topActivity = top.intent.getComponent();
6632 ci.thumbnail = top.thumbnail;
6633 ci.description = topDescription;
6634 ci.numActivities = numActivities;
6635 ci.numRunning = numRunning;
6636 //System.out.println(
6637 // "#" + maxNum + ": " + " descr=" + ci.description);
6638 if (ci.thumbnail == null && receiver != null) {
6639 if (localLOGV) Log.v(
6640 TAG, "State=" + top.state + "Idle=" + top.idle
6641 + " app=" + top.app
6642 + " thr=" + (top.app != null ? top.app.thread : null));
6643 if (top.state == ActivityState.RESUMED
6644 || top.state == ActivityState.PAUSING) {
6645 if (top.idle && top.app != null
6646 && top.app.thread != null) {
6647 topRecord = top;
6648 topThumbnail = top.app.thread;
6649 } else {
6650 top.thumbnailNeeded = true;
6651 }
6652 }
6653 if (pending == null) {
6654 pending = new PendingThumbnailsRecord(receiver);
6655 }
6656 pending.pendingRecords.add(top);
6657 }
6658 list.add(ci);
6659 maxNum--;
6660 top = null;
6661 }
6662 }
6663
6664 if (pending != null) {
6665 mPendingThumbnails.add(pending);
6666 }
6667 }
6668
6669 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6670
6671 if (topThumbnail != null) {
6672 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6673 try {
6674 topThumbnail.requestThumbnail(topRecord);
6675 } catch (Exception e) {
6676 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6677 sendPendingThumbnail(null, topRecord, null, null, true);
6678 }
6679 }
6680
6681 if (pending == null && receiver != null) {
6682 // In this case all thumbnails were available and the client
6683 // is being asked to be told when the remaining ones come in...
6684 // which is unusually, since the top-most currently running
6685 // activity should never have a canned thumbnail! Oh well.
6686 try {
6687 receiver.finished();
6688 } catch (RemoteException ex) {
6689 }
6690 }
6691
6692 return list;
6693 }
6694
6695 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6696 int flags) {
6697 synchronized (this) {
6698 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6699 "getRecentTasks()");
6700
6701 final int N = mRecentTasks.size();
6702 ArrayList<ActivityManager.RecentTaskInfo> res
6703 = new ArrayList<ActivityManager.RecentTaskInfo>(
6704 maxNum < N ? maxNum : N);
6705 for (int i=0; i<N && maxNum > 0; i++) {
6706 TaskRecord tr = mRecentTasks.get(i);
6707 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6708 || (tr.intent == null)
6709 || ((tr.intent.getFlags()
6710 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6711 ActivityManager.RecentTaskInfo rti
6712 = new ActivityManager.RecentTaskInfo();
6713 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6714 rti.baseIntent = new Intent(
6715 tr.intent != null ? tr.intent : tr.affinityIntent);
6716 rti.origActivity = tr.origActivity;
6717 res.add(rti);
6718 maxNum--;
6719 }
6720 }
6721 return res;
6722 }
6723 }
6724
6725 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6726 int j;
6727 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6728 TaskRecord jt = startTask;
6729
6730 // First look backwards
6731 for (j=startIndex-1; j>=0; j--) {
6732 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6733 if (r.task != jt) {
6734 jt = r.task;
6735 if (affinity.equals(jt.affinity)) {
6736 return j;
6737 }
6738 }
6739 }
6740
6741 // Now look forwards
6742 final int N = mHistory.size();
6743 jt = startTask;
6744 for (j=startIndex+1; j<N; j++) {
6745 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6746 if (r.task != jt) {
6747 if (affinity.equals(jt.affinity)) {
6748 return j;
6749 }
6750 jt = r.task;
6751 }
6752 }
6753
6754 // Might it be at the top?
6755 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6756 return N-1;
6757 }
6758
6759 return -1;
6760 }
6761
6762 /**
6763 * Perform a reset of the given task, if needed as part of launching it.
6764 * Returns the new HistoryRecord at the top of the task.
6765 */
6766 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6767 HistoryRecord newActivity) {
6768 boolean forceReset = (newActivity.info.flags
6769 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6770 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6771 if ((newActivity.info.flags
6772 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6773 forceReset = true;
6774 }
6775 }
6776
6777 final TaskRecord task = taskTop.task;
6778
6779 // We are going to move through the history list so that we can look
6780 // at each activity 'target' with 'below' either the interesting
6781 // activity immediately below it in the stack or null.
6782 HistoryRecord target = null;
6783 int targetI = 0;
6784 int taskTopI = -1;
6785 int replyChainEnd = -1;
6786 int lastReparentPos = -1;
6787 for (int i=mHistory.size()-1; i>=-1; i--) {
6788 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6789
6790 if (below != null && below.finishing) {
6791 continue;
6792 }
6793 if (target == null) {
6794 target = below;
6795 targetI = i;
6796 // If we were in the middle of a reply chain before this
6797 // task, it doesn't appear like the root of the chain wants
6798 // anything interesting, so drop it.
6799 replyChainEnd = -1;
6800 continue;
6801 }
6802
6803 final int flags = target.info.flags;
6804
6805 final boolean finishOnTaskLaunch =
6806 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6807 final boolean allowTaskReparenting =
6808 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6809
6810 if (target.task == task) {
6811 // We are inside of the task being reset... we'll either
6812 // finish this activity, push it out for another task,
6813 // or leave it as-is. We only do this
6814 // for activities that are not the root of the task (since
6815 // if we finish the root, we may no longer have the task!).
6816 if (taskTopI < 0) {
6817 taskTopI = targetI;
6818 }
6819 if (below != null && below.task == task) {
6820 final boolean clearWhenTaskReset =
6821 (target.intent.getFlags()
6822 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006823 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006824 // If this activity is sending a reply to a previous
6825 // activity, we can't do anything with it now until
6826 // we reach the start of the reply chain.
6827 // XXX note that we are assuming the result is always
6828 // to the previous activity, which is almost always
6829 // the case but we really shouldn't count on.
6830 if (replyChainEnd < 0) {
6831 replyChainEnd = targetI;
6832 }
Ed Heyl73798232009-03-24 21:32:21 -07006833 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006834 && target.taskAffinity != null
6835 && !target.taskAffinity.equals(task.affinity)) {
6836 // If this activity has an affinity for another
6837 // task, then we need to move it out of here. We will
6838 // move it as far out of the way as possible, to the
6839 // bottom of the activity stack. This also keeps it
6840 // correctly ordered with any activities we previously
6841 // moved.
6842 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6843 if (target.taskAffinity != null
6844 && target.taskAffinity.equals(p.task.affinity)) {
6845 // If the activity currently at the bottom has the
6846 // same task affinity as the one we are moving,
6847 // then merge it into the same task.
6848 target.task = p.task;
6849 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6850 + " out to bottom task " + p.task);
6851 } else {
6852 mCurTask++;
6853 if (mCurTask <= 0) {
6854 mCurTask = 1;
6855 }
6856 target.task = new TaskRecord(mCurTask, target.info, null,
6857 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6858 target.task.affinityIntent = target.intent;
6859 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6860 + " out to new task " + target.task);
6861 }
6862 mWindowManager.setAppGroupId(target, task.taskId);
6863 if (replyChainEnd < 0) {
6864 replyChainEnd = targetI;
6865 }
6866 int dstPos = 0;
6867 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6868 p = (HistoryRecord)mHistory.get(srcPos);
6869 if (p.finishing) {
6870 continue;
6871 }
6872 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6873 + " out to target's task " + target.task);
6874 task.numActivities--;
6875 p.task = target.task;
6876 target.task.numActivities++;
6877 mHistory.remove(srcPos);
6878 mHistory.add(dstPos, p);
6879 mWindowManager.moveAppToken(dstPos, p);
6880 mWindowManager.setAppGroupId(p, p.task.taskId);
6881 dstPos++;
6882 if (VALIDATE_TOKENS) {
6883 mWindowManager.validateAppTokens(mHistory);
6884 }
6885 i++;
6886 }
6887 if (taskTop == p) {
6888 taskTop = below;
6889 }
6890 if (taskTopI == replyChainEnd) {
6891 taskTopI = -1;
6892 }
6893 replyChainEnd = -1;
Josh Bartel7f208742010-02-25 11:01:44 -06006894 addRecentTaskLocked(target.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006895 } else if (forceReset || finishOnTaskLaunch
6896 || clearWhenTaskReset) {
6897 // If the activity should just be removed -- either
6898 // because it asks for it, or the task should be
6899 // cleared -- then finish it and anything that is
6900 // part of its reply chain.
6901 if (clearWhenTaskReset) {
6902 // In this case, we want to finish this activity
6903 // and everything above it, so be sneaky and pretend
6904 // like these are all in the reply chain.
6905 replyChainEnd = targetI+1;
6906 while (replyChainEnd < mHistory.size() &&
6907 ((HistoryRecord)mHistory.get(
6908 replyChainEnd)).task == task) {
6909 replyChainEnd++;
6910 }
6911 replyChainEnd--;
6912 } else if (replyChainEnd < 0) {
6913 replyChainEnd = targetI;
6914 }
6915 HistoryRecord p = null;
6916 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6917 p = (HistoryRecord)mHistory.get(srcPos);
6918 if (p.finishing) {
6919 continue;
6920 }
6921 if (finishActivityLocked(p, srcPos,
6922 Activity.RESULT_CANCELED, null, "reset")) {
6923 replyChainEnd--;
6924 srcPos--;
6925 }
6926 }
6927 if (taskTop == p) {
6928 taskTop = below;
6929 }
6930 if (taskTopI == replyChainEnd) {
6931 taskTopI = -1;
6932 }
6933 replyChainEnd = -1;
6934 } else {
6935 // If we were in the middle of a chain, well the
6936 // activity that started it all doesn't want anything
6937 // special, so leave it all as-is.
6938 replyChainEnd = -1;
6939 }
6940 } else {
6941 // Reached the bottom of the task -- any reply chain
6942 // should be left as-is.
6943 replyChainEnd = -1;
6944 }
6945
6946 } else if (target.resultTo != null) {
6947 // If this activity is sending a reply to a previous
6948 // activity, we can't do anything with it now until
6949 // we reach the start of the reply chain.
6950 // XXX note that we are assuming the result is always
6951 // to the previous activity, which is almost always
6952 // the case but we really shouldn't count on.
6953 if (replyChainEnd < 0) {
6954 replyChainEnd = targetI;
6955 }
6956
6957 } else if (taskTopI >= 0 && allowTaskReparenting
6958 && task.affinity != null
6959 && task.affinity.equals(target.taskAffinity)) {
6960 // We are inside of another task... if this activity has
6961 // an affinity for our task, then either remove it if we are
6962 // clearing or move it over to our task. Note that
6963 // we currently punt on the case where we are resetting a
6964 // task that is not at the top but who has activities above
6965 // with an affinity to it... this is really not a normal
6966 // case, and we will need to later pull that task to the front
6967 // and usually at that point we will do the reset and pick
6968 // up those remaining activities. (This only happens if
6969 // someone starts an activity in a new task from an activity
6970 // in a task that is not currently on top.)
6971 if (forceReset || finishOnTaskLaunch) {
6972 if (replyChainEnd < 0) {
6973 replyChainEnd = targetI;
6974 }
6975 HistoryRecord p = null;
6976 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6977 p = (HistoryRecord)mHistory.get(srcPos);
6978 if (p.finishing) {
6979 continue;
6980 }
6981 if (finishActivityLocked(p, srcPos,
6982 Activity.RESULT_CANCELED, null, "reset")) {
6983 taskTopI--;
6984 lastReparentPos--;
6985 replyChainEnd--;
6986 srcPos--;
6987 }
6988 }
6989 replyChainEnd = -1;
6990 } else {
6991 if (replyChainEnd < 0) {
6992 replyChainEnd = targetI;
6993 }
6994 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6995 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6996 if (p.finishing) {
6997 continue;
6998 }
6999 if (lastReparentPos < 0) {
7000 lastReparentPos = taskTopI;
7001 taskTop = p;
7002 } else {
7003 lastReparentPos--;
7004 }
7005 mHistory.remove(srcPos);
7006 p.task.numActivities--;
7007 p.task = task;
7008 mHistory.add(lastReparentPos, p);
7009 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
7010 + " in to resetting task " + task);
7011 task.numActivities++;
7012 mWindowManager.moveAppToken(lastReparentPos, p);
7013 mWindowManager.setAppGroupId(p, p.task.taskId);
7014 if (VALIDATE_TOKENS) {
7015 mWindowManager.validateAppTokens(mHistory);
7016 }
7017 }
7018 replyChainEnd = -1;
7019
7020 // Now we've moved it in to place... but what if this is
7021 // a singleTop activity and we have put it on top of another
7022 // instance of the same activity? Then we drop the instance
7023 // below so it remains singleTop.
7024 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
7025 for (int j=lastReparentPos-1; j>=0; j--) {
7026 HistoryRecord p = (HistoryRecord)mHistory.get(j);
7027 if (p.finishing) {
7028 continue;
7029 }
7030 if (p.intent.getComponent().equals(target.intent.getComponent())) {
7031 if (finishActivityLocked(p, j,
7032 Activity.RESULT_CANCELED, null, "replace")) {
7033 taskTopI--;
7034 lastReparentPos--;
7035 }
7036 }
7037 }
7038 }
7039 }
7040 }
7041
7042 target = below;
7043 targetI = i;
7044 }
7045
7046 return taskTop;
7047 }
7048
7049 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007050 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007051 */
7052 public void moveTaskToFront(int task) {
7053 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7054 "moveTaskToFront()");
7055
7056 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007057 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7058 Binder.getCallingUid(), "Task to front")) {
7059 return;
7060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007061 final long origId = Binder.clearCallingIdentity();
7062 try {
7063 int N = mRecentTasks.size();
7064 for (int i=0; i<N; i++) {
7065 TaskRecord tr = mRecentTasks.get(i);
7066 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007067 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007068 return;
7069 }
7070 }
7071 for (int i=mHistory.size()-1; i>=0; i--) {
7072 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7073 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007074 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007075 return;
7076 }
7077 }
7078 } finally {
7079 Binder.restoreCallingIdentity(origId);
7080 }
7081 }
7082 }
7083
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007084 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007085 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7086
7087 final int task = tr.taskId;
7088 int top = mHistory.size()-1;
7089
7090 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7091 // nothing to do!
7092 return;
7093 }
7094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007095 ArrayList moved = new ArrayList();
7096
7097 // Applying the affinities may have removed entries from the history,
7098 // so get the size again.
7099 top = mHistory.size()-1;
7100 int pos = top;
7101
7102 // Shift all activities with this task up to the top
7103 // of the stack, keeping them in the same internal order.
7104 while (pos >= 0) {
7105 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7106 if (localLOGV) Log.v(
7107 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7108 boolean first = true;
7109 if (r.task.taskId == task) {
7110 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7111 mHistory.remove(pos);
7112 mHistory.add(top, r);
7113 moved.add(0, r);
7114 top--;
7115 if (first) {
Josh Bartel7f208742010-02-25 11:01:44 -06007116 addRecentTaskLocked(r.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007117 first = false;
7118 }
7119 }
7120 pos--;
7121 }
7122
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007123 if (DEBUG_TRANSITION) Log.v(TAG,
7124 "Prepare to front transition: task=" + tr);
7125 if (reason != null &&
7126 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7127 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7128 HistoryRecord r = topRunningActivityLocked(null);
7129 if (r != null) {
7130 mNoAnimActivities.add(r);
7131 }
7132 } else {
7133 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7134 }
7135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007136 mWindowManager.moveAppTokensToTop(moved);
7137 if (VALIDATE_TOKENS) {
7138 mWindowManager.validateAppTokens(mHistory);
7139 }
7140
Josh Bartel7f208742010-02-25 11:01:44 -06007141 finishTaskMoveLocked(task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007142 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7143 }
7144
Josh Bartel7f208742010-02-25 11:01:44 -06007145 private final void finishTaskMoveLocked(int task) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007146 resumeTopActivityLocked(null);
7147 }
7148
7149 public void moveTaskToBack(int task) {
7150 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7151 "moveTaskToBack()");
7152
7153 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007154 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7155 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7156 Binder.getCallingUid(), "Task to back")) {
7157 return;
7158 }
7159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007160 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007161 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007162 Binder.restoreCallingIdentity(origId);
7163 }
7164 }
7165
7166 /**
7167 * Moves an activity, and all of the other activities within the same task, to the bottom
7168 * of the history stack. The activity's order within the task is unchanged.
7169 *
7170 * @param token A reference to the activity we wish to move
7171 * @param nonRoot If false then this only works if the activity is the root
7172 * of a task; if true it will work for any activity in a task.
7173 * @return Returns true if the move completed, false if not.
7174 */
7175 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7176 synchronized(this) {
7177 final long origId = Binder.clearCallingIdentity();
7178 int taskId = getTaskForActivityLocked(token, !nonRoot);
7179 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007180 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007181 }
7182 Binder.restoreCallingIdentity(origId);
7183 }
7184 return false;
7185 }
7186
7187 /**
7188 * Worker method for rearranging history stack. Implements the function of moving all
7189 * activities for a specific task (gathering them if disjoint) into a single group at the
7190 * bottom of the stack.
7191 *
7192 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7193 * to premeptively cancel the move.
7194 *
7195 * @param task The taskId to collect and move to the bottom.
7196 * @return Returns true if the move completed, false if not.
7197 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007198 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007199 Log.i(TAG, "moveTaskToBack: " + task);
7200
7201 // If we have a watcher, preflight the move before committing to it. First check
7202 // for *other* available tasks, but if none are available, then try again allowing the
7203 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007204 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007205 HistoryRecord next = topRunningActivityLocked(null, task);
7206 if (next == null) {
7207 next = topRunningActivityLocked(null, 0);
7208 }
7209 if (next != null) {
7210 // ask watcher if this is allowed
7211 boolean moveOK = true;
7212 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007213 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007214 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007215 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007216 }
7217 if (!moveOK) {
7218 return false;
7219 }
7220 }
7221 }
7222
7223 ArrayList moved = new ArrayList();
7224
7225 if (DEBUG_TRANSITION) Log.v(TAG,
7226 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007227
7228 final int N = mHistory.size();
7229 int bottom = 0;
7230 int pos = 0;
7231
7232 // Shift all activities with this task down to the bottom
7233 // of the stack, keeping them in the same internal order.
7234 while (pos < N) {
7235 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7236 if (localLOGV) Log.v(
7237 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7238 if (r.task.taskId == task) {
7239 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7240 mHistory.remove(pos);
7241 mHistory.add(bottom, r);
7242 moved.add(r);
7243 bottom++;
7244 }
7245 pos++;
7246 }
7247
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007248 if (reason != null &&
7249 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7250 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7251 HistoryRecord r = topRunningActivityLocked(null);
7252 if (r != null) {
7253 mNoAnimActivities.add(r);
7254 }
7255 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007256 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007258 mWindowManager.moveAppTokensToBottom(moved);
7259 if (VALIDATE_TOKENS) {
7260 mWindowManager.validateAppTokens(mHistory);
7261 }
7262
Josh Bartel7f208742010-02-25 11:01:44 -06007263 finishTaskMoveLocked(task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007264 return true;
7265 }
7266
7267 public void moveTaskBackwards(int task) {
7268 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7269 "moveTaskBackwards()");
7270
7271 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007272 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7273 Binder.getCallingUid(), "Task backwards")) {
7274 return;
7275 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007276 final long origId = Binder.clearCallingIdentity();
7277 moveTaskBackwardsLocked(task);
7278 Binder.restoreCallingIdentity(origId);
7279 }
7280 }
7281
7282 private final void moveTaskBackwardsLocked(int task) {
7283 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7284 }
7285
7286 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7287 synchronized(this) {
7288 return getTaskForActivityLocked(token, onlyRoot);
7289 }
7290 }
7291
7292 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7293 final int N = mHistory.size();
7294 TaskRecord lastTask = null;
7295 for (int i=0; i<N; i++) {
7296 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7297 if (r == token) {
7298 if (!onlyRoot || lastTask != r.task) {
7299 return r.task.taskId;
7300 }
7301 return -1;
7302 }
7303 lastTask = r.task;
7304 }
7305
7306 return -1;
7307 }
7308
7309 /**
7310 * Returns the top activity in any existing task matching the given
7311 * Intent. Returns null if no such task is found.
7312 */
7313 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7314 ComponentName cls = intent.getComponent();
7315 if (info.targetActivity != null) {
7316 cls = new ComponentName(info.packageName, info.targetActivity);
7317 }
7318
7319 TaskRecord cp = null;
7320
7321 final int N = mHistory.size();
7322 for (int i=(N-1); i>=0; i--) {
7323 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7324 if (!r.finishing && r.task != cp
7325 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7326 cp = r.task;
7327 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7328 // + "/aff=" + r.task.affinity + " to new cls="
7329 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7330 if (r.task.affinity != null) {
7331 if (r.task.affinity.equals(info.taskAffinity)) {
7332 //Log.i(TAG, "Found matching affinity!");
7333 return r;
7334 }
7335 } else if (r.task.intent != null
7336 && r.task.intent.getComponent().equals(cls)) {
7337 //Log.i(TAG, "Found matching class!");
7338 //dump();
7339 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7340 return r;
7341 } else if (r.task.affinityIntent != null
7342 && r.task.affinityIntent.getComponent().equals(cls)) {
7343 //Log.i(TAG, "Found matching class!");
7344 //dump();
7345 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7346 return r;
7347 }
7348 }
7349 }
7350
7351 return null;
7352 }
7353
7354 /**
7355 * Returns the first activity (starting from the top of the stack) that
7356 * is the same as the given activity. Returns null if no such activity
7357 * is found.
7358 */
7359 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7360 ComponentName cls = intent.getComponent();
7361 if (info.targetActivity != null) {
7362 cls = new ComponentName(info.packageName, info.targetActivity);
7363 }
7364
7365 final int N = mHistory.size();
7366 for (int i=(N-1); i>=0; i--) {
7367 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7368 if (!r.finishing) {
7369 if (r.intent.getComponent().equals(cls)) {
7370 //Log.i(TAG, "Found matching class!");
7371 //dump();
7372 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7373 return r;
7374 }
7375 }
7376 }
7377
7378 return null;
7379 }
7380
7381 public void finishOtherInstances(IBinder token, ComponentName className) {
7382 synchronized(this) {
7383 final long origId = Binder.clearCallingIdentity();
7384
7385 int N = mHistory.size();
7386 TaskRecord lastTask = null;
7387 for (int i=0; i<N; i++) {
7388 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7389 if (r.realActivity.equals(className)
7390 && r != token && lastTask != r.task) {
7391 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7392 null, "others")) {
7393 i--;
7394 N--;
7395 }
7396 }
7397 lastTask = r.task;
7398 }
7399
7400 Binder.restoreCallingIdentity(origId);
7401 }
7402 }
7403
7404 // =========================================================
7405 // THUMBNAILS
7406 // =========================================================
7407
7408 public void reportThumbnail(IBinder token,
7409 Bitmap thumbnail, CharSequence description) {
7410 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7411 final long origId = Binder.clearCallingIdentity();
7412 sendPendingThumbnail(null, token, thumbnail, description, true);
7413 Binder.restoreCallingIdentity(origId);
7414 }
7415
7416 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7417 Bitmap thumbnail, CharSequence description, boolean always) {
7418 TaskRecord task = null;
7419 ArrayList receivers = null;
7420
7421 //System.out.println("Send pending thumbnail: " + r);
7422
7423 synchronized(this) {
7424 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007425 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007426 if (index < 0) {
7427 return;
7428 }
7429 r = (HistoryRecord)mHistory.get(index);
7430 }
7431 if (thumbnail == null) {
7432 thumbnail = r.thumbnail;
7433 description = r.description;
7434 }
7435 if (thumbnail == null && !always) {
7436 // If there is no thumbnail, and this entry is not actually
7437 // going away, then abort for now and pick up the next
7438 // thumbnail we get.
7439 return;
7440 }
7441 task = r.task;
7442
7443 int N = mPendingThumbnails.size();
7444 int i=0;
7445 while (i<N) {
7446 PendingThumbnailsRecord pr =
7447 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7448 //System.out.println("Looking in " + pr.pendingRecords);
7449 if (pr.pendingRecords.remove(r)) {
7450 if (receivers == null) {
7451 receivers = new ArrayList();
7452 }
7453 receivers.add(pr);
7454 if (pr.pendingRecords.size() == 0) {
7455 pr.finished = true;
7456 mPendingThumbnails.remove(i);
7457 N--;
7458 continue;
7459 }
7460 }
7461 i++;
7462 }
7463 }
7464
7465 if (receivers != null) {
7466 final int N = receivers.size();
7467 for (int i=0; i<N; i++) {
7468 try {
7469 PendingThumbnailsRecord pr =
7470 (PendingThumbnailsRecord)receivers.get(i);
7471 pr.receiver.newThumbnail(
7472 task != null ? task.taskId : -1, thumbnail, description);
7473 if (pr.finished) {
7474 pr.receiver.finished();
7475 }
7476 } catch (Exception e) {
7477 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7478 }
7479 }
7480 }
7481 }
7482
7483 // =========================================================
7484 // CONTENT PROVIDERS
7485 // =========================================================
7486
7487 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7488 List providers = null;
7489 try {
7490 providers = ActivityThread.getPackageManager().
7491 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007492 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007493 } catch (RemoteException ex) {
7494 }
7495 if (providers != null) {
7496 final int N = providers.size();
7497 for (int i=0; i<N; i++) {
7498 ProviderInfo cpi =
7499 (ProviderInfo)providers.get(i);
7500 ContentProviderRecord cpr =
7501 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7502 if (cpr == null) {
7503 cpr = new ContentProviderRecord(cpi, app.info);
7504 mProvidersByClass.put(cpi.name, cpr);
7505 }
7506 app.pubProviders.put(cpi.name, cpr);
7507 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007508 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007509 }
7510 }
7511 return providers;
7512 }
7513
7514 private final String checkContentProviderPermissionLocked(
7515 ProviderInfo cpi, ProcessRecord r, int mode) {
7516 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7517 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7518 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7519 cpi.exported ? -1 : cpi.applicationInfo.uid)
7520 == PackageManager.PERMISSION_GRANTED
7521 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7522 return null;
7523 }
7524 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7525 cpi.exported ? -1 : cpi.applicationInfo.uid)
7526 == PackageManager.PERMISSION_GRANTED) {
7527 return null;
7528 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007529
7530 PathPermission[] pps = cpi.pathPermissions;
7531 if (pps != null) {
7532 int i = pps.length;
7533 while (i > 0) {
7534 i--;
7535 PathPermission pp = pps[i];
7536 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7537 cpi.exported ? -1 : cpi.applicationInfo.uid)
7538 == PackageManager.PERMISSION_GRANTED
7539 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7540 return null;
7541 }
7542 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7543 cpi.exported ? -1 : cpi.applicationInfo.uid)
7544 == PackageManager.PERMISSION_GRANTED) {
7545 return null;
7546 }
7547 }
7548 }
7549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007550 String msg = "Permission Denial: opening provider " + cpi.name
7551 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7552 + ", uid=" + callingUid + ") requires "
7553 + cpi.readPermission + " or " + cpi.writePermission;
7554 Log.w(TAG, msg);
7555 return msg;
7556 }
7557
7558 private final ContentProviderHolder getContentProviderImpl(
7559 IApplicationThread caller, String name) {
7560 ContentProviderRecord cpr;
7561 ProviderInfo cpi = null;
7562
7563 synchronized(this) {
7564 ProcessRecord r = null;
7565 if (caller != null) {
7566 r = getRecordForAppLocked(caller);
7567 if (r == null) {
7568 throw new SecurityException(
7569 "Unable to find app for caller " + caller
7570 + " (pid=" + Binder.getCallingPid()
7571 + ") when getting content provider " + name);
7572 }
7573 }
7574
7575 // First check if this content provider has been published...
7576 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7577 if (cpr != null) {
7578 cpi = cpr.info;
7579 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7580 return new ContentProviderHolder(cpi,
7581 cpi.readPermission != null
7582 ? cpi.readPermission : cpi.writePermission);
7583 }
7584
7585 if (r != null && cpr.canRunHere(r)) {
7586 // This provider has been published or is in the process
7587 // of being published... but it is also allowed to run
7588 // in the caller's process, so don't make a connection
7589 // and just let the caller instantiate its own instance.
7590 if (cpr.provider != null) {
7591 // don't give caller the provider object, it needs
7592 // to make its own.
7593 cpr = new ContentProviderRecord(cpr);
7594 }
7595 return cpr;
7596 }
7597
7598 final long origId = Binder.clearCallingIdentity();
7599
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007600 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007601 // return it right away.
7602 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007603 if (DEBUG_PROVIDER) Log.v(TAG,
7604 "Adding provider requested by "
7605 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007606 + cpr.info.processName);
7607 Integer cnt = r.conProviders.get(cpr);
7608 if (cnt == null) {
7609 r.conProviders.put(cpr, new Integer(1));
7610 } else {
7611 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007613 cpr.clients.add(r);
7614 } else {
7615 cpr.externals++;
7616 }
7617
7618 if (cpr.app != null) {
7619 updateOomAdjLocked(cpr.app);
7620 }
7621
7622 Binder.restoreCallingIdentity(origId);
7623
7624 } else {
7625 try {
7626 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007627 resolveContentProvider(name,
7628 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007629 } catch (RemoteException ex) {
7630 }
7631 if (cpi == null) {
7632 return null;
7633 }
7634
7635 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7636 return new ContentProviderHolder(cpi,
7637 cpi.readPermission != null
7638 ? cpi.readPermission : cpi.writePermission);
7639 }
7640
7641 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7642 final boolean firstClass = cpr == null;
7643 if (firstClass) {
7644 try {
7645 ApplicationInfo ai =
7646 ActivityThread.getPackageManager().
7647 getApplicationInfo(
7648 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007649 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007650 if (ai == null) {
7651 Log.w(TAG, "No package info for content provider "
7652 + cpi.name);
7653 return null;
7654 }
7655 cpr = new ContentProviderRecord(cpi, ai);
7656 } catch (RemoteException ex) {
7657 // pm is in same process, this will never happen.
7658 }
7659 }
7660
7661 if (r != null && cpr.canRunHere(r)) {
7662 // If this is a multiprocess provider, then just return its
7663 // info and allow the caller to instantiate it. Only do
7664 // this if the provider is the same user as the caller's
7665 // process, or can run as root (so can be in any process).
7666 return cpr;
7667 }
7668
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007669 if (DEBUG_PROVIDER) {
7670 RuntimeException e = new RuntimeException("here");
7671 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7672 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007673 }
7674
7675 // This is single process, and our app is now connecting to it.
7676 // See if we are already in the process of launching this
7677 // provider.
7678 final int N = mLaunchingProviders.size();
7679 int i;
7680 for (i=0; i<N; i++) {
7681 if (mLaunchingProviders.get(i) == cpr) {
7682 break;
7683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007684 }
7685
7686 // If the provider is not already being launched, then get it
7687 // started.
7688 if (i >= N) {
7689 final long origId = Binder.clearCallingIdentity();
7690 ProcessRecord proc = startProcessLocked(cpi.processName,
7691 cpr.appInfo, false, 0, "content provider",
7692 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007693 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007694 if (proc == null) {
7695 Log.w(TAG, "Unable to launch app "
7696 + cpi.applicationInfo.packageName + "/"
7697 + cpi.applicationInfo.uid + " for provider "
7698 + name + ": process is bad");
7699 return null;
7700 }
7701 cpr.launchingApp = proc;
7702 mLaunchingProviders.add(cpr);
7703 Binder.restoreCallingIdentity(origId);
7704 }
7705
7706 // Make sure the provider is published (the same provider class
7707 // may be published under multiple names).
7708 if (firstClass) {
7709 mProvidersByClass.put(cpi.name, cpr);
7710 }
7711 mProvidersByName.put(name, cpr);
7712
7713 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007714 if (DEBUG_PROVIDER) Log.v(TAG,
7715 "Adding provider requested by "
7716 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007717 + cpr.info.processName);
7718 Integer cnt = r.conProviders.get(cpr);
7719 if (cnt == null) {
7720 r.conProviders.put(cpr, new Integer(1));
7721 } else {
7722 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007724 cpr.clients.add(r);
7725 } else {
7726 cpr.externals++;
7727 }
7728 }
7729 }
7730
7731 // Wait for the provider to be published...
7732 synchronized (cpr) {
7733 while (cpr.provider == null) {
7734 if (cpr.launchingApp == null) {
7735 Log.w(TAG, "Unable to launch app "
7736 + cpi.applicationInfo.packageName + "/"
7737 + cpi.applicationInfo.uid + " for provider "
7738 + name + ": launching app became null");
7739 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7740 cpi.applicationInfo.packageName,
7741 cpi.applicationInfo.uid, name);
7742 return null;
7743 }
7744 try {
7745 cpr.wait();
7746 } catch (InterruptedException ex) {
7747 }
7748 }
7749 }
7750 return cpr;
7751 }
7752
7753 public final ContentProviderHolder getContentProvider(
7754 IApplicationThread caller, String name) {
7755 if (caller == null) {
7756 String msg = "null IApplicationThread when getting content provider "
7757 + name;
7758 Log.w(TAG, msg);
7759 throw new SecurityException(msg);
7760 }
7761
7762 return getContentProviderImpl(caller, name);
7763 }
7764
7765 private ContentProviderHolder getContentProviderExternal(String name) {
7766 return getContentProviderImpl(null, name);
7767 }
7768
7769 /**
7770 * Drop a content provider from a ProcessRecord's bookkeeping
7771 * @param cpr
7772 */
7773 public void removeContentProvider(IApplicationThread caller, String name) {
7774 synchronized (this) {
7775 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7776 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007777 // remove from mProvidersByClass
7778 if (DEBUG_PROVIDER) Log.v(TAG, name +
7779 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007780 return;
7781 }
7782 final ProcessRecord r = getRecordForAppLocked(caller);
7783 if (r == null) {
7784 throw new SecurityException(
7785 "Unable to find app for caller " + caller +
7786 " when removing content provider " + name);
7787 }
7788 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007789 ContentProviderRecord localCpr = (ContentProviderRecord)
7790 mProvidersByClass.get(cpr.info.name);
7791 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7792 + r.info.processName + " from process "
7793 + localCpr.appInfo.processName);
7794 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007795 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007796 Log.w(TAG, "removeContentProvider called on local provider: "
7797 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007798 return;
7799 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007800 Integer cnt = r.conProviders.get(localCpr);
7801 if (cnt == null || cnt.intValue() <= 1) {
7802 localCpr.clients.remove(r);
7803 r.conProviders.remove(localCpr);
7804 } else {
7805 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7806 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007807 }
7808 updateOomAdjLocked();
7809 }
7810 }
7811
7812 private void removeContentProviderExternal(String name) {
7813 synchronized (this) {
7814 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7815 if(cpr == null) {
7816 //remove from mProvidersByClass
7817 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7818 return;
7819 }
7820
7821 //update content provider record entry info
7822 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7823 localCpr.externals--;
7824 if (localCpr.externals < 0) {
7825 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7826 }
7827 updateOomAdjLocked();
7828 }
7829 }
7830
7831 public final void publishContentProviders(IApplicationThread caller,
7832 List<ContentProviderHolder> providers) {
7833 if (providers == null) {
7834 return;
7835 }
7836
7837 synchronized(this) {
7838 final ProcessRecord r = getRecordForAppLocked(caller);
7839 if (r == null) {
7840 throw new SecurityException(
7841 "Unable to find app for caller " + caller
7842 + " (pid=" + Binder.getCallingPid()
7843 + ") when publishing content providers");
7844 }
7845
7846 final long origId = Binder.clearCallingIdentity();
7847
7848 final int N = providers.size();
7849 for (int i=0; i<N; i++) {
7850 ContentProviderHolder src = providers.get(i);
7851 if (src == null || src.info == null || src.provider == null) {
7852 continue;
7853 }
7854 ContentProviderRecord dst =
7855 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7856 if (dst != null) {
7857 mProvidersByClass.put(dst.info.name, dst);
7858 String names[] = dst.info.authority.split(";");
7859 for (int j = 0; j < names.length; j++) {
7860 mProvidersByName.put(names[j], dst);
7861 }
7862
7863 int NL = mLaunchingProviders.size();
7864 int j;
7865 for (j=0; j<NL; j++) {
7866 if (mLaunchingProviders.get(j) == dst) {
7867 mLaunchingProviders.remove(j);
7868 j--;
7869 NL--;
7870 }
7871 }
7872 synchronized (dst) {
7873 dst.provider = src.provider;
7874 dst.app = r;
7875 dst.notifyAll();
7876 }
7877 updateOomAdjLocked(r);
7878 }
7879 }
7880
7881 Binder.restoreCallingIdentity(origId);
7882 }
7883 }
7884
7885 public static final void installSystemProviders() {
Josh Bartel2ecce342010-02-25 10:55:48 -06007886 List providers = null;
7887 synchronized (mSelf) {
7888 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7889 providers = mSelf.generateApplicationProvidersLocked(app);
7890 }
7891 if (providers != null) {
7892 mSystemThread.installSystemProviders(providers);
7893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007894 }
7895
7896 // =========================================================
7897 // GLOBAL MANAGEMENT
7898 // =========================================================
7899
7900 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7901 ApplicationInfo info, String customProcess) {
7902 String proc = customProcess != null ? customProcess : info.processName;
7903 BatteryStatsImpl.Uid.Proc ps = null;
7904 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7905 synchronized (stats) {
7906 ps = stats.getProcessStatsLocked(info.uid, proc);
7907 }
7908 return new ProcessRecord(ps, thread, info, proc);
7909 }
7910
7911 final ProcessRecord addAppLocked(ApplicationInfo info) {
7912 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7913
7914 if (app == null) {
7915 app = newProcessRecordLocked(null, info, null);
7916 mProcessNames.put(info.processName, info.uid, app);
7917 updateLRUListLocked(app, true);
7918 }
7919
7920 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7921 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7922 app.persistent = true;
7923 app.maxAdj = CORE_SERVER_ADJ;
7924 }
7925 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7926 mPersistentStartingProcesses.add(app);
7927 startProcessLocked(app, "added application", app.processName);
7928 }
7929
7930 return app;
7931 }
7932
7933 public void unhandledBack() {
7934 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7935 "unhandledBack()");
7936
7937 synchronized(this) {
7938 int count = mHistory.size();
7939 if (Config.LOGD) Log.d(
7940 TAG, "Performing unhandledBack(): stack size = " + count);
7941 if (count > 1) {
7942 final long origId = Binder.clearCallingIdentity();
7943 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7944 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7945 Binder.restoreCallingIdentity(origId);
7946 }
7947 }
7948 }
7949
7950 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7951 String name = uri.getAuthority();
7952 ContentProviderHolder cph = getContentProviderExternal(name);
7953 ParcelFileDescriptor pfd = null;
7954 if (cph != null) {
7955 // We record the binder invoker's uid in thread-local storage before
7956 // going to the content provider to open the file. Later, in the code
7957 // that handles all permissions checks, we look for this uid and use
7958 // that rather than the Activity Manager's own uid. The effect is that
7959 // we do the check against the caller's permissions even though it looks
7960 // to the content provider like the Activity Manager itself is making
7961 // the request.
7962 sCallerIdentity.set(new Identity(
7963 Binder.getCallingPid(), Binder.getCallingUid()));
7964 try {
7965 pfd = cph.provider.openFile(uri, "r");
7966 } catch (FileNotFoundException e) {
7967 // do nothing; pfd will be returned null
7968 } finally {
7969 // Ensure that whatever happens, we clean up the identity state
7970 sCallerIdentity.remove();
7971 }
7972
7973 // We've got the fd now, so we're done with the provider.
7974 removeContentProviderExternal(name);
7975 } else {
7976 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7977 }
7978 return pfd;
7979 }
7980
7981 public void goingToSleep() {
7982 synchronized(this) {
7983 mSleeping = true;
7984 mWindowManager.setEventDispatching(false);
7985
7986 if (mResumedActivity != null) {
7987 pauseIfSleepingLocked();
7988 } else {
7989 Log.w(TAG, "goingToSleep with no resumed activity!");
7990 }
7991 }
7992 }
7993
Dianne Hackborn55280a92009-05-07 15:53:46 -07007994 public boolean shutdown(int timeout) {
7995 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7996 != PackageManager.PERMISSION_GRANTED) {
7997 throw new SecurityException("Requires permission "
7998 + android.Manifest.permission.SHUTDOWN);
7999 }
8000
8001 boolean timedout = false;
8002
8003 synchronized(this) {
8004 mShuttingDown = true;
8005 mWindowManager.setEventDispatching(false);
8006
8007 if (mResumedActivity != null) {
8008 pauseIfSleepingLocked();
8009 final long endTime = System.currentTimeMillis() + timeout;
8010 while (mResumedActivity != null || mPausingActivity != null) {
8011 long delay = endTime - System.currentTimeMillis();
8012 if (delay <= 0) {
8013 Log.w(TAG, "Activity manager shutdown timed out");
8014 timedout = true;
8015 break;
8016 }
8017 try {
8018 this.wait();
8019 } catch (InterruptedException e) {
8020 }
8021 }
8022 }
8023 }
8024
8025 mUsageStatsService.shutdown();
8026 mBatteryStatsService.shutdown();
8027
8028 return timedout;
8029 }
8030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008031 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07008032 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008033 if (!mGoingToSleep.isHeld()) {
8034 mGoingToSleep.acquire();
8035 if (mLaunchingActivity.isHeld()) {
8036 mLaunchingActivity.release();
8037 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
8038 }
8039 }
8040
8041 // If we are not currently pausing an activity, get the current
8042 // one to pause. If we are pausing one, we will just let that stuff
8043 // run and release the wake lock when all done.
8044 if (mPausingActivity == null) {
8045 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8046 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8047 startPausingLocked(false, true);
8048 }
8049 }
8050 }
8051
8052 public void wakingUp() {
8053 synchronized(this) {
8054 if (mGoingToSleep.isHeld()) {
8055 mGoingToSleep.release();
8056 }
8057 mWindowManager.setEventDispatching(true);
8058 mSleeping = false;
8059 resumeTopActivityLocked(null);
8060 }
8061 }
8062
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008063 public void stopAppSwitches() {
8064 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8065 != PackageManager.PERMISSION_GRANTED) {
8066 throw new SecurityException("Requires permission "
8067 + android.Manifest.permission.STOP_APP_SWITCHES);
8068 }
8069
8070 synchronized(this) {
8071 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8072 + APP_SWITCH_DELAY_TIME;
8073 mDidAppSwitch = false;
8074 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8075 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8076 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8077 }
8078 }
8079
8080 public void resumeAppSwitches() {
8081 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8082 != PackageManager.PERMISSION_GRANTED) {
8083 throw new SecurityException("Requires permission "
8084 + android.Manifest.permission.STOP_APP_SWITCHES);
8085 }
8086
8087 synchronized(this) {
8088 // Note that we don't execute any pending app switches... we will
8089 // let those wait until either the timeout, or the next start
8090 // activity request.
8091 mAppSwitchesAllowedTime = 0;
8092 }
8093 }
8094
8095 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8096 String name) {
8097 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8098 return true;
8099 }
8100
8101 final int perm = checkComponentPermission(
8102 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8103 callingUid, -1);
8104 if (perm == PackageManager.PERMISSION_GRANTED) {
8105 return true;
8106 }
8107
8108 Log.w(TAG, name + " request from " + callingUid + " stopped");
8109 return false;
8110 }
8111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008112 public void setDebugApp(String packageName, boolean waitForDebugger,
8113 boolean persistent) {
8114 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8115 "setDebugApp()");
8116
8117 // Note that this is not really thread safe if there are multiple
8118 // callers into it at the same time, but that's not a situation we
8119 // care about.
8120 if (persistent) {
8121 final ContentResolver resolver = mContext.getContentResolver();
8122 Settings.System.putString(
8123 resolver, Settings.System.DEBUG_APP,
8124 packageName);
8125 Settings.System.putInt(
8126 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8127 waitForDebugger ? 1 : 0);
8128 }
8129
8130 synchronized (this) {
8131 if (!persistent) {
8132 mOrigDebugApp = mDebugApp;
8133 mOrigWaitForDebugger = mWaitForDebugger;
8134 }
8135 mDebugApp = packageName;
8136 mWaitForDebugger = waitForDebugger;
8137 mDebugTransient = !persistent;
8138 if (packageName != null) {
8139 final long origId = Binder.clearCallingIdentity();
8140 uninstallPackageLocked(packageName, -1, false);
8141 Binder.restoreCallingIdentity(origId);
8142 }
8143 }
8144 }
8145
8146 public void setAlwaysFinish(boolean enabled) {
8147 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8148 "setAlwaysFinish()");
8149
8150 Settings.System.putInt(
8151 mContext.getContentResolver(),
8152 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8153
8154 synchronized (this) {
8155 mAlwaysFinishActivities = enabled;
8156 }
8157 }
8158
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008159 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008160 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008161 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008162 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008163 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008164 }
8165 }
8166
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008167 public void registerActivityWatcher(IActivityWatcher watcher) {
Josh Bartel2ecce342010-02-25 10:55:48 -06008168 synchronized (this) {
8169 mWatchers.register(watcher);
8170 }
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008171 }
8172
8173 public void unregisterActivityWatcher(IActivityWatcher watcher) {
Josh Bartel2ecce342010-02-25 10:55:48 -06008174 synchronized (this) {
8175 mWatchers.unregister(watcher);
8176 }
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008177 }
8178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008179 public final void enterSafeMode() {
8180 synchronized(this) {
8181 // It only makes sense to do this before the system is ready
8182 // and started launching other packages.
8183 if (!mSystemReady) {
8184 try {
8185 ActivityThread.getPackageManager().enterSafeMode();
8186 } catch (RemoteException e) {
8187 }
8188
8189 View v = LayoutInflater.from(mContext).inflate(
8190 com.android.internal.R.layout.safe_mode, null);
8191 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8192 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8193 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8194 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8195 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8196 lp.format = v.getBackground().getOpacity();
8197 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8198 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8199 ((WindowManager)mContext.getSystemService(
8200 Context.WINDOW_SERVICE)).addView(v, lp);
8201 }
8202 }
8203 }
8204
8205 public void noteWakeupAlarm(IIntentSender sender) {
8206 if (!(sender instanceof PendingIntentRecord)) {
8207 return;
8208 }
8209 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8210 synchronized (stats) {
8211 if (mBatteryStatsService.isOnBattery()) {
8212 mBatteryStatsService.enforceCallingPermission();
8213 PendingIntentRecord rec = (PendingIntentRecord)sender;
8214 int MY_UID = Binder.getCallingUid();
8215 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8216 BatteryStatsImpl.Uid.Pkg pkg =
8217 stats.getPackageStatsLocked(uid, rec.key.packageName);
8218 pkg.incWakeupsLocked();
8219 }
8220 }
8221 }
8222
8223 public boolean killPidsForMemory(int[] pids) {
8224 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8225 throw new SecurityException("killPidsForMemory only available to the system");
8226 }
8227
8228 // XXX Note: don't acquire main activity lock here, because the window
8229 // manager calls in with its locks held.
8230
8231 boolean killed = false;
8232 synchronized (mPidsSelfLocked) {
8233 int[] types = new int[pids.length];
8234 int worstType = 0;
8235 for (int i=0; i<pids.length; i++) {
8236 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8237 if (proc != null) {
8238 int type = proc.setAdj;
8239 types[i] = type;
8240 if (type > worstType) {
8241 worstType = type;
8242 }
8243 }
8244 }
8245
8246 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8247 // then constrain it so we will kill all hidden procs.
8248 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8249 worstType = HIDDEN_APP_MIN_ADJ;
8250 }
8251 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8252 for (int i=0; i<pids.length; i++) {
8253 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8254 if (proc == null) {
8255 continue;
8256 }
8257 int adj = proc.setAdj;
8258 if (adj >= worstType) {
8259 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8260 + adj + ")");
8261 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8262 proc.processName, adj);
8263 killed = true;
8264 Process.killProcess(pids[i]);
8265 }
8266 }
8267 }
8268 return killed;
8269 }
8270
8271 public void reportPss(IApplicationThread caller, int pss) {
8272 Watchdog.PssRequestor req;
8273 String name;
8274 ProcessRecord callerApp;
8275 synchronized (this) {
8276 if (caller == null) {
8277 return;
8278 }
8279 callerApp = getRecordForAppLocked(caller);
8280 if (callerApp == null) {
8281 return;
8282 }
8283 callerApp.lastPss = pss;
8284 req = callerApp;
8285 name = callerApp.processName;
8286 }
8287 Watchdog.getInstance().reportPss(req, name, pss);
8288 if (!callerApp.persistent) {
8289 removeRequestedPss(callerApp);
8290 }
8291 }
8292
8293 public void requestPss(Runnable completeCallback) {
8294 ArrayList<ProcessRecord> procs;
8295 synchronized (this) {
8296 mRequestPssCallback = completeCallback;
8297 mRequestPssList.clear();
8298 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8299 ProcessRecord proc = mLRUProcesses.get(i);
8300 if (!proc.persistent) {
8301 mRequestPssList.add(proc);
8302 }
8303 }
8304 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8305 }
8306
8307 int oldPri = Process.getThreadPriority(Process.myTid());
8308 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8309 for (int i=procs.size()-1; i>=0; i--) {
8310 ProcessRecord proc = procs.get(i);
8311 proc.lastPss = 0;
8312 proc.requestPss();
8313 }
8314 Process.setThreadPriority(oldPri);
8315 }
8316
8317 void removeRequestedPss(ProcessRecord proc) {
8318 Runnable callback = null;
8319 synchronized (this) {
8320 if (mRequestPssList.remove(proc)) {
8321 if (mRequestPssList.size() == 0) {
8322 callback = mRequestPssCallback;
8323 mRequestPssCallback = null;
8324 }
8325 }
8326 }
8327
8328 if (callback != null) {
8329 callback.run();
8330 }
8331 }
8332
8333 public void collectPss(Watchdog.PssStats stats) {
8334 stats.mEmptyPss = 0;
8335 stats.mEmptyCount = 0;
8336 stats.mBackgroundPss = 0;
8337 stats.mBackgroundCount = 0;
8338 stats.mServicePss = 0;
8339 stats.mServiceCount = 0;
8340 stats.mVisiblePss = 0;
8341 stats.mVisibleCount = 0;
8342 stats.mForegroundPss = 0;
8343 stats.mForegroundCount = 0;
8344 stats.mNoPssCount = 0;
8345 synchronized (this) {
8346 int i;
8347 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8348 ? mProcDeaths.length : stats.mProcDeaths.length;
8349 int aggr = 0;
8350 for (i=0; i<NPD; i++) {
8351 aggr += mProcDeaths[i];
8352 stats.mProcDeaths[i] = aggr;
8353 }
8354 while (i<stats.mProcDeaths.length) {
8355 stats.mProcDeaths[i] = 0;
8356 i++;
8357 }
8358
8359 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8360 ProcessRecord proc = mLRUProcesses.get(i);
8361 if (proc.persistent) {
8362 continue;
8363 }
8364 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8365 if (proc.lastPss == 0) {
8366 stats.mNoPssCount++;
8367 continue;
8368 }
8369 if (proc.setAdj == EMPTY_APP_ADJ) {
8370 stats.mEmptyPss += proc.lastPss;
8371 stats.mEmptyCount++;
8372 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8373 stats.mEmptyPss += proc.lastPss;
8374 stats.mEmptyCount++;
8375 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8376 stats.mBackgroundPss += proc.lastPss;
8377 stats.mBackgroundCount++;
8378 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8379 stats.mVisiblePss += proc.lastPss;
8380 stats.mVisibleCount++;
8381 } else {
8382 stats.mForegroundPss += proc.lastPss;
8383 stats.mForegroundCount++;
8384 }
8385 }
8386 }
8387 }
8388
8389 public final void startRunning(String pkg, String cls, String action,
8390 String data) {
8391 synchronized(this) {
8392 if (mStartRunning) {
8393 return;
8394 }
8395 mStartRunning = true;
8396 mTopComponent = pkg != null && cls != null
8397 ? new ComponentName(pkg, cls) : null;
8398 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8399 mTopData = data;
8400 if (!mSystemReady) {
8401 return;
8402 }
8403 }
8404
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008405 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008406 }
8407
8408 private void retrieveSettings() {
8409 final ContentResolver resolver = mContext.getContentResolver();
8410 String debugApp = Settings.System.getString(
8411 resolver, Settings.System.DEBUG_APP);
8412 boolean waitForDebugger = Settings.System.getInt(
8413 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8414 boolean alwaysFinishActivities = Settings.System.getInt(
8415 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8416
8417 Configuration configuration = new Configuration();
8418 Settings.System.getConfiguration(resolver, configuration);
8419
8420 synchronized (this) {
8421 mDebugApp = mOrigDebugApp = debugApp;
8422 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8423 mAlwaysFinishActivities = alwaysFinishActivities;
8424 // This happens before any activities are started, so we can
8425 // change mConfiguration in-place.
8426 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008427 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008428 }
8429 }
8430
8431 public boolean testIsSystemReady() {
8432 // no need to synchronize(this) just to read & return the value
8433 return mSystemReady;
8434 }
8435
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008436 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008437 // In the simulator, startRunning will never have been called, which
8438 // normally sets a few crucial variables. Do it here instead.
8439 if (!Process.supportsProcesses()) {
8440 mStartRunning = true;
8441 mTopAction = Intent.ACTION_MAIN;
8442 }
8443
8444 synchronized(this) {
8445 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008446 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008447 return;
8448 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008449
8450 // Check to see if there are any update receivers to run.
8451 if (!mDidUpdate) {
8452 if (mWaitingUpdate) {
8453 return;
8454 }
8455 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8456 List<ResolveInfo> ris = null;
8457 try {
8458 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8459 intent, null, 0);
8460 } catch (RemoteException e) {
8461 }
8462 if (ris != null) {
8463 for (int i=ris.size()-1; i>=0; i--) {
8464 if ((ris.get(i).activityInfo.applicationInfo.flags
8465 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8466 ris.remove(i);
8467 }
8468 }
8469 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8470 for (int i=0; i<ris.size(); i++) {
8471 ActivityInfo ai = ris.get(i).activityInfo;
8472 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8473 IIntentReceiver finisher = null;
8474 if (i == 0) {
8475 finisher = new IIntentReceiver.Stub() {
8476 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008477 String data, Bundle extras, boolean ordered,
8478 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008479 throws RemoteException {
8480 synchronized (ActivityManagerService.this) {
8481 mDidUpdate = true;
8482 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008483 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008484 }
8485 };
8486 }
8487 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8488 broadcastIntentLocked(null, null, intent, null, finisher,
8489 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8490 if (i == 0) {
8491 mWaitingUpdate = true;
8492 }
8493 }
8494 }
8495 if (mWaitingUpdate) {
8496 return;
8497 }
8498 mDidUpdate = true;
8499 }
8500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008501 mSystemReady = true;
8502 if (!mStartRunning) {
8503 return;
8504 }
8505 }
8506
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008507 ArrayList<ProcessRecord> procsToKill = null;
8508 synchronized(mPidsSelfLocked) {
8509 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8510 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8511 if (!isAllowedWhileBooting(proc.info)){
8512 if (procsToKill == null) {
8513 procsToKill = new ArrayList<ProcessRecord>();
8514 }
8515 procsToKill.add(proc);
8516 }
8517 }
8518 }
8519
8520 if (procsToKill != null) {
8521 synchronized(this) {
8522 for (int i=procsToKill.size()-1; i>=0; i--) {
8523 ProcessRecord proc = procsToKill.get(i);
8524 Log.i(TAG, "Removing system update proc: " + proc);
8525 removeProcessLocked(proc, true);
8526 }
8527 }
8528 }
8529
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008530 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008531 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8532 SystemClock.uptimeMillis());
8533
8534 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008535 // Make sure we have no pre-ready processes sitting around.
8536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008537 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8538 ResolveInfo ri = mContext.getPackageManager()
8539 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008540 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008541 CharSequence errorMsg = null;
8542 if (ri != null) {
8543 ActivityInfo ai = ri.activityInfo;
8544 ApplicationInfo app = ai.applicationInfo;
8545 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8546 mTopAction = Intent.ACTION_FACTORY_TEST;
8547 mTopData = null;
8548 mTopComponent = new ComponentName(app.packageName,
8549 ai.name);
8550 } else {
8551 errorMsg = mContext.getResources().getText(
8552 com.android.internal.R.string.factorytest_not_system);
8553 }
8554 } else {
8555 errorMsg = mContext.getResources().getText(
8556 com.android.internal.R.string.factorytest_no_action);
8557 }
8558 if (errorMsg != null) {
8559 mTopAction = null;
8560 mTopData = null;
8561 mTopComponent = null;
8562 Message msg = Message.obtain();
8563 msg.what = SHOW_FACTORY_ERROR_MSG;
8564 msg.getData().putCharSequence("msg", errorMsg);
8565 mHandler.sendMessage(msg);
8566 }
8567 }
8568 }
8569
8570 retrieveSettings();
8571
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008572 if (goingCallback != null) goingCallback.run();
8573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008574 synchronized (this) {
8575 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8576 try {
8577 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008578 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008579 if (apps != null) {
8580 int N = apps.size();
8581 int i;
8582 for (i=0; i<N; i++) {
8583 ApplicationInfo info
8584 = (ApplicationInfo)apps.get(i);
8585 if (info != null &&
8586 !info.packageName.equals("android")) {
8587 addAppLocked(info);
8588 }
8589 }
8590 }
8591 } catch (RemoteException ex) {
8592 // pm is in same process, this will never happen.
8593 }
8594 }
8595
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008596 // Start up initial activity.
8597 mBooting = true;
8598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008599 try {
8600 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8601 Message msg = Message.obtain();
8602 msg.what = SHOW_UID_ERROR_MSG;
8603 mHandler.sendMessage(msg);
8604 }
8605 } catch (RemoteException e) {
8606 }
8607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008608 resumeTopActivityLocked(null);
8609 }
8610 }
8611
8612 boolean makeAppCrashingLocked(ProcessRecord app,
8613 String tag, String shortMsg, String longMsg, byte[] crashData) {
8614 app.crashing = true;
8615 app.crashingReport = generateProcessError(app,
8616 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8617 startAppProblemLocked(app);
8618 app.stopFreezingAllLocked();
8619 return handleAppCrashLocked(app);
8620 }
8621
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008622 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008623 // check if error reporting is enabled in Gservices
8624 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8625 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8626 if (enabled == 0) {
8627 return null;
8628 }
8629
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008630 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008631
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008632 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008633 // look for receiver in the installer package
8634 String candidate = pm.getInstallerPackageName(app.info.packageName);
8635 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8636 if (result != null) {
8637 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008638 }
8639
Jacek Surazski82a73df2009-06-17 14:33:18 +02008640 // if the error app is on the system image, look for system apps
8641 // error receiver
8642 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8643 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8644 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8645 if (result != null) {
8646 return result;
8647 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008648 }
8649
Jacek Surazski82a73df2009-06-17 14:33:18 +02008650 // if there is a default receiver, try that
8651 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8652 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008653 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008654 // should not happen
8655 Log.e(TAG, "error talking to PackageManager", e);
8656 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008657 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008658 }
8659
8660 /**
8661 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8662 *
8663 * @param pm PackageManager isntance
8664 * @param errorPackage package which caused the error
8665 * @param receiverPackage candidate package to receive the error
8666 * @return activity component within receiverPackage which handles
8667 * ACTION_APP_ERROR, or null if not found
8668 */
8669 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8670 String receiverPackage) throws RemoteException {
8671 if (receiverPackage == null || receiverPackage.length() == 0) {
8672 return null;
8673 }
8674
8675 // break the loop if it's the error report receiver package that crashed
8676 if (receiverPackage.equals(errorPackage)) {
8677 return null;
8678 }
8679
8680 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8681 intent.setPackage(receiverPackage);
8682 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8683 if (info == null || info.activityInfo == null) {
8684 return null;
8685 }
8686 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008687 }
8688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008689 void makeAppNotRespondingLocked(ProcessRecord app,
8690 String tag, String shortMsg, String longMsg, byte[] crashData) {
8691 app.notResponding = true;
8692 app.notRespondingReport = generateProcessError(app,
8693 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8694 crashData);
8695 startAppProblemLocked(app);
8696 app.stopFreezingAllLocked();
8697 }
8698
8699 /**
8700 * Generate a process error record, suitable for attachment to a ProcessRecord.
8701 *
8702 * @param app The ProcessRecord in which the error occurred.
8703 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8704 * ActivityManager.AppErrorStateInfo
8705 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8706 * @param shortMsg Short message describing the crash.
8707 * @param longMsg Long message describing the crash.
8708 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8709 *
8710 * @return Returns a fully-formed AppErrorStateInfo record.
8711 */
8712 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8713 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8714 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8715
8716 report.condition = condition;
8717 report.processName = app.processName;
8718 report.pid = app.pid;
8719 report.uid = app.info.uid;
8720 report.tag = tag;
8721 report.shortMsg = shortMsg;
8722 report.longMsg = longMsg;
8723 report.crashData = crashData;
8724
8725 return report;
8726 }
8727
8728 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8729 boolean crashed) {
8730 synchronized (this) {
8731 app.crashing = false;
8732 app.crashingReport = null;
8733 app.notResponding = false;
8734 app.notRespondingReport = null;
8735 if (app.anrDialog == fromDialog) {
8736 app.anrDialog = null;
8737 }
8738 if (app.waitDialog == fromDialog) {
8739 app.waitDialog = null;
8740 }
8741 if (app.pid > 0 && app.pid != MY_PID) {
8742 if (crashed) {
8743 handleAppCrashLocked(app);
8744 }
8745 Log.i(ActivityManagerService.TAG, "Killing process "
8746 + app.processName
8747 + " (pid=" + app.pid + ") at user's request");
8748 Process.killProcess(app.pid);
8749 }
8750
8751 }
8752 }
8753
8754 boolean handleAppCrashLocked(ProcessRecord app) {
8755 long now = SystemClock.uptimeMillis();
8756
8757 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8758 app.info.uid);
8759 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8760 // This process loses!
8761 Log.w(TAG, "Process " + app.info.processName
8762 + " has crashed too many times: killing!");
8763 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8764 app.info.processName, app.info.uid);
8765 killServicesLocked(app, false);
8766 for (int i=mHistory.size()-1; i>=0; i--) {
8767 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8768 if (r.app == app) {
8769 if (Config.LOGD) Log.d(
8770 TAG, " Force finishing activity "
8771 + r.intent.getComponent().flattenToShortString());
8772 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8773 }
8774 }
8775 if (!app.persistent) {
8776 // We don't want to start this process again until the user
8777 // explicitly does so... but for persistent process, we really
8778 // need to keep it running. If a persistent process is actually
8779 // repeatedly crashing, then badness for everyone.
8780 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8781 app.info.processName);
8782 mBadProcesses.put(app.info.processName, app.info.uid, now);
8783 app.bad = true;
8784 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8785 app.removed = true;
8786 removeProcessLocked(app, false);
8787 return false;
8788 }
8789 }
8790
8791 // Bump up the crash count of any services currently running in the proc.
8792 if (app.services.size() != 0) {
8793 // Any services running in the application need to be placed
8794 // back in the pending list.
8795 Iterator it = app.services.iterator();
8796 while (it.hasNext()) {
8797 ServiceRecord sr = (ServiceRecord)it.next();
8798 sr.crashCount++;
8799 }
8800 }
8801
8802 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8803 return true;
8804 }
8805
8806 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008807 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008808 skipCurrentReceiverLocked(app);
8809 }
8810
8811 void skipCurrentReceiverLocked(ProcessRecord app) {
8812 boolean reschedule = false;
8813 BroadcastRecord r = app.curReceiver;
8814 if (r != null) {
8815 // The current broadcast is waiting for this app's receiver
8816 // to be finished. Looks like that's not going to happen, so
8817 // let the broadcast continue.
8818 logBroadcastReceiverDiscard(r);
8819 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8820 r.resultExtras, r.resultAbort, true);
8821 reschedule = true;
8822 }
8823 r = mPendingBroadcast;
8824 if (r != null && r.curApp == app) {
8825 if (DEBUG_BROADCAST) Log.v(TAG,
8826 "skip & discard pending app " + r);
8827 logBroadcastReceiverDiscard(r);
8828 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8829 r.resultExtras, r.resultAbort, true);
8830 reschedule = true;
8831 }
8832 if (reschedule) {
8833 scheduleBroadcastsLocked();
8834 }
8835 }
8836
8837 public int handleApplicationError(IBinder app, int flags,
8838 String tag, String shortMsg, String longMsg, byte[] crashData) {
8839 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008840 ProcessRecord r = null;
8841 synchronized (this) {
8842 if (app != null) {
8843 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8844 final int NA = apps.size();
8845 for (int ia=0; ia<NA; ia++) {
8846 ProcessRecord p = apps.valueAt(ia);
8847 if (p.thread != null && p.thread.asBinder() == app) {
8848 r = p;
8849 break;
8850 }
8851 }
8852 }
8853 }
8854
8855 if (r != null) {
8856 // The application has crashed. Send the SIGQUIT to the process so
8857 // that it can dump its state.
8858 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8859 //Log.i(TAG, "Current system threads:");
8860 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8861 }
8862
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008863 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008864 try {
8865 String name = r != null ? r.processName : null;
8866 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008867 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008868 shortMsg, longMsg, crashData)) {
8869 Log.w(TAG, "Force-killing crashed app " + name
8870 + " at watcher's request");
8871 Process.killProcess(pid);
8872 return 0;
8873 }
8874 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008875 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008876 }
8877 }
8878
8879 final long origId = Binder.clearCallingIdentity();
8880
8881 // If this process is running instrumentation, finish it.
8882 if (r != null && r.instrumentationClass != null) {
8883 Log.w(TAG, "Error in app " + r.processName
8884 + " running instrumentation " + r.instrumentationClass + ":");
8885 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8886 if (longMsg != null) Log.w(TAG, " " + longMsg);
8887 Bundle info = new Bundle();
8888 info.putString("shortMsg", shortMsg);
8889 info.putString("longMsg", longMsg);
8890 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8891 Binder.restoreCallingIdentity(origId);
8892 return 0;
8893 }
8894
8895 if (r != null) {
8896 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8897 return 0;
8898 }
8899 } else {
8900 Log.w(TAG, "Some application object " + app + " tag " + tag
8901 + " has crashed, but I don't know who it is.");
8902 Log.w(TAG, "ShortMsg:" + shortMsg);
8903 Log.w(TAG, "LongMsg:" + longMsg);
8904 Binder.restoreCallingIdentity(origId);
8905 return 0;
8906 }
8907
8908 Message msg = Message.obtain();
8909 msg.what = SHOW_ERROR_MSG;
8910 HashMap data = new HashMap();
8911 data.put("result", result);
8912 data.put("app", r);
8913 data.put("flags", flags);
8914 data.put("shortMsg", shortMsg);
8915 data.put("longMsg", longMsg);
8916 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8917 // For system processes, submit crash data to the server.
8918 data.put("crashData", crashData);
8919 }
8920 msg.obj = data;
8921 mHandler.sendMessage(msg);
8922
8923 Binder.restoreCallingIdentity(origId);
8924 }
8925
8926 int res = result.get();
8927
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008928 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008929 synchronized (this) {
8930 if (r != null) {
8931 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8932 SystemClock.uptimeMillis());
8933 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008934 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8935 appErrorIntent = createAppErrorIntentLocked(r);
8936 res = AppErrorDialog.FORCE_QUIT;
8937 }
8938 }
8939
8940 if (appErrorIntent != null) {
8941 try {
8942 mContext.startActivity(appErrorIntent);
8943 } catch (ActivityNotFoundException e) {
8944 Log.w(TAG, "bug report receiver dissappeared", e);
8945 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008946 }
8947
8948 return res;
8949 }
8950
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008951 Intent createAppErrorIntentLocked(ProcessRecord r) {
8952 ApplicationErrorReport report = createAppErrorReportLocked(r);
8953 if (report == null) {
8954 return null;
8955 }
8956 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8957 result.setComponent(r.errorReportReceiver);
8958 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8959 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8960 return result;
8961 }
8962
8963 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8964 if (r.errorReportReceiver == null) {
8965 return null;
8966 }
8967
8968 if (!r.crashing && !r.notResponding) {
8969 return null;
8970 }
8971
8972 try {
8973 ApplicationErrorReport report = new ApplicationErrorReport();
8974 report.packageName = r.info.packageName;
8975 report.installerPackageName = r.errorReportReceiver.getPackageName();
8976 report.processName = r.processName;
8977
8978 if (r.crashing) {
8979 report.type = ApplicationErrorReport.TYPE_CRASH;
8980 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8981
8982 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8983 r.crashingReport.crashData);
8984 DataInputStream dataStream = new DataInputStream(byteStream);
8985 CrashData crashData = new CrashData(dataStream);
8986 ThrowableData throwData = crashData.getThrowableData();
8987
8988 report.time = crashData.getTime();
8989 report.crashInfo.stackTrace = throwData.toString();
8990
Jacek Surazskif829a782009-06-11 22:47:02 +02008991 // Extract the source of the exception, useful for report
8992 // clustering. Also extract the "deepest" non-null exception
8993 // message.
8994 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008995 while (throwData.getCause() != null) {
8996 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008997 String msg = throwData.getMessage();
8998 if (msg != null && msg.length() > 0) {
8999 exceptionMessage = msg;
9000 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009001 }
9002 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02009003 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009004 report.crashInfo.exceptionClassName = throwData.getType();
9005 report.crashInfo.throwFileName = trace.getFileName();
9006 report.crashInfo.throwClassName = trace.getClassName();
9007 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02009008 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009009 } else if (r.notResponding) {
9010 report.type = ApplicationErrorReport.TYPE_ANR;
9011 report.anrInfo = new ApplicationErrorReport.AnrInfo();
9012
9013 report.anrInfo.activity = r.notRespondingReport.tag;
9014 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9015 report.anrInfo.info = r.notRespondingReport.longMsg;
9016 }
9017
9018 return report;
9019 } catch (IOException e) {
9020 // we don't send it
9021 }
9022
9023 return null;
9024 }
9025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009026 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9027 // assume our apps are happy - lazy create the list
9028 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9029
9030 synchronized (this) {
9031
9032 // iterate across all processes
9033 final int N = mLRUProcesses.size();
9034 for (int i = 0; i < N; i++) {
9035 ProcessRecord app = mLRUProcesses.get(i);
9036 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9037 // This one's in trouble, so we'll generate a report for it
9038 // crashes are higher priority (in case there's a crash *and* an anr)
9039 ActivityManager.ProcessErrorStateInfo report = null;
9040 if (app.crashing) {
9041 report = app.crashingReport;
9042 } else if (app.notResponding) {
9043 report = app.notRespondingReport;
9044 }
9045
9046 if (report != null) {
9047 if (errList == null) {
9048 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9049 }
9050 errList.add(report);
9051 } else {
9052 Log.w(TAG, "Missing app error report, app = " + app.processName +
9053 " crashing = " + app.crashing +
9054 " notResponding = " + app.notResponding);
9055 }
9056 }
9057 }
9058 }
9059
9060 return errList;
9061 }
9062
9063 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9064 // Lazy instantiation of list
9065 List<ActivityManager.RunningAppProcessInfo> runList = null;
9066 synchronized (this) {
9067 // Iterate across all processes
9068 final int N = mLRUProcesses.size();
9069 for (int i = 0; i < N; i++) {
9070 ProcessRecord app = mLRUProcesses.get(i);
9071 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9072 // Generate process state info for running application
9073 ActivityManager.RunningAppProcessInfo currApp =
9074 new ActivityManager.RunningAppProcessInfo(app.processName,
9075 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009076 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009077 int adj = app.curAdj;
9078 if (adj >= CONTENT_PROVIDER_ADJ) {
9079 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9080 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9081 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009082 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9083 } else if (adj >= HOME_APP_ADJ) {
9084 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9085 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009086 } else if (adj >= SECONDARY_SERVER_ADJ) {
9087 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9088 } else if (adj >= VISIBLE_APP_ADJ) {
9089 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9090 } else {
9091 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9092 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009093 currApp.importanceReasonCode = app.adjTypeCode;
9094 if (app.adjSource instanceof ProcessRecord) {
9095 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9096 } else if (app.adjSource instanceof HistoryRecord) {
9097 HistoryRecord r = (HistoryRecord)app.adjSource;
9098 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9099 }
9100 if (app.adjTarget instanceof ComponentName) {
9101 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9102 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009103 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9104 // + " lru=" + currApp.lru);
9105 if (runList == null) {
9106 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9107 }
9108 runList.add(currApp);
9109 }
9110 }
9111 }
9112 return runList;
9113 }
9114
9115 @Override
9116 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9117 synchronized (this) {
9118 if (checkCallingPermission(android.Manifest.permission.DUMP)
9119 != PackageManager.PERMISSION_GRANTED) {
9120 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9121 + Binder.getCallingPid()
9122 + ", uid=" + Binder.getCallingUid()
9123 + " without permission "
9124 + android.Manifest.permission.DUMP);
9125 return;
9126 }
9127 if (args.length != 0 && "service".equals(args[0])) {
9128 dumpService(fd, pw, args);
9129 return;
9130 }
9131 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009132 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009133 pw.println(" ");
9134 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009135 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009136 if (mWaitingVisibleActivities.size() > 0) {
9137 pw.println(" ");
9138 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009139 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009140 }
9141 if (mStoppingActivities.size() > 0) {
9142 pw.println(" ");
9143 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009144 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009145 }
9146 if (mFinishingActivities.size() > 0) {
9147 pw.println(" ");
9148 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009149 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009150 }
9151
9152 pw.println(" ");
9153 pw.println(" mPausingActivity: " + mPausingActivity);
9154 pw.println(" mResumedActivity: " + mResumedActivity);
9155 pw.println(" mFocusedActivity: " + mFocusedActivity);
9156 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9157
9158 if (mRecentTasks.size() > 0) {
9159 pw.println(" ");
9160 pw.println("Recent tasks in Current Activity Manager State:");
9161
9162 final int N = mRecentTasks.size();
9163 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009164 TaskRecord tr = mRecentTasks.get(i);
9165 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9166 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009167 mRecentTasks.get(i).dump(pw, " ");
9168 }
9169 }
9170
9171 pw.println(" ");
9172 pw.println(" mCurTask: " + mCurTask);
9173
9174 pw.println(" ");
9175 pw.println("Processes in Current Activity Manager State:");
9176
9177 boolean needSep = false;
9178 int numPers = 0;
9179
9180 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9181 final int NA = procs.size();
9182 for (int ia=0; ia<NA; ia++) {
9183 if (!needSep) {
9184 pw.println(" All known processes:");
9185 needSep = true;
9186 }
9187 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009188 pw.print(r.persistent ? " *PERS*" : " *APP*");
9189 pw.print(" UID "); pw.print(procs.keyAt(ia));
9190 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009191 r.dump(pw, " ");
9192 if (r.persistent) {
9193 numPers++;
9194 }
9195 }
9196 }
9197
9198 if (mLRUProcesses.size() > 0) {
9199 if (needSep) pw.println(" ");
9200 needSep = true;
9201 pw.println(" Running processes (most recent first):");
9202 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009203 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009204 needSep = true;
9205 }
9206
9207 synchronized (mPidsSelfLocked) {
9208 if (mPidsSelfLocked.size() > 0) {
9209 if (needSep) pw.println(" ");
9210 needSep = true;
9211 pw.println(" PID mappings:");
9212 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009213 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9214 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009215 }
9216 }
9217 }
9218
9219 if (mForegroundProcesses.size() > 0) {
9220 if (needSep) pw.println(" ");
9221 needSep = true;
9222 pw.println(" Foreground Processes:");
9223 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009224 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9225 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009226 }
9227 }
9228
9229 if (mPersistentStartingProcesses.size() > 0) {
9230 if (needSep) pw.println(" ");
9231 needSep = true;
9232 pw.println(" Persisent processes that are starting:");
9233 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009234 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009235 }
9236
9237 if (mStartingProcesses.size() > 0) {
9238 if (needSep) pw.println(" ");
9239 needSep = true;
9240 pw.println(" Processes that are starting:");
9241 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009242 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009243 }
9244
9245 if (mRemovedProcesses.size() > 0) {
9246 if (needSep) pw.println(" ");
9247 needSep = true;
9248 pw.println(" Processes that are being removed:");
9249 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009250 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009251 }
9252
9253 if (mProcessesOnHold.size() > 0) {
9254 if (needSep) pw.println(" ");
9255 needSep = true;
9256 pw.println(" Processes that are on old until the system is ready:");
9257 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009258 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009259 }
9260
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009261 if (mProcessesToGc.size() > 0) {
9262 if (needSep) pw.println(" ");
9263 needSep = true;
9264 pw.println(" Processes that are waiting to GC:");
9265 long now = SystemClock.uptimeMillis();
9266 for (int i=0; i<mProcessesToGc.size(); i++) {
9267 ProcessRecord proc = mProcessesToGc.get(i);
9268 pw.print(" Process "); pw.println(proc);
9269 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9270 pw.print(", last gced=");
9271 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009272 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009273 pw.print(now-proc.lastLowMemory);
9274 pw.println(" ms ago");
9275
9276 }
9277 }
9278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009279 if (mProcessCrashTimes.getMap().size() > 0) {
9280 if (needSep) pw.println(" ");
9281 needSep = true;
9282 pw.println(" Time since processes crashed:");
9283 long now = SystemClock.uptimeMillis();
9284 for (Map.Entry<String, SparseArray<Long>> procs
9285 : mProcessCrashTimes.getMap().entrySet()) {
9286 SparseArray<Long> uids = procs.getValue();
9287 final int N = uids.size();
9288 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009289 pw.print(" Process "); pw.print(procs.getKey());
9290 pw.print(" uid "); pw.print(uids.keyAt(i));
9291 pw.print(": last crashed ");
9292 pw.print((now-uids.valueAt(i)));
9293 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009294 }
9295 }
9296 }
9297
9298 if (mBadProcesses.getMap().size() > 0) {
9299 if (needSep) pw.println(" ");
9300 needSep = true;
9301 pw.println(" Bad processes:");
9302 for (Map.Entry<String, SparseArray<Long>> procs
9303 : mBadProcesses.getMap().entrySet()) {
9304 SparseArray<Long> uids = procs.getValue();
9305 final int N = uids.size();
9306 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009307 pw.print(" Bad process "); pw.print(procs.getKey());
9308 pw.print(" uid "); pw.print(uids.keyAt(i));
9309 pw.print(": crashed at time ");
9310 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009311 }
9312 }
9313 }
9314
9315 pw.println(" ");
9316 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009317 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009318 pw.println(" mConfiguration: " + mConfiguration);
9319 pw.println(" mStartRunning=" + mStartRunning
9320 + " mSystemReady=" + mSystemReady
9321 + " mBooting=" + mBooting
9322 + " mBooted=" + mBooted
9323 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009324 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009325 pw.println(" mGoingToSleep=" + mGoingToSleep);
9326 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9327 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9328 + " mDebugTransient=" + mDebugTransient
9329 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9330 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009331 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009332 }
9333 }
9334
9335 /**
9336 * There are three ways to call this:
9337 * - no service specified: dump all the services
9338 * - a flattened component name that matched an existing service was specified as the
9339 * first arg: dump that one service
9340 * - the first arg isn't the flattened component name of an existing service:
9341 * dump all services whose component contains the first arg as a substring
9342 */
9343 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9344 String[] newArgs;
9345 String componentNameString;
9346 ServiceRecord r;
9347 if (args.length == 1) {
9348 componentNameString = null;
9349 newArgs = EMPTY_STRING_ARRAY;
9350 r = null;
9351 } else {
9352 componentNameString = args[1];
9353 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9354 r = componentName != null ? mServices.get(componentName) : null;
9355 newArgs = new String[args.length - 2];
9356 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9357 }
9358
9359 if (r != null) {
9360 dumpService(fd, pw, r, newArgs);
9361 } else {
9362 for (ServiceRecord r1 : mServices.values()) {
9363 if (componentNameString == null
9364 || r1.name.flattenToString().contains(componentNameString)) {
9365 dumpService(fd, pw, r1, newArgs);
9366 }
9367 }
9368 }
9369 }
9370
9371 /**
9372 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9373 * there is a thread associated with the service.
9374 */
9375 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9376 pw.println(" Service " + r.name.flattenToString());
9377 if (r.app != null && r.app.thread != null) {
9378 try {
9379 // flush anything that is already in the PrintWriter since the thread is going
9380 // to write to the file descriptor directly
9381 pw.flush();
9382 r.app.thread.dumpService(fd, r, args);
9383 pw.print("\n");
9384 } catch (RemoteException e) {
9385 pw.println("got a RemoteException while dumping the service");
9386 }
9387 }
9388 }
9389
9390 void dumpBroadcasts(PrintWriter pw) {
9391 synchronized (this) {
9392 if (checkCallingPermission(android.Manifest.permission.DUMP)
9393 != PackageManager.PERMISSION_GRANTED) {
9394 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9395 + Binder.getCallingPid()
9396 + ", uid=" + Binder.getCallingUid()
9397 + " without permission "
9398 + android.Manifest.permission.DUMP);
9399 return;
9400 }
9401 pw.println("Broadcasts in Current Activity Manager State:");
9402
9403 if (mRegisteredReceivers.size() > 0) {
9404 pw.println(" ");
9405 pw.println(" Registered Receivers:");
9406 Iterator it = mRegisteredReceivers.values().iterator();
9407 while (it.hasNext()) {
9408 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009409 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009410 r.dump(pw, " ");
9411 }
9412 }
9413
9414 pw.println(" ");
9415 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009416 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009417
9418 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9419 || mPendingBroadcast != null) {
9420 if (mParallelBroadcasts.size() > 0) {
9421 pw.println(" ");
9422 pw.println(" Active broadcasts:");
9423 }
9424 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9425 pw.println(" Broadcast #" + i + ":");
9426 mParallelBroadcasts.get(i).dump(pw, " ");
9427 }
9428 if (mOrderedBroadcasts.size() > 0) {
9429 pw.println(" ");
9430 pw.println(" Active serialized broadcasts:");
9431 }
9432 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9433 pw.println(" Serialized Broadcast #" + i + ":");
9434 mOrderedBroadcasts.get(i).dump(pw, " ");
9435 }
9436 pw.println(" ");
9437 pw.println(" Pending broadcast:");
9438 if (mPendingBroadcast != null) {
9439 mPendingBroadcast.dump(pw, " ");
9440 } else {
9441 pw.println(" (null)");
9442 }
9443 }
9444
9445 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009446 pw.println(" Historical broadcasts:");
9447 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9448 BroadcastRecord r = mBroadcastHistory[i];
9449 if (r == null) {
9450 break;
9451 }
9452 pw.println(" Historical Broadcast #" + i + ":");
9453 r.dump(pw, " ");
9454 }
9455
9456 pw.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009457 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9458 if (mStickyBroadcasts != null) {
9459 pw.println(" ");
9460 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009461 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009462 for (Map.Entry<String, ArrayList<Intent>> ent
9463 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009464 pw.print(" * Sticky action "); pw.print(ent.getKey());
9465 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009466 ArrayList<Intent> intents = ent.getValue();
9467 final int N = intents.size();
9468 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009469 sb.setLength(0);
9470 sb.append(" Intent: ");
9471 intents.get(i).toShortString(sb, true, false);
9472 pw.println(sb.toString());
9473 Bundle bundle = intents.get(i).getExtras();
9474 if (bundle != null) {
9475 pw.print(" ");
9476 pw.println(bundle.toString());
9477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009478 }
9479 }
9480 }
9481
9482 pw.println(" ");
9483 pw.println(" mHandler:");
9484 mHandler.dump(new PrintWriterPrinter(pw), " ");
9485 }
9486 }
9487
9488 void dumpServices(PrintWriter pw) {
9489 synchronized (this) {
9490 if (checkCallingPermission(android.Manifest.permission.DUMP)
9491 != PackageManager.PERMISSION_GRANTED) {
9492 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9493 + Binder.getCallingPid()
9494 + ", uid=" + Binder.getCallingUid()
9495 + " without permission "
9496 + android.Manifest.permission.DUMP);
9497 return;
9498 }
9499 pw.println("Services in Current Activity Manager State:");
9500
9501 boolean needSep = false;
9502
9503 if (mServices.size() > 0) {
9504 pw.println(" Active services:");
9505 Iterator<ServiceRecord> it = mServices.values().iterator();
9506 while (it.hasNext()) {
9507 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009508 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009509 r.dump(pw, " ");
9510 }
9511 needSep = true;
9512 }
9513
9514 if (mPendingServices.size() > 0) {
9515 if (needSep) pw.println(" ");
9516 pw.println(" Pending services:");
9517 for (int i=0; i<mPendingServices.size(); i++) {
9518 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009519 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009520 r.dump(pw, " ");
9521 }
9522 needSep = true;
9523 }
9524
9525 if (mRestartingServices.size() > 0) {
9526 if (needSep) pw.println(" ");
9527 pw.println(" Restarting services:");
9528 for (int i=0; i<mRestartingServices.size(); i++) {
9529 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009530 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009531 r.dump(pw, " ");
9532 }
9533 needSep = true;
9534 }
9535
9536 if (mStoppingServices.size() > 0) {
9537 if (needSep) pw.println(" ");
9538 pw.println(" Stopping services:");
9539 for (int i=0; i<mStoppingServices.size(); i++) {
9540 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009541 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009542 r.dump(pw, " ");
9543 }
9544 needSep = true;
9545 }
9546
9547 if (mServiceConnections.size() > 0) {
9548 if (needSep) pw.println(" ");
9549 pw.println(" Connection bindings to services:");
9550 Iterator<ConnectionRecord> it
9551 = mServiceConnections.values().iterator();
9552 while (it.hasNext()) {
9553 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009554 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009555 r.dump(pw, " ");
9556 }
9557 }
9558 }
9559 }
9560
9561 void dumpProviders(PrintWriter pw) {
9562 synchronized (this) {
9563 if (checkCallingPermission(android.Manifest.permission.DUMP)
9564 != PackageManager.PERMISSION_GRANTED) {
9565 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9566 + Binder.getCallingPid()
9567 + ", uid=" + Binder.getCallingUid()
9568 + " without permission "
9569 + android.Manifest.permission.DUMP);
9570 return;
9571 }
9572
9573 pw.println("Content Providers in Current Activity Manager State:");
9574
9575 boolean needSep = false;
9576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009577 if (mProvidersByClass.size() > 0) {
9578 if (needSep) pw.println(" ");
9579 pw.println(" Published content providers (by class):");
9580 Iterator it = mProvidersByClass.entrySet().iterator();
9581 while (it.hasNext()) {
9582 Map.Entry e = (Map.Entry)it.next();
9583 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009584 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009585 r.dump(pw, " ");
9586 }
9587 needSep = true;
9588 }
9589
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009590 if (mProvidersByName.size() > 0) {
9591 pw.println(" ");
9592 pw.println(" Authority to provider mappings:");
9593 Iterator it = mProvidersByName.entrySet().iterator();
9594 while (it.hasNext()) {
9595 Map.Entry e = (Map.Entry)it.next();
9596 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9597 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9598 pw.println(r);
9599 }
9600 needSep = true;
9601 }
9602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009603 if (mLaunchingProviders.size() > 0) {
9604 if (needSep) pw.println(" ");
9605 pw.println(" Launching content providers:");
9606 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009607 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9608 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009609 }
9610 needSep = true;
9611 }
9612
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009613 if (mGrantedUriPermissions.size() > 0) {
9614 pw.println();
9615 pw.println("Granted Uri Permissions:");
9616 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9617 int uid = mGrantedUriPermissions.keyAt(i);
9618 HashMap<Uri, UriPermission> perms
9619 = mGrantedUriPermissions.valueAt(i);
9620 pw.print(" * UID "); pw.print(uid);
9621 pw.println(" holds:");
9622 for (UriPermission perm : perms.values()) {
9623 pw.print(" "); pw.println(perm);
9624 perm.dump(pw, " ");
9625 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009626 }
9627 }
9628 }
9629 }
9630
9631 void dumpSenders(PrintWriter pw) {
9632 synchronized (this) {
9633 if (checkCallingPermission(android.Manifest.permission.DUMP)
9634 != PackageManager.PERMISSION_GRANTED) {
9635 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9636 + Binder.getCallingPid()
9637 + ", uid=" + Binder.getCallingUid()
9638 + " without permission "
9639 + android.Manifest.permission.DUMP);
9640 return;
9641 }
9642
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009643 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009644
9645 if (this.mIntentSenderRecords.size() > 0) {
9646 Iterator<WeakReference<PendingIntentRecord>> it
9647 = mIntentSenderRecords.values().iterator();
9648 while (it.hasNext()) {
9649 WeakReference<PendingIntentRecord> ref = it.next();
9650 PendingIntentRecord rec = ref != null ? ref.get(): null;
9651 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009652 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009653 rec.dump(pw, " ");
9654 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009655 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009656 }
9657 }
9658 }
9659 }
9660 }
9661
9662 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009663 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009664 TaskRecord lastTask = null;
9665 for (int i=list.size()-1; i>=0; i--) {
9666 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009667 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009668 if (lastTask != r.task) {
9669 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009670 pw.print(prefix);
9671 pw.print(full ? "* " : " ");
9672 pw.println(lastTask);
9673 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009674 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009675 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009676 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009677 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9678 pw.print(" #"); pw.print(i); pw.print(": ");
9679 pw.println(r);
9680 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009681 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009683 }
9684 }
9685
9686 private static final int dumpProcessList(PrintWriter pw, List list,
9687 String prefix, String normalLabel, String persistentLabel,
9688 boolean inclOomAdj) {
9689 int numPers = 0;
9690 for (int i=list.size()-1; i>=0; i--) {
9691 ProcessRecord r = (ProcessRecord)list.get(i);
9692 if (false) {
9693 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9694 + " #" + i + ":");
9695 r.dump(pw, prefix + " ");
9696 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009697 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009698 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009699 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9700 if (r.adjSource != null || r.adjTarget != null) {
9701 pw.println(prefix + " " + r.adjTarget
9702 + " used by " + r.adjSource);
9703 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009704 } else {
9705 pw.println(String.format("%s%s #%2d: %s",
9706 prefix, (r.persistent ? persistentLabel : normalLabel),
9707 i, r.toString()));
9708 }
9709 if (r.persistent) {
9710 numPers++;
9711 }
9712 }
9713 return numPers;
9714 }
9715
9716 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9717 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009718 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009719 long uptime = SystemClock.uptimeMillis();
9720 long realtime = SystemClock.elapsedRealtime();
9721
9722 if (isCheckinRequest) {
9723 // short checkin version
9724 pw.println(uptime + "," + realtime);
9725 pw.flush();
9726 } else {
9727 pw.println("Applications Memory Usage (kB):");
9728 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9729 }
9730 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9731 ProcessRecord r = (ProcessRecord)list.get(i);
9732 if (r.thread != null) {
9733 if (!isCheckinRequest) {
9734 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9735 pw.flush();
9736 }
9737 try {
9738 r.thread.asBinder().dump(fd, args);
9739 } catch (RemoteException e) {
9740 if (!isCheckinRequest) {
9741 pw.println("Got RemoteException!");
9742 pw.flush();
9743 }
9744 }
9745 }
9746 }
9747 }
9748
9749 /**
9750 * Searches array of arguments for the specified string
9751 * @param args array of argument strings
9752 * @param value value to search for
9753 * @return true if the value is contained in the array
9754 */
9755 private static boolean scanArgs(String[] args, String value) {
9756 if (args != null) {
9757 for (String arg : args) {
9758 if (value.equals(arg)) {
9759 return true;
9760 }
9761 }
9762 }
9763 return false;
9764 }
9765
Dianne Hackborn75b03852009-06-12 15:43:26 -07009766 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009767 int count = mHistory.size();
9768
9769 // convert the token to an entry in the history.
9770 HistoryRecord r = null;
9771 int index = -1;
9772 for (int i=count-1; i>=0; i--) {
9773 Object o = mHistory.get(i);
9774 if (o == token) {
9775 r = (HistoryRecord)o;
9776 index = i;
9777 break;
9778 }
9779 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009780
9781 return index;
9782 }
9783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009784 private final void killServicesLocked(ProcessRecord app,
9785 boolean allowRestart) {
9786 // Report disconnected services.
9787 if (false) {
9788 // XXX we are letting the client link to the service for
9789 // death notifications.
9790 if (app.services.size() > 0) {
9791 Iterator it = app.services.iterator();
9792 while (it.hasNext()) {
9793 ServiceRecord r = (ServiceRecord)it.next();
9794 if (r.connections.size() > 0) {
9795 Iterator<ConnectionRecord> jt
9796 = r.connections.values().iterator();
9797 while (jt.hasNext()) {
9798 ConnectionRecord c = jt.next();
9799 if (c.binding.client != app) {
9800 try {
9801 //c.conn.connected(r.className, null);
9802 } catch (Exception e) {
9803 // todo: this should be asynchronous!
9804 Log.w(TAG, "Exception thrown disconnected servce "
9805 + r.shortName
9806 + " from app " + app.processName, e);
9807 }
9808 }
9809 }
9810 }
9811 }
9812 }
9813 }
9814
9815 // Clean up any connections this application has to other services.
9816 if (app.connections.size() > 0) {
9817 Iterator<ConnectionRecord> it = app.connections.iterator();
9818 while (it.hasNext()) {
9819 ConnectionRecord r = it.next();
9820 removeConnectionLocked(r, app, null);
9821 }
9822 }
9823 app.connections.clear();
9824
9825 if (app.services.size() != 0) {
9826 // Any services running in the application need to be placed
9827 // back in the pending list.
9828 Iterator it = app.services.iterator();
9829 while (it.hasNext()) {
9830 ServiceRecord sr = (ServiceRecord)it.next();
9831 synchronized (sr.stats.getBatteryStats()) {
9832 sr.stats.stopLaunchedLocked();
9833 }
9834 sr.app = null;
9835 sr.executeNesting = 0;
9836 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009837
9838 boolean hasClients = sr.bindings.size() > 0;
9839 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009840 Iterator<IntentBindRecord> bindings
9841 = sr.bindings.values().iterator();
9842 while (bindings.hasNext()) {
9843 IntentBindRecord b = bindings.next();
9844 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9845 + ": shouldUnbind=" + b.hasBound);
9846 b.binder = null;
9847 b.requested = b.received = b.hasBound = false;
9848 }
9849 }
9850
9851 if (sr.crashCount >= 2) {
9852 Log.w(TAG, "Service crashed " + sr.crashCount
9853 + " times, stopping: " + sr);
9854 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9855 sr.crashCount, sr.shortName, app.pid);
9856 bringDownServiceLocked(sr, true);
9857 } else if (!allowRestart) {
9858 bringDownServiceLocked(sr, true);
9859 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009860 boolean canceled = scheduleServiceRestartLocked(sr, true);
9861
9862 // Should the service remain running? Note that in the
9863 // extreme case of so many attempts to deliver a command
9864 // that it failed, that we also will stop it here.
9865 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9866 if (sr.pendingStarts.size() == 0) {
9867 sr.startRequested = false;
9868 if (!hasClients) {
9869 // Whoops, no reason to restart!
9870 bringDownServiceLocked(sr, true);
9871 }
9872 }
9873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009874 }
9875 }
9876
9877 if (!allowRestart) {
9878 app.services.clear();
9879 }
9880 }
9881
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009882 // Make sure we have no more records on the stopping list.
9883 int i = mStoppingServices.size();
9884 while (i > 0) {
9885 i--;
9886 ServiceRecord sr = mStoppingServices.get(i);
9887 if (sr.app == app) {
9888 mStoppingServices.remove(i);
9889 }
9890 }
9891
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009892 app.executingServices.clear();
9893 }
9894
9895 private final void removeDyingProviderLocked(ProcessRecord proc,
9896 ContentProviderRecord cpr) {
9897 synchronized (cpr) {
9898 cpr.launchingApp = null;
9899 cpr.notifyAll();
9900 }
9901
9902 mProvidersByClass.remove(cpr.info.name);
9903 String names[] = cpr.info.authority.split(";");
9904 for (int j = 0; j < names.length; j++) {
9905 mProvidersByName.remove(names[j]);
9906 }
9907
9908 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9909 while (cit.hasNext()) {
9910 ProcessRecord capp = cit.next();
9911 if (!capp.persistent && capp.thread != null
9912 && capp.pid != 0
9913 && capp.pid != MY_PID) {
9914 Log.i(TAG, "Killing app " + capp.processName
9915 + " (pid " + capp.pid
9916 + ") because provider " + cpr.info.name
9917 + " is in dying process " + proc.processName);
9918 Process.killProcess(capp.pid);
9919 }
9920 }
9921
9922 mLaunchingProviders.remove(cpr);
9923 }
9924
9925 /**
9926 * Main code for cleaning up a process when it has gone away. This is
9927 * called both as a result of the process dying, or directly when stopping
9928 * a process when running in single process mode.
9929 */
9930 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9931 boolean restarting, int index) {
9932 if (index >= 0) {
9933 mLRUProcesses.remove(index);
9934 }
9935
Dianne Hackborn36124872009-10-08 16:22:03 -07009936 mProcessesToGc.remove(app);
9937
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009938 // Dismiss any open dialogs.
9939 if (app.crashDialog != null) {
9940 app.crashDialog.dismiss();
9941 app.crashDialog = null;
9942 }
9943 if (app.anrDialog != null) {
9944 app.anrDialog.dismiss();
9945 app.anrDialog = null;
9946 }
9947 if (app.waitDialog != null) {
9948 app.waitDialog.dismiss();
9949 app.waitDialog = null;
9950 }
9951
9952 app.crashing = false;
9953 app.notResponding = false;
9954
9955 app.resetPackageList();
9956 app.thread = null;
9957 app.forcingToForeground = null;
9958 app.foregroundServices = false;
9959
9960 killServicesLocked(app, true);
9961
9962 boolean restart = false;
9963
9964 int NL = mLaunchingProviders.size();
9965
9966 // Remove published content providers.
9967 if (!app.pubProviders.isEmpty()) {
9968 Iterator it = app.pubProviders.values().iterator();
9969 while (it.hasNext()) {
9970 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9971 cpr.provider = null;
9972 cpr.app = null;
9973
9974 // See if someone is waiting for this provider... in which
9975 // case we don't remove it, but just let it restart.
9976 int i = 0;
9977 if (!app.bad) {
9978 for (; i<NL; i++) {
9979 if (mLaunchingProviders.get(i) == cpr) {
9980 restart = true;
9981 break;
9982 }
9983 }
9984 } else {
9985 i = NL;
9986 }
9987
9988 if (i >= NL) {
9989 removeDyingProviderLocked(app, cpr);
9990 NL = mLaunchingProviders.size();
9991 }
9992 }
9993 app.pubProviders.clear();
9994 }
9995
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009996 // Take care of any launching providers waiting for this process.
9997 if (checkAppInLaunchingProvidersLocked(app, false)) {
9998 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009999 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010001 // Unregister from connected content providers.
10002 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010003 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010004 while (it.hasNext()) {
10005 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10006 cpr.clients.remove(app);
10007 }
10008 app.conProviders.clear();
10009 }
10010
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010011 // At this point there may be remaining entries in mLaunchingProviders
10012 // where we were the only one waiting, so they are no longer of use.
10013 // Look for these and clean up if found.
10014 // XXX Commented out for now. Trying to figure out a way to reproduce
10015 // the actual situation to identify what is actually going on.
10016 if (false) {
10017 for (int i=0; i<NL; i++) {
10018 ContentProviderRecord cpr = (ContentProviderRecord)
10019 mLaunchingProviders.get(i);
10020 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10021 synchronized (cpr) {
10022 cpr.launchingApp = null;
10023 cpr.notifyAll();
10024 }
10025 }
10026 }
10027 }
10028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010029 skipCurrentReceiverLocked(app);
10030
10031 // Unregister any receivers.
10032 if (app.receivers.size() > 0) {
10033 Iterator<ReceiverList> it = app.receivers.iterator();
10034 while (it.hasNext()) {
10035 removeReceiverLocked(it.next());
10036 }
10037 app.receivers.clear();
10038 }
10039
Christopher Tate181fafa2009-05-14 11:12:14 -070010040 // If the app is undergoing backup, tell the backup manager about it
10041 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10042 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10043 try {
10044 IBackupManager bm = IBackupManager.Stub.asInterface(
10045 ServiceManager.getService(Context.BACKUP_SERVICE));
10046 bm.agentDisconnected(app.info.packageName);
10047 } catch (RemoteException e) {
10048 // can't happen; backup manager is local
10049 }
10050 }
10051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010052 // If the caller is restarting this app, then leave it in its
10053 // current lists and let the caller take care of it.
10054 if (restarting) {
10055 return;
10056 }
10057
10058 if (!app.persistent) {
10059 if (DEBUG_PROCESSES) Log.v(TAG,
10060 "Removing non-persistent process during cleanup: " + app);
10061 mProcessNames.remove(app.processName, app.info.uid);
10062 } else if (!app.removed) {
10063 // This app is persistent, so we need to keep its record around.
10064 // If it is not already on the pending app list, add it there
10065 // and start a new process for it.
10066 app.thread = null;
10067 app.forcingToForeground = null;
10068 app.foregroundServices = false;
10069 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10070 mPersistentStartingProcesses.add(app);
10071 restart = true;
10072 }
10073 }
10074 mProcessesOnHold.remove(app);
10075
The Android Open Source Project4df24232009-03-05 14:34:35 -080010076 if (app == mHomeProcess) {
10077 mHomeProcess = null;
10078 }
10079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010080 if (restart) {
10081 // We have components that still need to be running in the
10082 // process, so re-launch it.
10083 mProcessNames.put(app.processName, app.info.uid, app);
10084 startProcessLocked(app, "restart", app.processName);
10085 } else if (app.pid > 0 && app.pid != MY_PID) {
10086 // Goodbye!
10087 synchronized (mPidsSelfLocked) {
10088 mPidsSelfLocked.remove(app.pid);
10089 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10090 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010091 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010092 }
10093 }
10094
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010095 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10096 // Look through the content providers we are waiting to have launched,
10097 // and if any run in this process then either schedule a restart of
10098 // the process or kill the client waiting for it if this process has
10099 // gone bad.
10100 int NL = mLaunchingProviders.size();
10101 boolean restart = false;
10102 for (int i=0; i<NL; i++) {
10103 ContentProviderRecord cpr = (ContentProviderRecord)
10104 mLaunchingProviders.get(i);
10105 if (cpr.launchingApp == app) {
10106 if (!alwaysBad && !app.bad) {
10107 restart = true;
10108 } else {
10109 removeDyingProviderLocked(app, cpr);
10110 NL = mLaunchingProviders.size();
10111 }
10112 }
10113 }
10114 return restart;
10115 }
10116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010117 // =========================================================
10118 // SERVICES
10119 // =========================================================
10120
10121 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10122 ActivityManager.RunningServiceInfo info =
10123 new ActivityManager.RunningServiceInfo();
10124 info.service = r.name;
10125 if (r.app != null) {
10126 info.pid = r.app.pid;
10127 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010128 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010129 info.process = r.processName;
10130 info.foreground = r.isForeground;
10131 info.activeSince = r.createTime;
10132 info.started = r.startRequested;
10133 info.clientCount = r.connections.size();
10134 info.crashCount = r.crashCount;
10135 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010136 if (r.isForeground) {
10137 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10138 }
10139 if (r.startRequested) {
10140 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10141 }
10142 if (r.app != null && r.app.pid == Process.myPid()) {
10143 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10144 }
10145 if (r.app != null && r.app.persistent) {
10146 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10147 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010148 for (ConnectionRecord conn : r.connections.values()) {
10149 if (conn.clientLabel != 0) {
10150 info.clientPackage = conn.binding.client.info.packageName;
10151 info.clientLabel = conn.clientLabel;
10152 break;
10153 }
10154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010155 return info;
10156 }
10157
10158 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10159 int flags) {
10160 synchronized (this) {
10161 ArrayList<ActivityManager.RunningServiceInfo> res
10162 = new ArrayList<ActivityManager.RunningServiceInfo>();
10163
10164 if (mServices.size() > 0) {
10165 Iterator<ServiceRecord> it = mServices.values().iterator();
10166 while (it.hasNext() && res.size() < maxNum) {
10167 res.add(makeRunningServiceInfoLocked(it.next()));
10168 }
10169 }
10170
10171 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10172 ServiceRecord r = mRestartingServices.get(i);
10173 ActivityManager.RunningServiceInfo info =
10174 makeRunningServiceInfoLocked(r);
10175 info.restarting = r.nextRestartTime;
10176 res.add(info);
10177 }
10178
10179 return res;
10180 }
10181 }
10182
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010183 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10184 synchronized (this) {
10185 ServiceRecord r = mServices.get(name);
10186 if (r != null) {
10187 for (ConnectionRecord conn : r.connections.values()) {
10188 if (conn.clientIntent != null) {
10189 return conn.clientIntent;
10190 }
10191 }
10192 }
10193 }
10194 return null;
10195 }
10196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010197 private final ServiceRecord findServiceLocked(ComponentName name,
10198 IBinder token) {
10199 ServiceRecord r = mServices.get(name);
10200 return r == token ? r : null;
10201 }
10202
10203 private final class ServiceLookupResult {
10204 final ServiceRecord record;
10205 final String permission;
10206
10207 ServiceLookupResult(ServiceRecord _record, String _permission) {
10208 record = _record;
10209 permission = _permission;
10210 }
10211 };
10212
10213 private ServiceLookupResult findServiceLocked(Intent service,
10214 String resolvedType) {
10215 ServiceRecord r = null;
10216 if (service.getComponent() != null) {
10217 r = mServices.get(service.getComponent());
10218 }
10219 if (r == null) {
10220 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10221 r = mServicesByIntent.get(filter);
10222 }
10223
10224 if (r == null) {
10225 try {
10226 ResolveInfo rInfo =
10227 ActivityThread.getPackageManager().resolveService(
10228 service, resolvedType, 0);
10229 ServiceInfo sInfo =
10230 rInfo != null ? rInfo.serviceInfo : null;
10231 if (sInfo == null) {
10232 return null;
10233 }
10234
10235 ComponentName name = new ComponentName(
10236 sInfo.applicationInfo.packageName, sInfo.name);
10237 r = mServices.get(name);
10238 } catch (RemoteException ex) {
10239 // pm is in same process, this will never happen.
10240 }
10241 }
10242 if (r != null) {
10243 int callingPid = Binder.getCallingPid();
10244 int callingUid = Binder.getCallingUid();
10245 if (checkComponentPermission(r.permission,
10246 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10247 != PackageManager.PERMISSION_GRANTED) {
10248 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10249 + " from pid=" + callingPid
10250 + ", uid=" + callingUid
10251 + " requires " + r.permission);
10252 return new ServiceLookupResult(null, r.permission);
10253 }
10254 return new ServiceLookupResult(r, null);
10255 }
10256 return null;
10257 }
10258
10259 private class ServiceRestarter implements Runnable {
10260 private ServiceRecord mService;
10261
10262 void setService(ServiceRecord service) {
10263 mService = service;
10264 }
10265
10266 public void run() {
10267 synchronized(ActivityManagerService.this) {
10268 performServiceRestartLocked(mService);
10269 }
10270 }
10271 }
10272
10273 private ServiceLookupResult retrieveServiceLocked(Intent service,
10274 String resolvedType, int callingPid, int callingUid) {
10275 ServiceRecord r = null;
10276 if (service.getComponent() != null) {
10277 r = mServices.get(service.getComponent());
10278 }
10279 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10280 r = mServicesByIntent.get(filter);
10281 if (r == null) {
10282 try {
10283 ResolveInfo rInfo =
10284 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010285 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010286 ServiceInfo sInfo =
10287 rInfo != null ? rInfo.serviceInfo : null;
10288 if (sInfo == null) {
10289 Log.w(TAG, "Unable to start service " + service +
10290 ": not found");
10291 return null;
10292 }
10293
10294 ComponentName name = new ComponentName(
10295 sInfo.applicationInfo.packageName, sInfo.name);
10296 r = mServices.get(name);
10297 if (r == null) {
10298 filter = new Intent.FilterComparison(service.cloneFilter());
10299 ServiceRestarter res = new ServiceRestarter();
10300 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10301 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10302 synchronized (stats) {
10303 ss = stats.getServiceStatsLocked(
10304 sInfo.applicationInfo.uid, sInfo.packageName,
10305 sInfo.name);
10306 }
Dianne Hackbornb1c4a2a2010-01-19 15:36:42 -080010307 r = new ServiceRecord(this, ss, name, filter, sInfo, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010308 res.setService(r);
10309 mServices.put(name, r);
10310 mServicesByIntent.put(filter, r);
10311
10312 // Make sure this component isn't in the pending list.
10313 int N = mPendingServices.size();
10314 for (int i=0; i<N; i++) {
10315 ServiceRecord pr = mPendingServices.get(i);
10316 if (pr.name.equals(name)) {
10317 mPendingServices.remove(i);
10318 i--;
10319 N--;
10320 }
10321 }
10322 }
10323 } catch (RemoteException ex) {
10324 // pm is in same process, this will never happen.
10325 }
10326 }
10327 if (r != null) {
10328 if (checkComponentPermission(r.permission,
10329 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10330 != PackageManager.PERMISSION_GRANTED) {
10331 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10332 + " from pid=" + Binder.getCallingPid()
10333 + ", uid=" + Binder.getCallingUid()
10334 + " requires " + r.permission);
10335 return new ServiceLookupResult(null, r.permission);
10336 }
10337 return new ServiceLookupResult(r, null);
10338 }
10339 return null;
10340 }
10341
10342 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10343 long now = SystemClock.uptimeMillis();
10344 if (r.executeNesting == 0 && r.app != null) {
10345 if (r.app.executingServices.size() == 0) {
10346 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10347 msg.obj = r.app;
10348 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10349 }
10350 r.app.executingServices.add(r);
10351 }
10352 r.executeNesting++;
10353 r.executingStart = now;
10354 }
10355
10356 private final void sendServiceArgsLocked(ServiceRecord r,
10357 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010358 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010359 if (N == 0) {
10360 return;
10361 }
10362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010363 int i = 0;
10364 while (i < N) {
10365 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010366 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010367 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010368 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010369 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010370 // If somehow we got a dummy start at the front, then
10371 // just drop it here.
10372 i++;
10373 continue;
10374 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010375 bumpServiceExecutingLocked(r);
10376 if (!oomAdjusted) {
10377 oomAdjusted = true;
10378 updateOomAdjLocked(r.app);
10379 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010380 int flags = 0;
10381 if (si.deliveryCount > 0) {
10382 flags |= Service.START_FLAG_RETRY;
10383 }
10384 if (si.doneExecutingCount > 0) {
10385 flags |= Service.START_FLAG_REDELIVERY;
10386 }
10387 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10388 si.deliveredTime = SystemClock.uptimeMillis();
10389 r.deliveredStarts.add(si);
10390 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010391 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010392 } catch (RemoteException e) {
10393 // Remote process gone... we'll let the normal cleanup take
10394 // care of this.
10395 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010396 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010397 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010398 break;
10399 }
10400 }
10401 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010402 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010403 } else {
10404 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010405 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010406 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010407 }
10408 }
10409 }
10410
10411 private final boolean requestServiceBindingLocked(ServiceRecord r,
10412 IntentBindRecord i, boolean rebind) {
10413 if (r.app == null || r.app.thread == null) {
10414 // If service is not currently running, can't yet bind.
10415 return false;
10416 }
10417 if ((!i.requested || rebind) && i.apps.size() > 0) {
10418 try {
10419 bumpServiceExecutingLocked(r);
10420 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10421 + ": shouldUnbind=" + i.hasBound);
10422 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10423 if (!rebind) {
10424 i.requested = true;
10425 }
10426 i.hasBound = true;
10427 i.doRebind = false;
10428 } catch (RemoteException e) {
10429 return false;
10430 }
10431 }
10432 return true;
10433 }
10434
10435 private final void requestServiceBindingsLocked(ServiceRecord r) {
10436 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10437 while (bindings.hasNext()) {
10438 IntentBindRecord i = bindings.next();
10439 if (!requestServiceBindingLocked(r, i, false)) {
10440 break;
10441 }
10442 }
10443 }
10444
10445 private final void realStartServiceLocked(ServiceRecord r,
10446 ProcessRecord app) throws RemoteException {
10447 if (app.thread == null) {
10448 throw new RemoteException();
10449 }
10450
10451 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010452 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010453
10454 app.services.add(r);
10455 bumpServiceExecutingLocked(r);
10456 updateLRUListLocked(app, true);
10457
10458 boolean created = false;
10459 try {
10460 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10461 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010462 mStringBuilder.setLength(0);
10463 r.intent.getIntent().toShortString(mStringBuilder, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010464 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10465 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010466 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010467 synchronized (r.stats.getBatteryStats()) {
10468 r.stats.startLaunchedLocked();
10469 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010470 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010471 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010472 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010473 created = true;
10474 } finally {
10475 if (!created) {
10476 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010477 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010478 }
10479 }
10480
10481 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010482
10483 // If the service is in the started state, and there are no
10484 // pending arguments, then fake up one so its onStartCommand() will
10485 // be called.
10486 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10487 r.lastStartId++;
10488 if (r.lastStartId < 1) {
10489 r.lastStartId = 1;
10490 }
10491 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10492 }
10493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010494 sendServiceArgsLocked(r, true);
10495 }
10496
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010497 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10498 boolean allowCancel) {
10499 boolean canceled = false;
10500
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010501 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010502 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010503 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010504
10505 // Any delivered but not yet finished starts should be put back
10506 // on the pending list.
10507 final int N = r.deliveredStarts.size();
10508 if (N > 0) {
10509 for (int i=N-1; i>=0; i--) {
10510 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10511 if (si.intent == null) {
10512 // We'll generate this again if needed.
10513 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10514 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10515 r.pendingStarts.add(0, si);
10516 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10517 dur *= 2;
10518 if (minDuration < dur) minDuration = dur;
10519 if (resetTime < dur) resetTime = dur;
10520 } else {
10521 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10522 + r.name);
10523 canceled = true;
10524 }
10525 }
10526 r.deliveredStarts.clear();
10527 }
10528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010529 r.totalRestartCount++;
10530 if (r.restartDelay == 0) {
10531 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010532 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010533 } else {
10534 // If it has been a "reasonably long time" since the service
10535 // was started, then reset our restart duration back to
10536 // the beginning, so we don't infinitely increase the duration
10537 // on a service that just occasionally gets killed (which is
10538 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010539 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010540 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010541 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010542 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010543 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010544 if (r.restartDelay < minDuration) {
10545 r.restartDelay = minDuration;
10546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010547 }
10548 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010549
10550 r.nextRestartTime = now + r.restartDelay;
10551
10552 // Make sure that we don't end up restarting a bunch of services
10553 // all at the same time.
10554 boolean repeat;
10555 do {
10556 repeat = false;
10557 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10558 ServiceRecord r2 = mRestartingServices.get(i);
10559 if (r2 != r && r.nextRestartTime
10560 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10561 && r.nextRestartTime
10562 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10563 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10564 r.restartDelay = r.nextRestartTime - now;
10565 repeat = true;
10566 break;
10567 }
10568 }
10569 } while (repeat);
10570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010571 if (!mRestartingServices.contains(r)) {
10572 mRestartingServices.add(r);
10573 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010574
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010575 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010577 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010578 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010579 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10580 Log.w(TAG, "Scheduling restart of crashed service "
10581 + r.shortName + " in " + r.restartDelay + "ms");
10582 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10583 r.shortName, r.restartDelay);
10584
10585 Message msg = Message.obtain();
10586 msg.what = SERVICE_ERROR_MSG;
10587 msg.obj = r;
10588 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010589
10590 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010591 }
10592
10593 final void performServiceRestartLocked(ServiceRecord r) {
10594 if (!mRestartingServices.contains(r)) {
10595 return;
10596 }
10597 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10598 }
10599
10600 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10601 if (r.restartDelay == 0) {
10602 return false;
10603 }
10604 r.resetRestartCounter();
10605 mRestartingServices.remove(r);
10606 mHandler.removeCallbacks(r.restarter);
10607 return true;
10608 }
10609
10610 private final boolean bringUpServiceLocked(ServiceRecord r,
10611 int intentFlags, boolean whileRestarting) {
10612 //Log.i(TAG, "Bring up service:");
10613 //r.dump(" ");
10614
Dianne Hackborn36124872009-10-08 16:22:03 -070010615 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010616 sendServiceArgsLocked(r, false);
10617 return true;
10618 }
10619
10620 if (!whileRestarting && r.restartDelay > 0) {
10621 // If waiting for a restart, then do nothing.
10622 return true;
10623 }
10624
10625 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10626 + " " + r.intent);
10627
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010628 // We are now bringing the service up, so no longer in the
10629 // restarting state.
10630 mRestartingServices.remove(r);
10631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010632 final String appName = r.processName;
10633 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10634 if (app != null && app.thread != null) {
10635 try {
10636 realStartServiceLocked(r, app);
10637 return true;
10638 } catch (RemoteException e) {
10639 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10640 }
10641
10642 // If a dead object exception was thrown -- fall through to
10643 // restart the application.
10644 }
10645
Dianne Hackborn36124872009-10-08 16:22:03 -070010646 // Not running -- get it started, and enqueue this service record
10647 // to be executed when the app comes up.
10648 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10649 "service", r.name, false) == null) {
10650 Log.w(TAG, "Unable to launch app "
10651 + r.appInfo.packageName + "/"
10652 + r.appInfo.uid + " for service "
10653 + r.intent.getIntent() + ": process is bad");
10654 bringDownServiceLocked(r, true);
10655 return false;
10656 }
10657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010658 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010659 mPendingServices.add(r);
10660 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010662 return true;
10663 }
10664
10665 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10666 //Log.i(TAG, "Bring down service:");
10667 //r.dump(" ");
10668
10669 // Does it still need to run?
10670 if (!force && r.startRequested) {
10671 return;
10672 }
10673 if (r.connections.size() > 0) {
10674 if (!force) {
10675 // XXX should probably keep a count of the number of auto-create
10676 // connections directly in the service.
10677 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10678 while (it.hasNext()) {
10679 ConnectionRecord cr = it.next();
10680 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10681 return;
10682 }
10683 }
10684 }
10685
10686 // Report to all of the connections that the service is no longer
10687 // available.
10688 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10689 while (it.hasNext()) {
10690 ConnectionRecord c = it.next();
10691 try {
10692 // todo: shouldn't be a synchronous call!
10693 c.conn.connected(r.name, null);
10694 } catch (Exception e) {
10695 Log.w(TAG, "Failure disconnecting service " + r.name +
10696 " to connection " + c.conn.asBinder() +
10697 " (in " + c.binding.client.processName + ")", e);
10698 }
10699 }
10700 }
10701
10702 // Tell the service that it has been unbound.
10703 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10704 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10705 while (it.hasNext()) {
10706 IntentBindRecord ibr = it.next();
10707 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10708 + ": hasBound=" + ibr.hasBound);
10709 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10710 try {
10711 bumpServiceExecutingLocked(r);
10712 updateOomAdjLocked(r.app);
10713 ibr.hasBound = false;
10714 r.app.thread.scheduleUnbindService(r,
10715 ibr.intent.getIntent());
10716 } catch (Exception e) {
10717 Log.w(TAG, "Exception when unbinding service "
10718 + r.shortName, e);
10719 serviceDoneExecutingLocked(r, true);
10720 }
10721 }
10722 }
10723 }
10724
10725 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10726 + " " + r.intent);
10727 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10728 System.identityHashCode(r), r.shortName,
10729 (r.app != null) ? r.app.pid : -1);
10730
10731 mServices.remove(r.name);
10732 mServicesByIntent.remove(r.intent);
10733 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10734 r.totalRestartCount = 0;
10735 unscheduleServiceRestartLocked(r);
10736
10737 // Also make sure it is not on the pending list.
10738 int N = mPendingServices.size();
10739 for (int i=0; i<N; i++) {
10740 if (mPendingServices.get(i) == r) {
10741 mPendingServices.remove(i);
10742 if (DEBUG_SERVICE) Log.v(
10743 TAG, "Removed pending service: " + r.shortName);
10744 i--;
10745 N--;
10746 }
10747 }
10748
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010749 r.cancelNotification();
10750 r.isForeground = false;
10751 r.foregroundId = 0;
10752 r.foregroundNoti = null;
10753
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010754 // Clear start entries.
10755 r.deliveredStarts.clear();
10756 r.pendingStarts.clear();
10757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010758 if (r.app != null) {
10759 synchronized (r.stats.getBatteryStats()) {
10760 r.stats.stopLaunchedLocked();
10761 }
10762 r.app.services.remove(r);
10763 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010764 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010765 if (DEBUG_SERVICE) Log.v(TAG,
10766 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010767 bumpServiceExecutingLocked(r);
10768 mStoppingServices.add(r);
10769 updateOomAdjLocked(r.app);
10770 r.app.thread.scheduleStopService(r);
10771 } catch (Exception e) {
10772 Log.w(TAG, "Exception when stopping service "
10773 + r.shortName, e);
10774 serviceDoneExecutingLocked(r, true);
10775 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010776 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010777 } else {
10778 if (DEBUG_SERVICE) Log.v(
10779 TAG, "Removed service that has no process: " + r.shortName);
10780 }
10781 } else {
10782 if (DEBUG_SERVICE) Log.v(
10783 TAG, "Removed service that is not running: " + r.shortName);
10784 }
10785 }
10786
10787 ComponentName startServiceLocked(IApplicationThread caller,
10788 Intent service, String resolvedType,
10789 int callingPid, int callingUid) {
10790 synchronized(this) {
10791 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10792 + " type=" + resolvedType + " args=" + service.getExtras());
10793
10794 if (caller != null) {
10795 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10796 if (callerApp == null) {
10797 throw new SecurityException(
10798 "Unable to find app for caller " + caller
10799 + " (pid=" + Binder.getCallingPid()
10800 + ") when starting service " + service);
10801 }
10802 }
10803
10804 ServiceLookupResult res =
10805 retrieveServiceLocked(service, resolvedType,
10806 callingPid, callingUid);
10807 if (res == null) {
10808 return null;
10809 }
10810 if (res.record == null) {
10811 return new ComponentName("!", res.permission != null
10812 ? res.permission : "private to package");
10813 }
10814 ServiceRecord r = res.record;
10815 if (unscheduleServiceRestartLocked(r)) {
10816 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10817 + r.shortName);
10818 }
10819 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010820 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010821 r.lastStartId++;
10822 if (r.lastStartId < 1) {
10823 r.lastStartId = 1;
10824 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010825 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010826 r.lastActivity = SystemClock.uptimeMillis();
10827 synchronized (r.stats.getBatteryStats()) {
10828 r.stats.startRunningLocked();
10829 }
10830 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10831 return new ComponentName("!", "Service process is bad");
10832 }
10833 return r.name;
10834 }
10835 }
10836
10837 public ComponentName startService(IApplicationThread caller, Intent service,
10838 String resolvedType) {
10839 // Refuse possible leaked file descriptors
10840 if (service != null && service.hasFileDescriptors() == true) {
10841 throw new IllegalArgumentException("File descriptors passed in Intent");
10842 }
10843
10844 synchronized(this) {
10845 final int callingPid = Binder.getCallingPid();
10846 final int callingUid = Binder.getCallingUid();
10847 final long origId = Binder.clearCallingIdentity();
10848 ComponentName res = startServiceLocked(caller, service,
10849 resolvedType, callingPid, callingUid);
10850 Binder.restoreCallingIdentity(origId);
10851 return res;
10852 }
10853 }
10854
10855 ComponentName startServiceInPackage(int uid,
10856 Intent service, String resolvedType) {
10857 synchronized(this) {
10858 final long origId = Binder.clearCallingIdentity();
10859 ComponentName res = startServiceLocked(null, service,
10860 resolvedType, -1, uid);
10861 Binder.restoreCallingIdentity(origId);
10862 return res;
10863 }
10864 }
10865
10866 public int stopService(IApplicationThread caller, Intent service,
10867 String resolvedType) {
10868 // Refuse possible leaked file descriptors
10869 if (service != null && service.hasFileDescriptors() == true) {
10870 throw new IllegalArgumentException("File descriptors passed in Intent");
10871 }
10872
10873 synchronized(this) {
10874 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10875 + " type=" + resolvedType);
10876
10877 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10878 if (caller != null && callerApp == null) {
10879 throw new SecurityException(
10880 "Unable to find app for caller " + caller
10881 + " (pid=" + Binder.getCallingPid()
10882 + ") when stopping service " + service);
10883 }
10884
10885 // If this service is active, make sure it is stopped.
10886 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10887 if (r != null) {
10888 if (r.record != null) {
10889 synchronized (r.record.stats.getBatteryStats()) {
10890 r.record.stats.stopRunningLocked();
10891 }
10892 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010893 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010894 final long origId = Binder.clearCallingIdentity();
10895 bringDownServiceLocked(r.record, false);
10896 Binder.restoreCallingIdentity(origId);
10897 return 1;
10898 }
10899 return -1;
10900 }
10901 }
10902
10903 return 0;
10904 }
10905
10906 public IBinder peekService(Intent service, String resolvedType) {
10907 // Refuse possible leaked file descriptors
10908 if (service != null && service.hasFileDescriptors() == true) {
10909 throw new IllegalArgumentException("File descriptors passed in Intent");
10910 }
10911
10912 IBinder ret = null;
10913
10914 synchronized(this) {
10915 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10916
10917 if (r != null) {
10918 // r.record is null if findServiceLocked() failed the caller permission check
10919 if (r.record == null) {
10920 throw new SecurityException(
10921 "Permission Denial: Accessing service " + r.record.name
10922 + " from pid=" + Binder.getCallingPid()
10923 + ", uid=" + Binder.getCallingUid()
10924 + " requires " + r.permission);
10925 }
10926 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10927 if (ib != null) {
10928 ret = ib.binder;
10929 }
10930 }
10931 }
10932
10933 return ret;
10934 }
10935
10936 public boolean stopServiceToken(ComponentName className, IBinder token,
10937 int startId) {
10938 synchronized(this) {
10939 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10940 + " " + token + " startId=" + startId);
10941 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010942 if (r != null) {
10943 if (startId >= 0) {
10944 // Asked to only stop if done with all work. Note that
10945 // to avoid leaks, we will take this as dropping all
10946 // start items up to and including this one.
10947 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10948 if (si != null) {
10949 while (r.deliveredStarts.size() > 0) {
10950 if (r.deliveredStarts.remove(0) == si) {
10951 break;
10952 }
10953 }
10954 }
10955
10956 if (r.lastStartId != startId) {
10957 return false;
10958 }
10959
10960 if (r.deliveredStarts.size() > 0) {
10961 Log.w(TAG, "stopServiceToken startId " + startId
10962 + " is last, but have " + r.deliveredStarts.size()
10963 + " remaining args");
10964 }
10965 }
10966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010967 synchronized (r.stats.getBatteryStats()) {
10968 r.stats.stopRunningLocked();
10969 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010970 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010971 }
10972 final long origId = Binder.clearCallingIdentity();
10973 bringDownServiceLocked(r, false);
10974 Binder.restoreCallingIdentity(origId);
10975 return true;
10976 }
10977 }
10978 return false;
10979 }
10980
10981 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010982 int id, Notification notification, boolean removeNotification) {
10983 final long origId = Binder.clearCallingIdentity();
10984 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010985 synchronized(this) {
10986 ServiceRecord r = findServiceLocked(className, token);
10987 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010988 if (id != 0) {
10989 if (notification == null) {
10990 throw new IllegalArgumentException("null notification");
10991 }
10992 if (r.foregroundId != id) {
10993 r.cancelNotification();
10994 r.foregroundId = id;
10995 }
10996 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10997 r.foregroundNoti = notification;
10998 r.isForeground = true;
10999 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011000 if (r.app != null) {
11001 updateServiceForegroundLocked(r.app, true);
11002 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011003 } else {
11004 if (r.isForeground) {
11005 r.isForeground = false;
11006 if (r.app != null) {
11007 updateServiceForegroundLocked(r.app, true);
11008 }
11009 }
11010 if (removeNotification) {
11011 r.cancelNotification();
11012 r.foregroundId = 0;
11013 r.foregroundNoti = null;
11014 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011015 }
11016 }
11017 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011018 } finally {
11019 Binder.restoreCallingIdentity(origId);
11020 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011021 }
11022
11023 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11024 boolean anyForeground = false;
11025 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11026 if (sr.isForeground) {
11027 anyForeground = true;
11028 break;
11029 }
11030 }
11031 if (anyForeground != proc.foregroundServices) {
11032 proc.foregroundServices = anyForeground;
11033 if (oomAdj) {
11034 updateOomAdjLocked();
11035 }
11036 }
11037 }
11038
11039 public int bindService(IApplicationThread caller, IBinder token,
11040 Intent service, String resolvedType,
11041 IServiceConnection connection, int flags) {
11042 // Refuse possible leaked file descriptors
11043 if (service != null && service.hasFileDescriptors() == true) {
11044 throw new IllegalArgumentException("File descriptors passed in Intent");
11045 }
11046
11047 synchronized(this) {
11048 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11049 + " type=" + resolvedType + " conn=" + connection.asBinder()
11050 + " flags=0x" + Integer.toHexString(flags));
11051 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11052 if (callerApp == null) {
11053 throw new SecurityException(
11054 "Unable to find app for caller " + caller
11055 + " (pid=" + Binder.getCallingPid()
11056 + ") when binding service " + service);
11057 }
11058
11059 HistoryRecord activity = null;
11060 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011061 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011062 if (aindex < 0) {
11063 Log.w(TAG, "Binding with unknown activity: " + token);
11064 return 0;
11065 }
11066 activity = (HistoryRecord)mHistory.get(aindex);
11067 }
11068
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011069 int clientLabel = 0;
11070 PendingIntent clientIntent = null;
11071
11072 if (callerApp.info.uid == Process.SYSTEM_UID) {
11073 // Hacky kind of thing -- allow system stuff to tell us
11074 // what they are, so we can report this elsewhere for
11075 // others to know why certain services are running.
11076 try {
11077 clientIntent = (PendingIntent)service.getParcelableExtra(
11078 Intent.EXTRA_CLIENT_INTENT);
11079 } catch (RuntimeException e) {
11080 }
11081 if (clientIntent != null) {
11082 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11083 if (clientLabel != 0) {
11084 // There are no useful extras in the intent, trash them.
11085 // System code calling with this stuff just needs to know
11086 // this will happen.
11087 service = service.cloneFilter();
11088 }
11089 }
11090 }
11091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011092 ServiceLookupResult res =
11093 retrieveServiceLocked(service, resolvedType,
11094 Binder.getCallingPid(), Binder.getCallingUid());
11095 if (res == null) {
11096 return 0;
11097 }
11098 if (res.record == null) {
11099 return -1;
11100 }
11101 ServiceRecord s = res.record;
11102
11103 final long origId = Binder.clearCallingIdentity();
11104
11105 if (unscheduleServiceRestartLocked(s)) {
11106 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11107 + s.shortName);
11108 }
11109
11110 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11111 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011112 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011113
11114 IBinder binder = connection.asBinder();
11115 s.connections.put(binder, c);
11116 b.connections.add(c);
11117 if (activity != null) {
11118 if (activity.connections == null) {
11119 activity.connections = new HashSet<ConnectionRecord>();
11120 }
11121 activity.connections.add(c);
11122 }
11123 b.client.connections.add(c);
11124 mServiceConnections.put(binder, c);
11125
11126 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11127 s.lastActivity = SystemClock.uptimeMillis();
11128 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11129 return 0;
11130 }
11131 }
11132
11133 if (s.app != null) {
11134 // This could have made the service more important.
11135 updateOomAdjLocked(s.app);
11136 }
11137
11138 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11139 + ": received=" + b.intent.received
11140 + " apps=" + b.intent.apps.size()
11141 + " doRebind=" + b.intent.doRebind);
11142
11143 if (s.app != null && b.intent.received) {
11144 // Service is already running, so we can immediately
11145 // publish the connection.
11146 try {
11147 c.conn.connected(s.name, b.intent.binder);
11148 } catch (Exception e) {
11149 Log.w(TAG, "Failure sending service " + s.shortName
11150 + " to connection " + c.conn.asBinder()
11151 + " (in " + c.binding.client.processName + ")", e);
11152 }
11153
11154 // If this is the first app connected back to this binding,
11155 // and the service had previously asked to be told when
11156 // rebound, then do so.
11157 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11158 requestServiceBindingLocked(s, b.intent, true);
11159 }
11160 } else if (!b.intent.requested) {
11161 requestServiceBindingLocked(s, b.intent, false);
11162 }
11163
11164 Binder.restoreCallingIdentity(origId);
11165 }
11166
11167 return 1;
11168 }
11169
11170 private void removeConnectionLocked(
11171 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11172 IBinder binder = c.conn.asBinder();
11173 AppBindRecord b = c.binding;
11174 ServiceRecord s = b.service;
11175 s.connections.remove(binder);
11176 b.connections.remove(c);
11177 if (c.activity != null && c.activity != skipAct) {
11178 if (c.activity.connections != null) {
11179 c.activity.connections.remove(c);
11180 }
11181 }
11182 if (b.client != skipApp) {
11183 b.client.connections.remove(c);
11184 }
11185 mServiceConnections.remove(binder);
11186
11187 if (b.connections.size() == 0) {
11188 b.intent.apps.remove(b.client);
11189 }
11190
11191 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11192 + ": shouldUnbind=" + b.intent.hasBound);
11193 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11194 && b.intent.hasBound) {
11195 try {
11196 bumpServiceExecutingLocked(s);
11197 updateOomAdjLocked(s.app);
11198 b.intent.hasBound = false;
11199 // Assume the client doesn't want to know about a rebind;
11200 // we will deal with that later if it asks for one.
11201 b.intent.doRebind = false;
11202 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11203 } catch (Exception e) {
11204 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11205 serviceDoneExecutingLocked(s, true);
11206 }
11207 }
11208
11209 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11210 bringDownServiceLocked(s, false);
11211 }
11212 }
11213
11214 public boolean unbindService(IServiceConnection connection) {
11215 synchronized (this) {
11216 IBinder binder = connection.asBinder();
11217 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11218 ConnectionRecord r = mServiceConnections.get(binder);
11219 if (r == null) {
11220 Log.w(TAG, "Unbind failed: could not find connection for "
11221 + connection.asBinder());
11222 return false;
11223 }
11224
11225 final long origId = Binder.clearCallingIdentity();
11226
11227 removeConnectionLocked(r, null, null);
11228
11229 if (r.binding.service.app != null) {
11230 // This could have made the service less important.
11231 updateOomAdjLocked(r.binding.service.app);
11232 }
11233
11234 Binder.restoreCallingIdentity(origId);
11235 }
11236
11237 return true;
11238 }
11239
11240 public void publishService(IBinder token, Intent intent, IBinder service) {
11241 // Refuse possible leaked file descriptors
11242 if (intent != null && intent.hasFileDescriptors() == true) {
11243 throw new IllegalArgumentException("File descriptors passed in Intent");
11244 }
11245
11246 synchronized(this) {
11247 if (!(token instanceof ServiceRecord)) {
11248 throw new IllegalArgumentException("Invalid service token");
11249 }
11250 ServiceRecord r = (ServiceRecord)token;
11251
11252 final long origId = Binder.clearCallingIdentity();
11253
11254 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11255 + " " + intent + ": " + service);
11256 if (r != null) {
11257 Intent.FilterComparison filter
11258 = new Intent.FilterComparison(intent);
11259 IntentBindRecord b = r.bindings.get(filter);
11260 if (b != null && !b.received) {
11261 b.binder = service;
11262 b.requested = true;
11263 b.received = true;
11264 if (r.connections.size() > 0) {
11265 Iterator<ConnectionRecord> it
11266 = r.connections.values().iterator();
11267 while (it.hasNext()) {
11268 ConnectionRecord c = it.next();
11269 if (!filter.equals(c.binding.intent.intent)) {
11270 if (DEBUG_SERVICE) Log.v(
11271 TAG, "Not publishing to: " + c);
11272 if (DEBUG_SERVICE) Log.v(
11273 TAG, "Bound intent: " + c.binding.intent.intent);
11274 if (DEBUG_SERVICE) Log.v(
11275 TAG, "Published intent: " + intent);
11276 continue;
11277 }
11278 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11279 try {
11280 c.conn.connected(r.name, service);
11281 } catch (Exception e) {
11282 Log.w(TAG, "Failure sending service " + r.name +
11283 " to connection " + c.conn.asBinder() +
11284 " (in " + c.binding.client.processName + ")", e);
11285 }
11286 }
11287 }
11288 }
11289
11290 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11291
11292 Binder.restoreCallingIdentity(origId);
11293 }
11294 }
11295 }
11296
11297 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11298 // Refuse possible leaked file descriptors
11299 if (intent != null && intent.hasFileDescriptors() == true) {
11300 throw new IllegalArgumentException("File descriptors passed in Intent");
11301 }
11302
11303 synchronized(this) {
11304 if (!(token instanceof ServiceRecord)) {
11305 throw new IllegalArgumentException("Invalid service token");
11306 }
11307 ServiceRecord r = (ServiceRecord)token;
11308
11309 final long origId = Binder.clearCallingIdentity();
11310
11311 if (r != null) {
11312 Intent.FilterComparison filter
11313 = new Intent.FilterComparison(intent);
11314 IntentBindRecord b = r.bindings.get(filter);
11315 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11316 + " at " + b + ": apps="
11317 + (b != null ? b.apps.size() : 0));
11318 if (b != null) {
11319 if (b.apps.size() > 0) {
11320 // Applications have already bound since the last
11321 // unbind, so just rebind right here.
11322 requestServiceBindingLocked(r, b, true);
11323 } else {
11324 // Note to tell the service the next time there is
11325 // a new client.
11326 b.doRebind = true;
11327 }
11328 }
11329
11330 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11331
11332 Binder.restoreCallingIdentity(origId);
11333 }
11334 }
11335 }
11336
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011337 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011338 synchronized(this) {
11339 if (!(token instanceof ServiceRecord)) {
11340 throw new IllegalArgumentException("Invalid service token");
11341 }
11342 ServiceRecord r = (ServiceRecord)token;
11343 boolean inStopping = mStoppingServices.contains(token);
11344 if (r != null) {
11345 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11346 + ": nesting=" + r.executeNesting
11347 + ", inStopping=" + inStopping);
11348 if (r != token) {
11349 Log.w(TAG, "Done executing service " + r.name
11350 + " with incorrect token: given " + token
11351 + ", expected " + r);
11352 return;
11353 }
11354
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011355 if (type == 1) {
11356 // This is a call from a service start... take care of
11357 // book-keeping.
11358 r.callStart = true;
11359 switch (res) {
11360 case Service.START_STICKY_COMPATIBILITY:
11361 case Service.START_STICKY: {
11362 // We are done with the associated start arguments.
11363 r.findDeliveredStart(startId, true);
11364 // Don't stop if killed.
11365 r.stopIfKilled = false;
11366 break;
11367 }
11368 case Service.START_NOT_STICKY: {
11369 // We are done with the associated start arguments.
11370 r.findDeliveredStart(startId, true);
11371 if (r.lastStartId == startId) {
11372 // There is no more work, and this service
11373 // doesn't want to hang around if killed.
11374 r.stopIfKilled = true;
11375 }
11376 break;
11377 }
11378 case Service.START_REDELIVER_INTENT: {
11379 // We'll keep this item until they explicitly
11380 // call stop for it, but keep track of the fact
11381 // that it was delivered.
11382 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11383 if (si != null) {
11384 si.deliveryCount = 0;
11385 si.doneExecutingCount++;
11386 // Don't stop if killed.
11387 r.stopIfKilled = true;
11388 }
11389 break;
11390 }
11391 default:
11392 throw new IllegalArgumentException(
11393 "Unknown service start result: " + res);
11394 }
11395 if (res == Service.START_STICKY_COMPATIBILITY) {
11396 r.callStart = false;
11397 }
11398 }
11399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011400 final long origId = Binder.clearCallingIdentity();
11401 serviceDoneExecutingLocked(r, inStopping);
11402 Binder.restoreCallingIdentity(origId);
11403 } else {
11404 Log.w(TAG, "Done executing unknown service " + r.name
11405 + " with token " + token);
11406 }
11407 }
11408 }
11409
11410 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11411 r.executeNesting--;
11412 if (r.executeNesting <= 0 && r.app != null) {
11413 r.app.executingServices.remove(r);
11414 if (r.app.executingServices.size() == 0) {
11415 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11416 }
11417 if (inStopping) {
11418 mStoppingServices.remove(r);
11419 }
11420 updateOomAdjLocked(r.app);
11421 }
11422 }
11423
11424 void serviceTimeout(ProcessRecord proc) {
11425 synchronized(this) {
11426 if (proc.executingServices.size() == 0 || proc.thread == null) {
11427 return;
11428 }
11429 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11430 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11431 ServiceRecord timeout = null;
11432 long nextTime = 0;
11433 while (it.hasNext()) {
11434 ServiceRecord sr = it.next();
11435 if (sr.executingStart < maxTime) {
11436 timeout = sr;
11437 break;
11438 }
11439 if (sr.executingStart > nextTime) {
11440 nextTime = sr.executingStart;
11441 }
11442 }
11443 if (timeout != null && mLRUProcesses.contains(proc)) {
11444 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011445 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011446 + timeout.name);
11447 } else {
11448 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11449 msg.obj = proc;
11450 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11451 }
11452 }
11453 }
11454
11455 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011456 // BACKUP AND RESTORE
11457 // =========================================================
11458
11459 // Cause the target app to be launched if necessary and its backup agent
11460 // instantiated. The backup agent will invoke backupAgentCreated() on the
11461 // activity manager to announce its creation.
11462 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11463 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11464 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11465
11466 synchronized(this) {
11467 // !!! TODO: currently no check here that we're already bound
11468 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11469 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11470 synchronized (stats) {
11471 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11472 }
11473
11474 BackupRecord r = new BackupRecord(ss, app, backupMode);
11475 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11476 // startProcessLocked() returns existing proc's record if it's already running
11477 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011478 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011479 if (proc == null) {
11480 Log.e(TAG, "Unable to start backup agent process " + r);
11481 return false;
11482 }
11483
11484 r.app = proc;
11485 mBackupTarget = r;
11486 mBackupAppName = app.packageName;
11487
Christopher Tate6fa95972009-06-05 18:43:55 -070011488 // Try not to kill the process during backup
11489 updateOomAdjLocked(proc);
11490
Christopher Tate181fafa2009-05-14 11:12:14 -070011491 // If the process is already attached, schedule the creation of the backup agent now.
11492 // If it is not yet live, this will be done when it attaches to the framework.
11493 if (proc.thread != null) {
11494 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11495 try {
11496 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11497 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011498 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011499 }
11500 } else {
11501 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11502 }
11503 // Invariants: at this point, the target app process exists and the application
11504 // is either already running or in the process of coming up. mBackupTarget and
11505 // mBackupAppName describe the app, so that when it binds back to the AM we
11506 // know that it's scheduled for a backup-agent operation.
11507 }
11508
11509 return true;
11510 }
11511
11512 // A backup agent has just come up
11513 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11514 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11515 + " = " + agent);
11516
11517 synchronized(this) {
11518 if (!agentPackageName.equals(mBackupAppName)) {
11519 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11520 return;
11521 }
11522
Christopher Tate043dadc2009-06-02 16:11:00 -070011523 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011524 try {
11525 IBackupManager bm = IBackupManager.Stub.asInterface(
11526 ServiceManager.getService(Context.BACKUP_SERVICE));
11527 bm.agentConnected(agentPackageName, agent);
11528 } catch (RemoteException e) {
11529 // can't happen; the backup manager service is local
11530 } catch (Exception e) {
11531 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11532 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011533 } finally {
11534 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011535 }
11536 }
11537 }
11538
11539 // done with this agent
11540 public void unbindBackupAgent(ApplicationInfo appInfo) {
11541 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011542 if (appInfo == null) {
11543 Log.w(TAG, "unbind backup agent for null app");
11544 return;
11545 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011546
11547 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011548 if (mBackupAppName == null) {
11549 Log.w(TAG, "Unbinding backup agent with no active backup");
11550 return;
11551 }
11552
Christopher Tate181fafa2009-05-14 11:12:14 -070011553 if (!mBackupAppName.equals(appInfo.packageName)) {
11554 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11555 return;
11556 }
11557
Christopher Tate6fa95972009-06-05 18:43:55 -070011558 ProcessRecord proc = mBackupTarget.app;
11559 mBackupTarget = null;
11560 mBackupAppName = null;
11561
11562 // Not backing this app up any more; reset its OOM adjustment
11563 updateOomAdjLocked(proc);
11564
Christopher Tatec7b31e32009-06-10 15:49:30 -070011565 // If the app crashed during backup, 'thread' will be null here
11566 if (proc.thread != null) {
11567 try {
11568 proc.thread.scheduleDestroyBackupAgent(appInfo);
11569 } catch (Exception e) {
11570 Log.e(TAG, "Exception when unbinding backup agent:");
11571 e.printStackTrace();
11572 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011573 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011574 }
11575 }
11576 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011577 // BROADCASTS
11578 // =========================================================
11579
Josh Bartel7f208742010-02-25 11:01:44 -060011580 private final List getStickiesLocked(String action, IntentFilter filter,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011581 List cur) {
11582 final ContentResolver resolver = mContext.getContentResolver();
11583 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11584 if (list == null) {
11585 return cur;
11586 }
11587 int N = list.size();
11588 for (int i=0; i<N; i++) {
11589 Intent intent = list.get(i);
11590 if (filter.match(resolver, intent, true, TAG) >= 0) {
11591 if (cur == null) {
11592 cur = new ArrayList<Intent>();
11593 }
11594 cur.add(intent);
11595 }
11596 }
11597 return cur;
11598 }
11599
11600 private final void scheduleBroadcastsLocked() {
11601 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11602 + mBroadcastsScheduled);
11603
11604 if (mBroadcastsScheduled) {
11605 return;
11606 }
11607 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11608 mBroadcastsScheduled = true;
11609 }
11610
11611 public Intent registerReceiver(IApplicationThread caller,
11612 IIntentReceiver receiver, IntentFilter filter, String permission) {
11613 synchronized(this) {
11614 ProcessRecord callerApp = null;
11615 if (caller != null) {
11616 callerApp = getRecordForAppLocked(caller);
11617 if (callerApp == null) {
11618 throw new SecurityException(
11619 "Unable to find app for caller " + caller
11620 + " (pid=" + Binder.getCallingPid()
11621 + ") when registering receiver " + receiver);
11622 }
11623 }
11624
11625 List allSticky = null;
11626
11627 // Look for any matching sticky broadcasts...
11628 Iterator actions = filter.actionsIterator();
11629 if (actions != null) {
11630 while (actions.hasNext()) {
11631 String action = (String)actions.next();
Josh Bartel7f208742010-02-25 11:01:44 -060011632 allSticky = getStickiesLocked(action, filter, allSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011633 }
11634 } else {
Josh Bartel7f208742010-02-25 11:01:44 -060011635 allSticky = getStickiesLocked(null, filter, allSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011636 }
11637
11638 // The first sticky in the list is returned directly back to
11639 // the client.
11640 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11641
11642 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11643 + ": " + sticky);
11644
11645 if (receiver == null) {
11646 return sticky;
11647 }
11648
11649 ReceiverList rl
11650 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11651 if (rl == null) {
11652 rl = new ReceiverList(this, callerApp,
11653 Binder.getCallingPid(),
11654 Binder.getCallingUid(), receiver);
11655 if (rl.app != null) {
11656 rl.app.receivers.add(rl);
11657 } else {
11658 try {
11659 receiver.asBinder().linkToDeath(rl, 0);
11660 } catch (RemoteException e) {
11661 return sticky;
11662 }
11663 rl.linkedToDeath = true;
11664 }
11665 mRegisteredReceivers.put(receiver.asBinder(), rl);
11666 }
11667 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11668 rl.add(bf);
11669 if (!bf.debugCheck()) {
11670 Log.w(TAG, "==> For Dynamic broadast");
11671 }
11672 mReceiverResolver.addFilter(bf);
11673
11674 // Enqueue broadcasts for all existing stickies that match
11675 // this filter.
11676 if (allSticky != null) {
11677 ArrayList receivers = new ArrayList();
11678 receivers.add(bf);
11679
11680 int N = allSticky.size();
11681 for (int i=0; i<N; i++) {
11682 Intent intent = (Intent)allSticky.get(i);
11683 BroadcastRecord r = new BroadcastRecord(intent, null,
11684 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011685 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011686 if (mParallelBroadcasts.size() == 0) {
11687 scheduleBroadcastsLocked();
11688 }
11689 mParallelBroadcasts.add(r);
11690 }
11691 }
11692
11693 return sticky;
11694 }
11695 }
11696
11697 public void unregisterReceiver(IIntentReceiver receiver) {
11698 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11699
11700 boolean doNext = false;
11701
11702 synchronized(this) {
11703 ReceiverList rl
11704 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11705 if (rl != null) {
11706 if (rl.curBroadcast != null) {
11707 BroadcastRecord r = rl.curBroadcast;
11708 doNext = finishReceiverLocked(
11709 receiver.asBinder(), r.resultCode, r.resultData,
11710 r.resultExtras, r.resultAbort, true);
11711 }
11712
11713 if (rl.app != null) {
11714 rl.app.receivers.remove(rl);
11715 }
11716 removeReceiverLocked(rl);
11717 if (rl.linkedToDeath) {
11718 rl.linkedToDeath = false;
11719 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11720 }
11721 }
11722 }
11723
11724 if (!doNext) {
11725 return;
11726 }
11727
11728 final long origId = Binder.clearCallingIdentity();
11729 processNextBroadcast(false);
11730 trimApplications();
11731 Binder.restoreCallingIdentity(origId);
11732 }
11733
11734 void removeReceiverLocked(ReceiverList rl) {
11735 mRegisteredReceivers.remove(rl.receiver.asBinder());
11736 int N = rl.size();
11737 for (int i=0; i<N; i++) {
11738 mReceiverResolver.removeFilter(rl.get(i));
11739 }
11740 }
11741
11742 private final int broadcastIntentLocked(ProcessRecord callerApp,
11743 String callerPackage, Intent intent, String resolvedType,
11744 IIntentReceiver resultTo, int resultCode, String resultData,
11745 Bundle map, String requiredPermission,
11746 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11747 intent = new Intent(intent);
11748
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011749 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011750 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11751 + " ordered=" + ordered);
11752 if ((resultTo != null) && !ordered) {
11753 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11754 }
11755
11756 // Handle special intents: if this broadcast is from the package
11757 // manager about a package being removed, we need to remove all of
11758 // its activities from the history stack.
11759 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11760 intent.getAction());
11761 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11762 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11763 || uidRemoved) {
11764 if (checkComponentPermission(
11765 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11766 callingPid, callingUid, -1)
11767 == PackageManager.PERMISSION_GRANTED) {
11768 if (uidRemoved) {
11769 final Bundle intentExtras = intent.getExtras();
11770 final int uid = intentExtras != null
11771 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11772 if (uid >= 0) {
11773 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11774 synchronized (bs) {
11775 bs.removeUidStatsLocked(uid);
11776 }
11777 }
11778 } else {
11779 Uri data = intent.getData();
11780 String ssp;
11781 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11782 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11783 uninstallPackageLocked(ssp,
11784 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011785 AttributeCache ac = AttributeCache.instance();
11786 if (ac != null) {
11787 ac.removePackage(ssp);
11788 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011789 }
11790 }
11791 }
11792 } else {
11793 String msg = "Permission Denial: " + intent.getAction()
11794 + " broadcast from " + callerPackage + " (pid=" + callingPid
11795 + ", uid=" + callingUid + ")"
11796 + " requires "
11797 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11798 Log.w(TAG, msg);
11799 throw new SecurityException(msg);
11800 }
11801 }
11802
11803 /*
11804 * If this is the time zone changed action, queue up a message that will reset the timezone
11805 * of all currently running processes. This message will get queued up before the broadcast
11806 * happens.
11807 */
11808 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11809 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11810 }
11811
Dianne Hackborn854060af2009-07-09 18:14:31 -070011812 /*
11813 * Prevent non-system code (defined here to be non-persistent
11814 * processes) from sending protected broadcasts.
11815 */
11816 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11817 || callingUid == Process.SHELL_UID || callingUid == 0) {
11818 // Always okay.
11819 } else if (callerApp == null || !callerApp.persistent) {
11820 try {
11821 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11822 intent.getAction())) {
11823 String msg = "Permission Denial: not allowed to send broadcast "
11824 + intent.getAction() + " from pid="
11825 + callingPid + ", uid=" + callingUid;
11826 Log.w(TAG, msg);
11827 throw new SecurityException(msg);
11828 }
11829 } catch (RemoteException e) {
11830 Log.w(TAG, "Remote exception", e);
11831 return BROADCAST_SUCCESS;
11832 }
11833 }
11834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011835 // Add to the sticky list if requested.
11836 if (sticky) {
11837 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11838 callingPid, callingUid)
11839 != PackageManager.PERMISSION_GRANTED) {
11840 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11841 + callingPid + ", uid=" + callingUid
11842 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11843 Log.w(TAG, msg);
11844 throw new SecurityException(msg);
11845 }
11846 if (requiredPermission != null) {
11847 Log.w(TAG, "Can't broadcast sticky intent " + intent
11848 + " and enforce permission " + requiredPermission);
11849 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11850 }
11851 if (intent.getComponent() != null) {
11852 throw new SecurityException(
11853 "Sticky broadcasts can't target a specific component");
11854 }
11855 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11856 if (list == null) {
11857 list = new ArrayList<Intent>();
11858 mStickyBroadcasts.put(intent.getAction(), list);
11859 }
11860 int N = list.size();
11861 int i;
11862 for (i=0; i<N; i++) {
11863 if (intent.filterEquals(list.get(i))) {
11864 // This sticky already exists, replace it.
11865 list.set(i, new Intent(intent));
11866 break;
11867 }
11868 }
11869 if (i >= N) {
11870 list.add(new Intent(intent));
11871 }
11872 }
11873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011874 // Figure out who all will receive this broadcast.
11875 List receivers = null;
11876 List<BroadcastFilter> registeredReceivers = null;
11877 try {
11878 if (intent.getComponent() != null) {
11879 // Broadcast is going to one specific receiver class...
11880 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011881 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011882 if (ai != null) {
11883 receivers = new ArrayList();
11884 ResolveInfo ri = new ResolveInfo();
11885 ri.activityInfo = ai;
11886 receivers.add(ri);
11887 }
11888 } else {
11889 // Need to resolve the intent to interested receivers...
11890 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11891 == 0) {
11892 receivers =
11893 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011894 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011895 }
Mihai Preda074edef2009-05-18 17:13:31 +020011896 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011897 }
11898 } catch (RemoteException ex) {
11899 // pm is in same process, this will never happen.
11900 }
11901
11902 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11903 if (!ordered && NR > 0) {
11904 // If we are not serializing this broadcast, then send the
11905 // registered receivers separately so they don't wait for the
11906 // components to be launched.
11907 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11908 callerPackage, callingPid, callingUid, requiredPermission,
11909 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011910 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011911 if (DEBUG_BROADCAST) Log.v(
11912 TAG, "Enqueueing parallel broadcast " + r
11913 + ": prev had " + mParallelBroadcasts.size());
11914 mParallelBroadcasts.add(r);
11915 scheduleBroadcastsLocked();
11916 registeredReceivers = null;
11917 NR = 0;
11918 }
11919
11920 // Merge into one list.
11921 int ir = 0;
11922 if (receivers != null) {
11923 // A special case for PACKAGE_ADDED: do not allow the package
11924 // being added to see this broadcast. This prevents them from
11925 // using this as a back door to get run as soon as they are
11926 // installed. Maybe in the future we want to have a special install
11927 // broadcast or such for apps, but we'd like to deliberately make
11928 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011929 boolean skip = false;
11930 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011931 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011932 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11933 skip = true;
11934 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11935 skip = true;
11936 }
11937 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011938 ? intent.getData().getSchemeSpecificPart()
11939 : null;
11940 if (skipPackage != null && receivers != null) {
11941 int NT = receivers.size();
11942 for (int it=0; it<NT; it++) {
11943 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11944 if (curt.activityInfo.packageName.equals(skipPackage)) {
11945 receivers.remove(it);
11946 it--;
11947 NT--;
11948 }
11949 }
11950 }
11951
11952 int NT = receivers != null ? receivers.size() : 0;
11953 int it = 0;
11954 ResolveInfo curt = null;
11955 BroadcastFilter curr = null;
11956 while (it < NT && ir < NR) {
11957 if (curt == null) {
11958 curt = (ResolveInfo)receivers.get(it);
11959 }
11960 if (curr == null) {
11961 curr = registeredReceivers.get(ir);
11962 }
11963 if (curr.getPriority() >= curt.priority) {
11964 // Insert this broadcast record into the final list.
11965 receivers.add(it, curr);
11966 ir++;
11967 curr = null;
11968 it++;
11969 NT++;
11970 } else {
11971 // Skip to the next ResolveInfo in the final list.
11972 it++;
11973 curt = null;
11974 }
11975 }
11976 }
11977 while (ir < NR) {
11978 if (receivers == null) {
11979 receivers = new ArrayList();
11980 }
11981 receivers.add(registeredReceivers.get(ir));
11982 ir++;
11983 }
11984
11985 if ((receivers != null && receivers.size() > 0)
11986 || resultTo != null) {
11987 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11988 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011989 receivers, resultTo, resultCode, resultData, map, ordered,
11990 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011991 if (DEBUG_BROADCAST) Log.v(
11992 TAG, "Enqueueing ordered broadcast " + r
11993 + ": prev had " + mOrderedBroadcasts.size());
11994 if (DEBUG_BROADCAST) {
11995 int seq = r.intent.getIntExtra("seq", -1);
11996 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11997 }
11998 mOrderedBroadcasts.add(r);
11999 scheduleBroadcastsLocked();
12000 }
12001
12002 return BROADCAST_SUCCESS;
12003 }
12004
12005 public final int broadcastIntent(IApplicationThread caller,
12006 Intent intent, String resolvedType, IIntentReceiver resultTo,
12007 int resultCode, String resultData, Bundle map,
12008 String requiredPermission, boolean serialized, boolean sticky) {
12009 // Refuse possible leaked file descriptors
12010 if (intent != null && intent.hasFileDescriptors() == true) {
12011 throw new IllegalArgumentException("File descriptors passed in Intent");
12012 }
12013
12014 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012015 int flags = intent.getFlags();
12016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012017 if (!mSystemReady) {
12018 // if the caller really truly claims to know what they're doing, go
12019 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012020 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12021 intent = new Intent(intent);
12022 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12023 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12024 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12025 + " before boot completion");
12026 throw new IllegalStateException("Cannot broadcast before boot completed");
12027 }
12028 }
12029
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012030 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12031 throw new IllegalArgumentException(
12032 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12033 }
12034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012035 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12036 final int callingPid = Binder.getCallingPid();
12037 final int callingUid = Binder.getCallingUid();
12038 final long origId = Binder.clearCallingIdentity();
12039 int res = broadcastIntentLocked(callerApp,
12040 callerApp != null ? callerApp.info.packageName : null,
12041 intent, resolvedType, resultTo,
12042 resultCode, resultData, map, requiredPermission, serialized,
12043 sticky, callingPid, callingUid);
12044 Binder.restoreCallingIdentity(origId);
12045 return res;
12046 }
12047 }
12048
12049 int broadcastIntentInPackage(String packageName, int uid,
12050 Intent intent, String resolvedType, IIntentReceiver resultTo,
12051 int resultCode, String resultData, Bundle map,
12052 String requiredPermission, boolean serialized, boolean sticky) {
12053 synchronized(this) {
12054 final long origId = Binder.clearCallingIdentity();
12055 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12056 resultTo, resultCode, resultData, map, requiredPermission,
12057 serialized, sticky, -1, uid);
12058 Binder.restoreCallingIdentity(origId);
12059 return res;
12060 }
12061 }
12062
12063 public final void unbroadcastIntent(IApplicationThread caller,
12064 Intent intent) {
12065 // Refuse possible leaked file descriptors
12066 if (intent != null && intent.hasFileDescriptors() == true) {
12067 throw new IllegalArgumentException("File descriptors passed in Intent");
12068 }
12069
12070 synchronized(this) {
12071 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12072 != PackageManager.PERMISSION_GRANTED) {
12073 String msg = "Permission Denial: unbroadcastIntent() from pid="
12074 + Binder.getCallingPid()
12075 + ", uid=" + Binder.getCallingUid()
12076 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12077 Log.w(TAG, msg);
12078 throw new SecurityException(msg);
12079 }
12080 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12081 if (list != null) {
12082 int N = list.size();
12083 int i;
12084 for (i=0; i<N; i++) {
12085 if (intent.filterEquals(list.get(i))) {
12086 list.remove(i);
12087 break;
12088 }
12089 }
12090 }
12091 }
12092 }
12093
12094 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12095 String resultData, Bundle resultExtras, boolean resultAbort,
12096 boolean explicit) {
12097 if (mOrderedBroadcasts.size() == 0) {
12098 if (explicit) {
12099 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12100 }
12101 return false;
12102 }
12103 BroadcastRecord r = mOrderedBroadcasts.get(0);
12104 if (r.receiver == null) {
12105 if (explicit) {
12106 Log.w(TAG, "finishReceiver called but none active");
12107 }
12108 return false;
12109 }
12110 if (r.receiver != receiver) {
12111 Log.w(TAG, "finishReceiver called but active receiver is different");
12112 return false;
12113 }
12114 int state = r.state;
12115 r.state = r.IDLE;
12116 if (state == r.IDLE) {
12117 if (explicit) {
12118 Log.w(TAG, "finishReceiver called but state is IDLE");
12119 }
12120 }
12121 r.receiver = null;
12122 r.intent.setComponent(null);
12123 if (r.curApp != null) {
12124 r.curApp.curReceiver = null;
12125 }
12126 if (r.curFilter != null) {
12127 r.curFilter.receiverList.curBroadcast = null;
12128 }
12129 r.curFilter = null;
12130 r.curApp = null;
12131 r.curComponent = null;
12132 r.curReceiver = null;
12133 mPendingBroadcast = null;
12134
12135 r.resultCode = resultCode;
12136 r.resultData = resultData;
12137 r.resultExtras = resultExtras;
12138 r.resultAbort = resultAbort;
12139
12140 // We will process the next receiver right now if this is finishing
12141 // an app receiver (which is always asynchronous) or after we have
12142 // come back from calling a receiver.
12143 return state == BroadcastRecord.APP_RECEIVE
12144 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12145 }
12146
12147 public void finishReceiver(IBinder who, int resultCode, String resultData,
12148 Bundle resultExtras, boolean resultAbort) {
12149 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12150
12151 // Refuse possible leaked file descriptors
12152 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12153 throw new IllegalArgumentException("File descriptors passed in Bundle");
12154 }
12155
12156 boolean doNext;
12157
12158 final long origId = Binder.clearCallingIdentity();
12159
12160 synchronized(this) {
12161 doNext = finishReceiverLocked(
12162 who, resultCode, resultData, resultExtras, resultAbort, true);
12163 }
12164
12165 if (doNext) {
12166 processNextBroadcast(false);
12167 }
12168 trimApplications();
12169
12170 Binder.restoreCallingIdentity(origId);
12171 }
12172
12173 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12174 if (r.nextReceiver > 0) {
12175 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12176 if (curReceiver instanceof BroadcastFilter) {
12177 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12178 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12179 System.identityHashCode(r),
12180 r.intent.getAction(),
12181 r.nextReceiver - 1,
12182 System.identityHashCode(bf));
12183 } else {
12184 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12185 System.identityHashCode(r),
12186 r.intent.getAction(),
12187 r.nextReceiver - 1,
12188 ((ResolveInfo)curReceiver).toString());
12189 }
12190 } else {
12191 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12192 + r);
12193 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12194 System.identityHashCode(r),
12195 r.intent.getAction(),
12196 r.nextReceiver,
12197 "NONE");
12198 }
12199 }
12200
12201 private final void broadcastTimeout() {
12202 synchronized (this) {
12203 if (mOrderedBroadcasts.size() == 0) {
12204 return;
12205 }
12206 long now = SystemClock.uptimeMillis();
12207 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012208 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012209 if (DEBUG_BROADCAST) Log.v(TAG,
12210 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012211 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012212 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012213 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012214 return;
12215 }
12216
12217 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012218 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012219 r.anrCount++;
12220
12221 // Current receiver has passed its expiration date.
12222 if (r.nextReceiver <= 0) {
12223 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12224 return;
12225 }
12226
12227 ProcessRecord app = null;
12228
12229 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12230 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12231 logBroadcastReceiverDiscard(r);
12232 if (curReceiver instanceof BroadcastFilter) {
12233 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12234 if (bf.receiverList.pid != 0
12235 && bf.receiverList.pid != MY_PID) {
12236 synchronized (this.mPidsSelfLocked) {
12237 app = this.mPidsSelfLocked.get(
12238 bf.receiverList.pid);
12239 }
12240 }
12241 } else {
12242 app = r.curApp;
12243 }
12244
12245 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012246 appNotRespondingLocked(app, null, null,
12247 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012248 }
12249
12250 if (mPendingBroadcast == r) {
12251 mPendingBroadcast = null;
12252 }
12253
12254 // Move on to the next receiver.
12255 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12256 r.resultExtras, r.resultAbort, true);
12257 scheduleBroadcastsLocked();
12258 }
12259 }
12260
12261 private final void processCurBroadcastLocked(BroadcastRecord r,
12262 ProcessRecord app) throws RemoteException {
12263 if (app.thread == null) {
12264 throw new RemoteException();
12265 }
12266 r.receiver = app.thread.asBinder();
12267 r.curApp = app;
12268 app.curReceiver = r;
12269 updateLRUListLocked(app, true);
12270
12271 // Tell the application to launch this receiver.
12272 r.intent.setComponent(r.curComponent);
12273
12274 boolean started = false;
12275 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012276 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012277 "Delivering to component " + r.curComponent
12278 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012279 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012280 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12281 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12282 started = true;
12283 } finally {
12284 if (!started) {
12285 r.receiver = null;
12286 r.curApp = null;
12287 app.curReceiver = null;
12288 }
12289 }
12290
12291 }
12292
12293 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012294 Intent intent, int resultCode, String data, Bundle extras,
12295 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012296 if (app != null && app.thread != null) {
12297 // If we have an app thread, do the call through that so it is
12298 // correctly ordered with other one-way calls.
12299 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012300 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012301 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012302 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012303 }
12304 }
12305
12306 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12307 BroadcastFilter filter, boolean ordered) {
12308 boolean skip = false;
12309 if (filter.requiredPermission != null) {
12310 int perm = checkComponentPermission(filter.requiredPermission,
12311 r.callingPid, r.callingUid, -1);
12312 if (perm != PackageManager.PERMISSION_GRANTED) {
12313 Log.w(TAG, "Permission Denial: broadcasting "
12314 + r.intent.toString()
12315 + " from " + r.callerPackage + " (pid="
12316 + r.callingPid + ", uid=" + r.callingUid + ")"
12317 + " requires " + filter.requiredPermission
12318 + " due to registered receiver " + filter);
12319 skip = true;
12320 }
12321 }
12322 if (r.requiredPermission != null) {
12323 int perm = checkComponentPermission(r.requiredPermission,
12324 filter.receiverList.pid, filter.receiverList.uid, -1);
12325 if (perm != PackageManager.PERMISSION_GRANTED) {
12326 Log.w(TAG, "Permission Denial: receiving "
12327 + r.intent.toString()
12328 + " to " + filter.receiverList.app
12329 + " (pid=" + filter.receiverList.pid
12330 + ", uid=" + filter.receiverList.uid + ")"
12331 + " requires " + r.requiredPermission
12332 + " due to sender " + r.callerPackage
12333 + " (uid " + r.callingUid + ")");
12334 skip = true;
12335 }
12336 }
12337
12338 if (!skip) {
12339 // If this is not being sent as an ordered broadcast, then we
12340 // don't want to touch the fields that keep track of the current
12341 // state of ordered broadcasts.
12342 if (ordered) {
12343 r.receiver = filter.receiverList.receiver.asBinder();
12344 r.curFilter = filter;
12345 filter.receiverList.curBroadcast = r;
12346 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012347 if (filter.receiverList.app != null) {
12348 // Bump hosting application to no longer be in background
12349 // scheduling class. Note that we can't do that if there
12350 // isn't an app... but we can only be in that case for
12351 // things that directly call the IActivityManager API, which
12352 // are already core system stuff so don't matter for this.
12353 r.curApp = filter.receiverList.app;
12354 filter.receiverList.app.curReceiver = r;
12355 updateOomAdjLocked();
12356 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012357 }
12358 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012359 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012360 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012361 Log.i(TAG, "Delivering to " + filter.receiverList.app
12362 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012363 }
12364 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12365 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012366 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012367 if (ordered) {
12368 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12369 }
12370 } catch (RemoteException e) {
12371 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12372 if (ordered) {
12373 r.receiver = null;
12374 r.curFilter = null;
12375 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012376 if (filter.receiverList.app != null) {
12377 filter.receiverList.app.curReceiver = null;
12378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012379 }
12380 }
12381 }
12382 }
12383
Dianne Hackborn12527f92009-11-11 17:39:50 -080012384 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12385 if (r.callingUid < 0) {
12386 // This was from a registerReceiver() call; ignore it.
12387 return;
12388 }
12389 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12390 MAX_BROADCAST_HISTORY-1);
12391 r.finishTime = SystemClock.uptimeMillis();
12392 mBroadcastHistory[0] = r;
12393 }
12394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012395 private final void processNextBroadcast(boolean fromMsg) {
12396 synchronized(this) {
12397 BroadcastRecord r;
12398
12399 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12400 + mParallelBroadcasts.size() + " broadcasts, "
12401 + mOrderedBroadcasts.size() + " serialized broadcasts");
12402
12403 updateCpuStats();
12404
12405 if (fromMsg) {
12406 mBroadcastsScheduled = false;
12407 }
12408
12409 // First, deliver any non-serialized broadcasts right away.
12410 while (mParallelBroadcasts.size() > 0) {
12411 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012412 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012413 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012414 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12415 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012416 for (int i=0; i<N; i++) {
12417 Object target = r.receivers.get(i);
12418 if (DEBUG_BROADCAST) Log.v(TAG,
12419 "Delivering non-serialized to registered "
12420 + target + ": " + r);
12421 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12422 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012423 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012424 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12425 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012426 }
12427
12428 // Now take care of the next serialized one...
12429
12430 // If we are waiting for a process to come up to handle the next
12431 // broadcast, then do nothing at this point. Just in case, we
12432 // check that the process we're waiting for still exists.
12433 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012434 if (DEBUG_BROADCAST_LIGHT) {
12435 Log.v(TAG, "processNextBroadcast: waiting for "
12436 + mPendingBroadcast.curApp);
12437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012438
12439 boolean isDead;
12440 synchronized (mPidsSelfLocked) {
12441 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12442 }
12443 if (!isDead) {
12444 // It's still alive, so keep waiting
12445 return;
12446 } else {
12447 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12448 + " died before responding to broadcast");
12449 mPendingBroadcast = null;
12450 }
12451 }
12452
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012453 boolean looped = false;
12454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012455 do {
12456 if (mOrderedBroadcasts.size() == 0) {
12457 // No more broadcasts pending, so all done!
12458 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012459 if (looped) {
12460 // If we had finished the last ordered broadcast, then
12461 // make sure all processes have correct oom and sched
12462 // adjustments.
12463 updateOomAdjLocked();
12464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012465 return;
12466 }
12467 r = mOrderedBroadcasts.get(0);
12468 boolean forceReceive = false;
12469
12470 // Ensure that even if something goes awry with the timeout
12471 // detection, we catch "hung" broadcasts here, discard them,
12472 // and continue to make progress.
12473 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12474 long now = SystemClock.uptimeMillis();
12475 if (r.dispatchTime > 0) {
12476 if ((numReceivers > 0) &&
12477 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12478 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12479 + " now=" + now
12480 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012481 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012482 + " intent=" + r.intent
12483 + " numReceivers=" + numReceivers
12484 + " nextReceiver=" + r.nextReceiver
12485 + " state=" + r.state);
12486 broadcastTimeout(); // forcibly finish this broadcast
12487 forceReceive = true;
12488 r.state = BroadcastRecord.IDLE;
12489 }
12490 }
12491
12492 if (r.state != BroadcastRecord.IDLE) {
12493 if (DEBUG_BROADCAST) Log.d(TAG,
12494 "processNextBroadcast() called when not idle (state="
12495 + r.state + ")");
12496 return;
12497 }
12498
12499 if (r.receivers == null || r.nextReceiver >= numReceivers
12500 || r.resultAbort || forceReceive) {
12501 // No more receivers for this broadcast! Send the final
12502 // result if requested...
12503 if (r.resultTo != null) {
12504 try {
12505 if (DEBUG_BROADCAST) {
12506 int seq = r.intent.getIntExtra("seq", -1);
12507 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12508 + " seq=" + seq + " app=" + r.callerApp);
12509 }
12510 performReceive(r.callerApp, r.resultTo,
12511 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012512 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012513 } catch (RemoteException e) {
12514 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12515 }
12516 }
12517
12518 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12519 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12520
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012521 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12522 + r);
12523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012524 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012525 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012526 mOrderedBroadcasts.remove(0);
12527 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012528 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012529 continue;
12530 }
12531 } while (r == null);
12532
12533 // Get the next receiver...
12534 int recIdx = r.nextReceiver++;
12535
12536 // Keep track of when this receiver started, and make sure there
12537 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012538 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012539 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012540 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012541
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012542 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12543 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012544 if (DEBUG_BROADCAST) Log.v(TAG,
12545 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012546 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012547 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012548 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012549 }
12550
12551 Object nextReceiver = r.receivers.get(recIdx);
12552 if (nextReceiver instanceof BroadcastFilter) {
12553 // Simple case: this is a registered receiver who gets
12554 // a direct call.
12555 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12556 if (DEBUG_BROADCAST) Log.v(TAG,
12557 "Delivering serialized to registered "
12558 + filter + ": " + r);
12559 deliverToRegisteredReceiver(r, filter, r.ordered);
12560 if (r.receiver == null || !r.ordered) {
12561 // The receiver has already finished, so schedule to
12562 // process the next one.
12563 r.state = BroadcastRecord.IDLE;
12564 scheduleBroadcastsLocked();
12565 }
12566 return;
12567 }
12568
12569 // Hard case: need to instantiate the receiver, possibly
12570 // starting its application process to host it.
12571
12572 ResolveInfo info =
12573 (ResolveInfo)nextReceiver;
12574
12575 boolean skip = false;
12576 int perm = checkComponentPermission(info.activityInfo.permission,
12577 r.callingPid, r.callingUid,
12578 info.activityInfo.exported
12579 ? -1 : info.activityInfo.applicationInfo.uid);
12580 if (perm != PackageManager.PERMISSION_GRANTED) {
12581 Log.w(TAG, "Permission Denial: broadcasting "
12582 + r.intent.toString()
12583 + " from " + r.callerPackage + " (pid=" + r.callingPid
12584 + ", uid=" + r.callingUid + ")"
12585 + " requires " + info.activityInfo.permission
12586 + " due to receiver " + info.activityInfo.packageName
12587 + "/" + info.activityInfo.name);
12588 skip = true;
12589 }
12590 if (r.callingUid != Process.SYSTEM_UID &&
12591 r.requiredPermission != null) {
12592 try {
12593 perm = ActivityThread.getPackageManager().
12594 checkPermission(r.requiredPermission,
12595 info.activityInfo.applicationInfo.packageName);
12596 } catch (RemoteException e) {
12597 perm = PackageManager.PERMISSION_DENIED;
12598 }
12599 if (perm != PackageManager.PERMISSION_GRANTED) {
12600 Log.w(TAG, "Permission Denial: receiving "
12601 + r.intent + " to "
12602 + info.activityInfo.applicationInfo.packageName
12603 + " requires " + r.requiredPermission
12604 + " due to sender " + r.callerPackage
12605 + " (uid " + r.callingUid + ")");
12606 skip = true;
12607 }
12608 }
12609 if (r.curApp != null && r.curApp.crashing) {
12610 // If the target process is crashing, just skip it.
12611 skip = true;
12612 }
12613
12614 if (skip) {
12615 r.receiver = null;
12616 r.curFilter = null;
12617 r.state = BroadcastRecord.IDLE;
12618 scheduleBroadcastsLocked();
12619 return;
12620 }
12621
12622 r.state = BroadcastRecord.APP_RECEIVE;
12623 String targetProcess = info.activityInfo.processName;
12624 r.curComponent = new ComponentName(
12625 info.activityInfo.applicationInfo.packageName,
12626 info.activityInfo.name);
12627 r.curReceiver = info.activityInfo;
12628
12629 // Is this receiver's application already running?
12630 ProcessRecord app = getProcessRecordLocked(targetProcess,
12631 info.activityInfo.applicationInfo.uid);
12632 if (app != null && app.thread != null) {
12633 try {
12634 processCurBroadcastLocked(r, app);
12635 return;
12636 } catch (RemoteException e) {
12637 Log.w(TAG, "Exception when sending broadcast to "
12638 + r.curComponent, e);
12639 }
12640
12641 // If a dead object exception was thrown -- fall through to
12642 // restart the application.
12643 }
12644
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012645 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012646 if ((r.curApp=startProcessLocked(targetProcess,
12647 info.activityInfo.applicationInfo, true,
12648 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012649 "broadcast", r.curComponent,
12650 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12651 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012652 // Ah, this recipient is unavailable. Finish it if necessary,
12653 // and mark the broadcast record as ready for the next.
12654 Log.w(TAG, "Unable to launch app "
12655 + info.activityInfo.applicationInfo.packageName + "/"
12656 + info.activityInfo.applicationInfo.uid + " for broadcast "
12657 + r.intent + ": process is bad");
12658 logBroadcastReceiverDiscard(r);
12659 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12660 r.resultExtras, r.resultAbort, true);
12661 scheduleBroadcastsLocked();
12662 r.state = BroadcastRecord.IDLE;
12663 return;
12664 }
12665
12666 mPendingBroadcast = r;
12667 }
12668 }
12669
12670 // =========================================================
12671 // INSTRUMENTATION
12672 // =========================================================
12673
12674 public boolean startInstrumentation(ComponentName className,
12675 String profileFile, int flags, Bundle arguments,
12676 IInstrumentationWatcher watcher) {
12677 // Refuse possible leaked file descriptors
12678 if (arguments != null && arguments.hasFileDescriptors()) {
12679 throw new IllegalArgumentException("File descriptors passed in Bundle");
12680 }
12681
12682 synchronized(this) {
12683 InstrumentationInfo ii = null;
12684 ApplicationInfo ai = null;
12685 try {
12686 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012687 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012688 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012689 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012690 } catch (PackageManager.NameNotFoundException e) {
12691 }
12692 if (ii == null) {
12693 reportStartInstrumentationFailure(watcher, className,
12694 "Unable to find instrumentation info for: " + className);
12695 return false;
12696 }
12697 if (ai == null) {
12698 reportStartInstrumentationFailure(watcher, className,
12699 "Unable to find instrumentation target package: " + ii.targetPackage);
12700 return false;
12701 }
12702
12703 int match = mContext.getPackageManager().checkSignatures(
12704 ii.targetPackage, ii.packageName);
12705 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12706 String msg = "Permission Denial: starting instrumentation "
12707 + className + " from pid="
12708 + Binder.getCallingPid()
12709 + ", uid=" + Binder.getCallingPid()
12710 + " not allowed because package " + ii.packageName
12711 + " does not have a signature matching the target "
12712 + ii.targetPackage;
12713 reportStartInstrumentationFailure(watcher, className, msg);
12714 throw new SecurityException(msg);
12715 }
12716
12717 final long origId = Binder.clearCallingIdentity();
12718 uninstallPackageLocked(ii.targetPackage, -1, true);
12719 ProcessRecord app = addAppLocked(ai);
12720 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012721 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012722 app.instrumentationProfileFile = profileFile;
12723 app.instrumentationArguments = arguments;
12724 app.instrumentationWatcher = watcher;
12725 app.instrumentationResultClass = className;
12726 Binder.restoreCallingIdentity(origId);
12727 }
12728
12729 return true;
12730 }
12731
12732 /**
12733 * Report errors that occur while attempting to start Instrumentation. Always writes the
12734 * error to the logs, but if somebody is watching, send the report there too. This enables
12735 * the "am" command to report errors with more information.
12736 *
12737 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12738 * @param cn The component name of the instrumentation.
12739 * @param report The error report.
12740 */
12741 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12742 ComponentName cn, String report) {
12743 Log.w(TAG, report);
12744 try {
12745 if (watcher != null) {
12746 Bundle results = new Bundle();
12747 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12748 results.putString("Error", report);
12749 watcher.instrumentationStatus(cn, -1, results);
12750 }
12751 } catch (RemoteException e) {
12752 Log.w(TAG, e);
12753 }
12754 }
12755
12756 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12757 if (app.instrumentationWatcher != null) {
12758 try {
12759 // NOTE: IInstrumentationWatcher *must* be oneway here
12760 app.instrumentationWatcher.instrumentationFinished(
12761 app.instrumentationClass,
12762 resultCode,
12763 results);
12764 } catch (RemoteException e) {
12765 }
12766 }
12767 app.instrumentationWatcher = null;
12768 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012769 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012770 app.instrumentationProfileFile = null;
12771 app.instrumentationArguments = null;
12772
12773 uninstallPackageLocked(app.processName, -1, false);
12774 }
12775
12776 public void finishInstrumentation(IApplicationThread target,
12777 int resultCode, Bundle results) {
12778 // Refuse possible leaked file descriptors
12779 if (results != null && results.hasFileDescriptors()) {
12780 throw new IllegalArgumentException("File descriptors passed in Intent");
12781 }
12782
12783 synchronized(this) {
12784 ProcessRecord app = getRecordForAppLocked(target);
12785 if (app == null) {
12786 Log.w(TAG, "finishInstrumentation: no app for " + target);
12787 return;
12788 }
12789 final long origId = Binder.clearCallingIdentity();
12790 finishInstrumentationLocked(app, resultCode, results);
12791 Binder.restoreCallingIdentity(origId);
12792 }
12793 }
12794
12795 // =========================================================
12796 // CONFIGURATION
12797 // =========================================================
12798
12799 public ConfigurationInfo getDeviceConfigurationInfo() {
12800 ConfigurationInfo config = new ConfigurationInfo();
12801 synchronized (this) {
12802 config.reqTouchScreen = mConfiguration.touchscreen;
12803 config.reqKeyboardType = mConfiguration.keyboard;
12804 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012805 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12806 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012807 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12808 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012809 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12810 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012811 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12812 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012813 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012814 }
12815 return config;
12816 }
12817
12818 public Configuration getConfiguration() {
12819 Configuration ci;
12820 synchronized(this) {
12821 ci = new Configuration(mConfiguration);
12822 }
12823 return ci;
12824 }
12825
12826 public void updateConfiguration(Configuration values) {
12827 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12828 "updateConfiguration()");
12829
12830 synchronized(this) {
12831 if (values == null && mWindowManager != null) {
12832 // sentinel: fetch the current configuration from the window manager
12833 values = mWindowManager.computeNewConfiguration();
12834 }
12835
12836 final long origId = Binder.clearCallingIdentity();
12837 updateConfigurationLocked(values, null);
12838 Binder.restoreCallingIdentity(origId);
12839 }
12840 }
12841
12842 /**
12843 * Do either or both things: (1) change the current configuration, and (2)
12844 * make sure the given activity is running with the (now) current
12845 * configuration. Returns true if the activity has been left running, or
12846 * false if <var>starting</var> is being destroyed to match the new
12847 * configuration.
12848 */
12849 public boolean updateConfigurationLocked(Configuration values,
12850 HistoryRecord starting) {
12851 int changes = 0;
12852
12853 boolean kept = true;
12854
12855 if (values != null) {
12856 Configuration newConfig = new Configuration(mConfiguration);
12857 changes = newConfig.updateFrom(values);
12858 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012859 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012860 Log.i(TAG, "Updating configuration to: " + values);
12861 }
12862
12863 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12864
12865 if (values.locale != null) {
12866 saveLocaleLocked(values.locale,
12867 !values.locale.equals(mConfiguration.locale),
12868 values.userSetLocale);
12869 }
12870
12871 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012872 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080012873
12874 AttributeCache ac = AttributeCache.instance();
12875 if (ac != null) {
12876 ac.updateConfiguration(mConfiguration);
12877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012878
12879 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12880 msg.obj = new Configuration(mConfiguration);
12881 mHandler.sendMessage(msg);
12882
12883 final int N = mLRUProcesses.size();
12884 for (int i=0; i<N; i++) {
12885 ProcessRecord app = mLRUProcesses.get(i);
12886 try {
12887 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012888 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12889 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012890 app.thread.scheduleConfigurationChanged(mConfiguration);
12891 }
12892 } catch (Exception e) {
12893 }
12894 }
12895 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012896 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012897 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12898 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012899 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
12900 broadcastIntentLocked(null, null,
12901 new Intent(Intent.ACTION_LOCALE_CHANGED),
12902 null, null, 0, null, null,
12903 null, false, false, MY_PID, Process.SYSTEM_UID);
12904 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012905 }
12906 }
12907
12908 if (changes != 0 && starting == null) {
12909 // If the configuration changed, and the caller is not already
12910 // in the process of starting an activity, then find the top
12911 // activity to check if its configuration needs to change.
12912 starting = topRunningActivityLocked(null);
12913 }
12914
12915 if (starting != null) {
12916 kept = ensureActivityConfigurationLocked(starting, changes);
12917 if (kept) {
12918 // If this didn't result in the starting activity being
12919 // destroyed, then we need to make sure at this point that all
12920 // other activities are made visible.
12921 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12922 + ", ensuring others are correct.");
12923 ensureActivitiesVisibleLocked(starting, changes);
12924 }
12925 }
12926
12927 return kept;
12928 }
12929
12930 private final boolean relaunchActivityLocked(HistoryRecord r,
12931 int changes, boolean andResume) {
12932 List<ResultInfo> results = null;
12933 List<Intent> newIntents = null;
12934 if (andResume) {
12935 results = r.results;
12936 newIntents = r.newIntents;
12937 }
12938 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12939 + " with results=" + results + " newIntents=" + newIntents
12940 + " andResume=" + andResume);
12941 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12942 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12943 r.task.taskId, r.shortComponentName);
12944
12945 r.startFreezingScreenLocked(r.app, 0);
12946
12947 try {
12948 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12949 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080012950 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012951 // Note: don't need to call pauseIfSleepingLocked() here, because
12952 // the caller will only pass in 'andResume' if this activity is
12953 // currently resumed, which implies we aren't sleeping.
12954 } catch (RemoteException e) {
12955 return false;
12956 }
12957
12958 if (andResume) {
12959 r.results = null;
12960 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012961 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012962 }
12963
12964 return true;
12965 }
12966
12967 /**
12968 * Make sure the given activity matches the current configuration. Returns
12969 * false if the activity had to be destroyed. Returns true if the
12970 * configuration is the same, or the activity will remain running as-is
12971 * for whatever reason. Ensures the HistoryRecord is updated with the
12972 * correct configuration and all other bookkeeping is handled.
12973 */
12974 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12975 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012976 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12977 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012978
12979 // Short circuit: if the two configurations are the exact same
12980 // object (the common case), then there is nothing to do.
12981 Configuration newConfig = mConfiguration;
12982 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012983 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12984 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012985 return true;
12986 }
12987
12988 // We don't worry about activities that are finishing.
12989 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012990 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012991 "Configuration doesn't matter in finishing " + r);
12992 r.stopFreezingScreenLocked(false);
12993 return true;
12994 }
12995
12996 // Okay we now are going to make this activity have the new config.
12997 // But then we need to figure out how it needs to deal with that.
12998 Configuration oldConfig = r.configuration;
12999 r.configuration = newConfig;
13000
13001 // If the activity isn't currently running, just leave the new
13002 // configuration and it will pick that up next time it starts.
13003 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013004 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013005 "Configuration doesn't matter not running " + r);
13006 r.stopFreezingScreenLocked(false);
13007 return true;
13008 }
13009
13010 // If the activity isn't persistent, there is a chance we will
13011 // need to restart it.
13012 if (!r.persistent) {
13013
13014 // Figure out what has changed between the two configurations.
13015 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013016 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13017 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013018 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013019 + Integer.toHexString(r.info.configChanges)
13020 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013021 }
13022 if ((changes&(~r.info.configChanges)) != 0) {
13023 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13024 r.configChangeFlags |= changes;
13025 r.startFreezingScreenLocked(r.app, globalChanges);
13026 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013027 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13028 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013029 destroyActivityLocked(r, true);
13030 } else if (r.state == ActivityState.PAUSING) {
13031 // A little annoying: we are waiting for this activity to
13032 // finish pausing. Let's not do anything now, but just
13033 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013034 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13035 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013036 r.configDestroy = true;
13037 return true;
13038 } else if (r.state == ActivityState.RESUMED) {
13039 // Try to optimize this case: the configuration is changing
13040 // and we need to restart the top, resumed activity.
13041 // Instead of doing the normal handshaking, just say
13042 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013043 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13044 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013045 relaunchActivityLocked(r, r.configChangeFlags, true);
13046 r.configChangeFlags = 0;
13047 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013048 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13049 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013050 relaunchActivityLocked(r, r.configChangeFlags, false);
13051 r.configChangeFlags = 0;
13052 }
13053
13054 // All done... tell the caller we weren't able to keep this
13055 // activity around.
13056 return false;
13057 }
13058 }
13059
13060 // Default case: the activity can handle this new configuration, so
13061 // hand it over. Note that we don't need to give it the new
13062 // configuration, since we always send configuration changes to all
13063 // process when they happen so it can just use whatever configuration
13064 // it last got.
13065 if (r.app != null && r.app.thread != null) {
13066 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013067 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013068 r.app.thread.scheduleActivityConfigurationChanged(r);
13069 } catch (RemoteException e) {
13070 // If process died, whatever.
13071 }
13072 }
13073 r.stopFreezingScreenLocked(false);
13074
13075 return true;
13076 }
13077
13078 /**
13079 * Save the locale. You must be inside a synchronized (this) block.
13080 */
13081 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13082 if(isDiff) {
13083 SystemProperties.set("user.language", l.getLanguage());
13084 SystemProperties.set("user.region", l.getCountry());
13085 }
13086
13087 if(isPersist) {
13088 SystemProperties.set("persist.sys.language", l.getLanguage());
13089 SystemProperties.set("persist.sys.country", l.getCountry());
13090 SystemProperties.set("persist.sys.localevar", l.getVariant());
13091 }
13092 }
13093
13094 // =========================================================
13095 // LIFETIME MANAGEMENT
13096 // =========================================================
13097
13098 private final int computeOomAdjLocked(
13099 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13100 if (mAdjSeq == app.adjSeq) {
13101 // This adjustment has already been computed.
13102 return app.curAdj;
13103 }
13104
13105 if (app.thread == null) {
13106 app.adjSeq = mAdjSeq;
13107 return (app.curAdj=EMPTY_APP_ADJ);
13108 }
13109
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013110 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13111 // The max adjustment doesn't allow this app to be anything
13112 // below foreground, so it is not worth doing work for it.
13113 app.adjType = "fixed";
13114 app.adjSeq = mAdjSeq;
13115 app.curRawAdj = app.maxAdj;
13116 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13117 return (app.curAdj=app.maxAdj);
13118 }
13119
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013120 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013121 app.adjSource = null;
13122 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013123
The Android Open Source Project4df24232009-03-05 14:34:35 -080013124 // Determine the importance of the process, starting with most
13125 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013126 int adj;
13127 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013128 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013129 // The last app on the list is the foreground app.
13130 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013131 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013132 } else if (app.instrumentationClass != null) {
13133 // Don't want to kill running instrumentation.
13134 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013135 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013136 } else if (app.persistentActivities > 0) {
13137 // Special persistent activities... shouldn't be used these days.
13138 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013139 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013140 } else if (app.curReceiver != null ||
13141 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13142 // An app that is currently receiving a broadcast also
13143 // counts as being in the foreground.
13144 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013145 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013146 } else if (app.executingServices.size() > 0) {
13147 // An app that is currently executing a service callback also
13148 // counts as being in the foreground.
13149 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013150 app.adjType = "exec-service";
13151 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013152 // The user is aware of this app, so make it visible.
13153 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013154 app.adjType = "foreground-service";
13155 } else if (app.forcingToForeground != null) {
13156 // The user is aware of this app, so make it visible.
13157 adj = VISIBLE_APP_ADJ;
13158 app.adjType = "force-foreground";
13159 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013160 } else if (app == mHomeProcess) {
13161 // This process is hosting what we currently consider to be the
13162 // home app, so we don't want to let it go into the background.
13163 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013164 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013165 } else if ((N=app.activities.size()) != 0) {
13166 // This app is in the background with paused activities.
13167 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013168 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013169 for (int j=0; j<N; j++) {
13170 if (((HistoryRecord)app.activities.get(j)).visible) {
13171 // This app has a visible activity!
13172 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013173 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013174 break;
13175 }
13176 }
13177 } else {
13178 // A very not-needed process.
13179 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013180 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013181 }
13182
The Android Open Source Project4df24232009-03-05 14:34:35 -080013183 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013184 // there are applications dependent on our services or providers, but
13185 // this gives us a baseline and makes sure we don't get into an
13186 // infinite recursion.
13187 app.adjSeq = mAdjSeq;
13188 app.curRawAdj = adj;
13189 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13190
Christopher Tate6fa95972009-06-05 18:43:55 -070013191 if (mBackupTarget != null && app == mBackupTarget.app) {
13192 // If possible we want to avoid killing apps while they're being backed up
13193 if (adj > BACKUP_APP_ADJ) {
13194 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13195 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013196 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013197 }
13198 }
13199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013200 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013201 final long now = SystemClock.uptimeMillis();
13202 // This process is more important if the top activity is
13203 // bound to the service.
13204 Iterator jt = app.services.iterator();
13205 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13206 ServiceRecord s = (ServiceRecord)jt.next();
13207 if (s.startRequested) {
13208 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13209 // This service has seen some activity within
13210 // recent memory, so we will keep its process ahead
13211 // of the background processes.
13212 if (adj > SECONDARY_SERVER_ADJ) {
13213 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013214 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013215 }
13216 }
13217 }
13218 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13219 Iterator<ConnectionRecord> kt
13220 = s.connections.values().iterator();
13221 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13222 // XXX should compute this based on the max of
13223 // all connected clients.
13224 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013225 if (cr.binding.client == app) {
13226 // Binding to ourself is not interesting.
13227 continue;
13228 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013229 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13230 ProcessRecord client = cr.binding.client;
13231 int myHiddenAdj = hiddenAdj;
13232 if (myHiddenAdj > client.hiddenAdj) {
13233 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13234 myHiddenAdj = client.hiddenAdj;
13235 } else {
13236 myHiddenAdj = VISIBLE_APP_ADJ;
13237 }
13238 }
13239 int clientAdj = computeOomAdjLocked(
13240 client, myHiddenAdj, TOP_APP);
13241 if (adj > clientAdj) {
13242 adj = clientAdj > VISIBLE_APP_ADJ
13243 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013244 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013245 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13246 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013247 app.adjSource = cr.binding.client;
13248 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013249 }
13250 }
13251 HistoryRecord a = cr.activity;
13252 //if (a != null) {
13253 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13254 //}
13255 if (a != null && adj > FOREGROUND_APP_ADJ &&
13256 (a.state == ActivityState.RESUMED
13257 || a.state == ActivityState.PAUSING)) {
13258 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013259 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013260 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13261 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013262 app.adjSource = a;
13263 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013264 }
13265 }
13266 }
13267 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013268
13269 // Finally, f this process has active services running in it, we
13270 // would like to avoid killing it unless it would prevent the current
13271 // application from running. By default we put the process in
13272 // with the rest of the background processes; as we scan through
13273 // its services we may bump it up from there.
13274 if (adj > hiddenAdj) {
13275 adj = hiddenAdj;
13276 app.adjType = "bg-services";
13277 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013278 }
13279
13280 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013281 Iterator jt = app.pubProviders.values().iterator();
13282 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13283 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13284 if (cpr.clients.size() != 0) {
13285 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13286 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13287 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013288 if (client == app) {
13289 // Being our own client is not interesting.
13290 continue;
13291 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013292 int myHiddenAdj = hiddenAdj;
13293 if (myHiddenAdj > client.hiddenAdj) {
13294 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13295 myHiddenAdj = client.hiddenAdj;
13296 } else {
13297 myHiddenAdj = FOREGROUND_APP_ADJ;
13298 }
13299 }
13300 int clientAdj = computeOomAdjLocked(
13301 client, myHiddenAdj, TOP_APP);
13302 if (adj > clientAdj) {
13303 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013304 ? clientAdj : FOREGROUND_APP_ADJ;
13305 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013306 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13307 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013308 app.adjSource = client;
13309 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013310 }
13311 }
13312 }
13313 // If the provider has external (non-framework) process
13314 // dependencies, ensure that its adjustment is at least
13315 // FOREGROUND_APP_ADJ.
13316 if (cpr.externals != 0) {
13317 if (adj > FOREGROUND_APP_ADJ) {
13318 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013319 app.adjType = "provider";
13320 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013321 }
13322 }
13323 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013324
13325 // Finally, if this process has published any content providers,
13326 // then its adjustment makes it at least as important as any of the
13327 // processes using those providers, and no less important than
13328 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13329 if (adj > CONTENT_PROVIDER_ADJ) {
13330 adj = CONTENT_PROVIDER_ADJ;
13331 app.adjType = "pub-providers";
13332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013333 }
13334
13335 app.curRawAdj = adj;
13336
13337 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13338 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13339 if (adj > app.maxAdj) {
13340 adj = app.maxAdj;
13341 }
13342
13343 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013344 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013345 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13346 : Process.THREAD_GROUP_DEFAULT;
13347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013348 return adj;
13349 }
13350
13351 /**
13352 * Ask a given process to GC right now.
13353 */
13354 final void performAppGcLocked(ProcessRecord app) {
13355 try {
13356 app.lastRequestedGc = SystemClock.uptimeMillis();
13357 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013358 if (app.reportLowMemory) {
13359 app.reportLowMemory = false;
13360 app.thread.scheduleLowMemory();
13361 } else {
13362 app.thread.processInBackground();
13363 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013364 }
13365 } catch (Exception e) {
13366 // whatever.
13367 }
13368 }
13369
13370 /**
13371 * Returns true if things are idle enough to perform GCs.
13372 */
Josh Bartel7f208742010-02-25 11:01:44 -060013373 private final boolean canGcNowLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013374 return mParallelBroadcasts.size() == 0
13375 && mOrderedBroadcasts.size() == 0
13376 && (mSleeping || (mResumedActivity != null &&
13377 mResumedActivity.idle));
13378 }
13379
13380 /**
13381 * Perform GCs on all processes that are waiting for it, but only
13382 * if things are idle.
13383 */
13384 final void performAppGcsLocked() {
13385 final int N = mProcessesToGc.size();
13386 if (N <= 0) {
13387 return;
13388 }
Josh Bartel7f208742010-02-25 11:01:44 -060013389 if (canGcNowLocked()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013390 while (mProcessesToGc.size() > 0) {
13391 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013392 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13393 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13394 <= SystemClock.uptimeMillis()) {
13395 // To avoid spamming the system, we will GC processes one
13396 // at a time, waiting a few seconds between each.
13397 performAppGcLocked(proc);
13398 scheduleAppGcsLocked();
13399 return;
13400 } else {
13401 // It hasn't been long enough since we last GCed this
13402 // process... put it in the list to wait for its time.
13403 addProcessToGcListLocked(proc);
13404 break;
13405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013406 }
13407 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013408
13409 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013410 }
13411 }
13412
13413 /**
13414 * If all looks good, perform GCs on all processes waiting for them.
13415 */
13416 final void performAppGcsIfAppropriateLocked() {
Josh Bartel7f208742010-02-25 11:01:44 -060013417 if (canGcNowLocked()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013418 performAppGcsLocked();
13419 return;
13420 }
13421 // Still not idle, wait some more.
13422 scheduleAppGcsLocked();
13423 }
13424
13425 /**
13426 * Schedule the execution of all pending app GCs.
13427 */
13428 final void scheduleAppGcsLocked() {
13429 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013430
13431 if (mProcessesToGc.size() > 0) {
13432 // Schedule a GC for the time to the next process.
13433 ProcessRecord proc = mProcessesToGc.get(0);
13434 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13435
13436 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13437 long now = SystemClock.uptimeMillis();
13438 if (when < (now+GC_TIMEOUT)) {
13439 when = now + GC_TIMEOUT;
13440 }
13441 mHandler.sendMessageAtTime(msg, when);
13442 }
13443 }
13444
13445 /**
13446 * Add a process to the array of processes waiting to be GCed. Keeps the
13447 * list in sorted order by the last GC time. The process can't already be
13448 * on the list.
13449 */
13450 final void addProcessToGcListLocked(ProcessRecord proc) {
13451 boolean added = false;
13452 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13453 if (mProcessesToGc.get(i).lastRequestedGc <
13454 proc.lastRequestedGc) {
13455 added = true;
13456 mProcessesToGc.add(i+1, proc);
13457 break;
13458 }
13459 }
13460 if (!added) {
13461 mProcessesToGc.add(0, proc);
13462 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013463 }
13464
13465 /**
13466 * Set up to ask a process to GC itself. This will either do it
13467 * immediately, or put it on the list of processes to gc the next
13468 * time things are idle.
13469 */
13470 final void scheduleAppGcLocked(ProcessRecord app) {
13471 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013472 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013473 return;
13474 }
13475 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013476 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013477 scheduleAppGcsLocked();
13478 }
13479 }
13480
13481 private final boolean updateOomAdjLocked(
13482 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13483 app.hiddenAdj = hiddenAdj;
13484
13485 if (app.thread == null) {
13486 return true;
13487 }
13488
13489 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013491 if (app.pid != 0 && app.pid != MY_PID) {
13492 if (app.curRawAdj != app.setRawAdj) {
13493 if (app.curRawAdj > FOREGROUND_APP_ADJ
13494 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13495 // If this app is transitioning from foreground to
13496 // non-foreground, have it do a gc.
13497 scheduleAppGcLocked(app);
13498 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13499 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13500 // Likewise do a gc when an app is moving in to the
13501 // background (such as a service stopping).
13502 scheduleAppGcLocked(app);
13503 }
13504 app.setRawAdj = app.curRawAdj;
13505 }
13506 if (adj != app.setAdj) {
13507 if (Process.setOomAdj(app.pid, adj)) {
13508 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13509 TAG, "Set app " + app.processName +
13510 " oom adj to " + adj);
13511 app.setAdj = adj;
13512 } else {
13513 return false;
13514 }
13515 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013516 if (app.setSchedGroup != app.curSchedGroup) {
13517 app.setSchedGroup = app.curSchedGroup;
13518 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13519 "Setting process group of " + app.processName
13520 + " to " + app.curSchedGroup);
13521 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013522 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013523 try {
13524 Process.setProcessGroup(app.pid, app.curSchedGroup);
13525 } catch (Exception e) {
13526 Log.w(TAG, "Failed setting process group of " + app.pid
13527 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013528 e.printStackTrace();
13529 } finally {
13530 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013531 }
13532 }
13533 if (false) {
13534 if (app.thread != null) {
13535 try {
13536 app.thread.setSchedulingGroup(app.curSchedGroup);
13537 } catch (RemoteException e) {
13538 }
13539 }
13540 }
13541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013542 }
13543
13544 return true;
13545 }
13546
13547 private final HistoryRecord resumedAppLocked() {
13548 HistoryRecord resumedActivity = mResumedActivity;
13549 if (resumedActivity == null || resumedActivity.app == null) {
13550 resumedActivity = mPausingActivity;
13551 if (resumedActivity == null || resumedActivity.app == null) {
13552 resumedActivity = topRunningActivityLocked(null);
13553 }
13554 }
13555 return resumedActivity;
13556 }
13557
13558 private final boolean updateOomAdjLocked(ProcessRecord app) {
13559 final HistoryRecord TOP_ACT = resumedAppLocked();
13560 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13561 int curAdj = app.curAdj;
13562 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13563 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13564
13565 mAdjSeq++;
13566
13567 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13568 if (res) {
13569 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13570 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13571 if (nowHidden != wasHidden) {
13572 // Changed to/from hidden state, so apps after it in the LRU
13573 // list may also be changed.
13574 updateOomAdjLocked();
13575 }
13576 }
13577 return res;
13578 }
13579
13580 private final boolean updateOomAdjLocked() {
13581 boolean didOomAdj = true;
13582 final HistoryRecord TOP_ACT = resumedAppLocked();
13583 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13584
13585 if (false) {
13586 RuntimeException e = new RuntimeException();
13587 e.fillInStackTrace();
13588 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13589 }
13590
13591 mAdjSeq++;
13592
13593 // First try updating the OOM adjustment for each of the
13594 // application processes based on their current state.
13595 int i = mLRUProcesses.size();
13596 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13597 while (i > 0) {
13598 i--;
13599 ProcessRecord app = mLRUProcesses.get(i);
13600 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13601 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13602 && app.curAdj == curHiddenAdj) {
13603 curHiddenAdj++;
13604 }
13605 } else {
13606 didOomAdj = false;
13607 }
13608 }
13609
13610 // todo: for now pretend like OOM ADJ didn't work, because things
13611 // aren't behaving as expected on Linux -- it's not killing processes.
13612 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13613 }
13614
13615 private final void trimApplications() {
13616 synchronized (this) {
13617 int i;
13618
13619 // First remove any unused application processes whose package
13620 // has been removed.
13621 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13622 final ProcessRecord app = mRemovedProcesses.get(i);
13623 if (app.activities.size() == 0
13624 && app.curReceiver == null && app.services.size() == 0) {
13625 Log.i(
13626 TAG, "Exiting empty application process "
13627 + app.processName + " ("
13628 + (app.thread != null ? app.thread.asBinder() : null)
13629 + ")\n");
13630 if (app.pid > 0 && app.pid != MY_PID) {
13631 Process.killProcess(app.pid);
13632 } else {
13633 try {
13634 app.thread.scheduleExit();
13635 } catch (Exception e) {
13636 // Ignore exceptions.
13637 }
13638 }
13639 cleanUpApplicationRecordLocked(app, false, -1);
13640 mRemovedProcesses.remove(i);
13641
13642 if (app.persistent) {
13643 if (app.persistent) {
13644 addAppLocked(app.info);
13645 }
13646 }
13647 }
13648 }
13649
13650 // Now try updating the OOM adjustment for each of the
13651 // application processes based on their current state.
13652 // If the setOomAdj() API is not supported, then go with our
13653 // back-up plan...
13654 if (!updateOomAdjLocked()) {
13655
13656 // Count how many processes are running services.
13657 int numServiceProcs = 0;
13658 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13659 final ProcessRecord app = mLRUProcesses.get(i);
13660
13661 if (app.persistent || app.services.size() != 0
13662 || app.curReceiver != null
13663 || app.persistentActivities > 0) {
13664 // Don't count processes holding services against our
13665 // maximum process count.
13666 if (localLOGV) Log.v(
13667 TAG, "Not trimming app " + app + " with services: "
13668 + app.services);
13669 numServiceProcs++;
13670 }
13671 }
13672
13673 int curMaxProcs = mProcessLimit;
13674 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13675 if (mAlwaysFinishActivities) {
13676 curMaxProcs = 1;
13677 }
13678 curMaxProcs += numServiceProcs;
13679
13680 // Quit as many processes as we can to get down to the desired
13681 // process count. First remove any processes that no longer
13682 // have activites running in them.
13683 for ( i=0;
13684 i<mLRUProcesses.size()
13685 && mLRUProcesses.size() > curMaxProcs;
13686 i++) {
13687 final ProcessRecord app = mLRUProcesses.get(i);
13688 // Quit an application only if it is not currently
13689 // running any activities.
13690 if (!app.persistent && app.activities.size() == 0
13691 && app.curReceiver == null && app.services.size() == 0) {
13692 Log.i(
13693 TAG, "Exiting empty application process "
13694 + app.processName + " ("
13695 + (app.thread != null ? app.thread.asBinder() : null)
13696 + ")\n");
13697 if (app.pid > 0 && app.pid != MY_PID) {
13698 Process.killProcess(app.pid);
13699 } else {
13700 try {
13701 app.thread.scheduleExit();
13702 } catch (Exception e) {
13703 // Ignore exceptions.
13704 }
13705 }
13706 // todo: For now we assume the application is not buggy
13707 // or evil, and will quit as a result of our request.
13708 // Eventually we need to drive this off of the death
13709 // notification, and kill the process if it takes too long.
13710 cleanUpApplicationRecordLocked(app, false, i);
13711 i--;
13712 }
13713 }
13714
13715 // If we still have too many processes, now from the least
13716 // recently used process we start finishing activities.
13717 if (Config.LOGV) Log.v(
13718 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13719 " of " + curMaxProcs + " processes");
13720 for ( i=0;
13721 i<mLRUProcesses.size()
13722 && mLRUProcesses.size() > curMaxProcs;
13723 i++) {
13724 final ProcessRecord app = mLRUProcesses.get(i);
13725 // Quit the application only if we have a state saved for
13726 // all of its activities.
13727 boolean canQuit = !app.persistent && app.curReceiver == null
13728 && app.services.size() == 0
13729 && app.persistentActivities == 0;
13730 int NUMA = app.activities.size();
13731 int j;
13732 if (Config.LOGV) Log.v(
13733 TAG, "Looking to quit " + app.processName);
13734 for (j=0; j<NUMA && canQuit; j++) {
13735 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13736 if (Config.LOGV) Log.v(
13737 TAG, " " + r.intent.getComponent().flattenToShortString()
13738 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13739 canQuit = (r.haveState || !r.stateNotNeeded)
13740 && !r.visible && r.stopped;
13741 }
13742 if (canQuit) {
13743 // Finish all of the activities, and then the app itself.
13744 for (j=0; j<NUMA; j++) {
13745 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13746 if (!r.finishing) {
13747 destroyActivityLocked(r, false);
13748 }
13749 r.resultTo = null;
13750 }
13751 Log.i(TAG, "Exiting application process "
13752 + app.processName + " ("
13753 + (app.thread != null ? app.thread.asBinder() : null)
13754 + ")\n");
13755 if (app.pid > 0 && app.pid != MY_PID) {
13756 Process.killProcess(app.pid);
13757 } else {
13758 try {
13759 app.thread.scheduleExit();
13760 } catch (Exception e) {
13761 // Ignore exceptions.
13762 }
13763 }
13764 // todo: For now we assume the application is not buggy
13765 // or evil, and will quit as a result of our request.
13766 // Eventually we need to drive this off of the death
13767 // notification, and kill the process if it takes too long.
13768 cleanUpApplicationRecordLocked(app, false, i);
13769 i--;
13770 //dump();
13771 }
13772 }
13773
13774 }
13775
13776 int curMaxActivities = MAX_ACTIVITIES;
13777 if (mAlwaysFinishActivities) {
13778 curMaxActivities = 1;
13779 }
13780
13781 // Finally, if there are too many activities now running, try to
13782 // finish as many as we can to get back down to the limit.
13783 for ( i=0;
13784 i<mLRUActivities.size()
13785 && mLRUActivities.size() > curMaxActivities;
13786 i++) {
13787 final HistoryRecord r
13788 = (HistoryRecord)mLRUActivities.get(i);
13789
13790 // We can finish this one if we have its icicle saved and
13791 // it is not persistent.
13792 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13793 && r.stopped && !r.persistent && !r.finishing) {
13794 final int origSize = mLRUActivities.size();
13795 destroyActivityLocked(r, true);
13796
13797 // This will remove it from the LRU list, so keep
13798 // our index at the same value. Note that this check to
13799 // see if the size changes is just paranoia -- if
13800 // something unexpected happens, we don't want to end up
13801 // in an infinite loop.
13802 if (origSize > mLRUActivities.size()) {
13803 i--;
13804 }
13805 }
13806 }
13807 }
13808 }
13809
13810 /** This method sends the specified signal to each of the persistent apps */
13811 public void signalPersistentProcesses(int sig) throws RemoteException {
13812 if (sig != Process.SIGNAL_USR1) {
13813 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13814 }
13815
13816 synchronized (this) {
13817 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13818 != PackageManager.PERMISSION_GRANTED) {
13819 throw new SecurityException("Requires permission "
13820 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13821 }
13822
13823 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13824 ProcessRecord r = mLRUProcesses.get(i);
13825 if (r.thread != null && r.persistent) {
13826 Process.sendSignal(r.pid, sig);
13827 }
13828 }
13829 }
13830 }
13831
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013832 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013833 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013834
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013835 try {
13836 synchronized (this) {
13837 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13838 // its own permission.
13839 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13840 != PackageManager.PERMISSION_GRANTED) {
13841 throw new SecurityException("Requires permission "
13842 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013843 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013844
13845 if (start && fd == null) {
13846 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013847 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013848
13849 ProcessRecord proc = null;
13850 try {
13851 int pid = Integer.parseInt(process);
13852 synchronized (mPidsSelfLocked) {
13853 proc = mPidsSelfLocked.get(pid);
13854 }
13855 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013856 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013857
13858 if (proc == null) {
13859 HashMap<String, SparseArray<ProcessRecord>> all
13860 = mProcessNames.getMap();
13861 SparseArray<ProcessRecord> procs = all.get(process);
13862 if (procs != null && procs.size() > 0) {
13863 proc = procs.valueAt(0);
13864 }
13865 }
13866
13867 if (proc == null || proc.thread == null) {
13868 throw new IllegalArgumentException("Unknown process: " + process);
13869 }
13870
13871 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13872 if (isSecure) {
13873 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13874 throw new SecurityException("Process not debuggable: " + proc);
13875 }
13876 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013877
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013878 proc.thread.profilerControl(start, path, fd);
13879 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013880 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013881 }
13882 } catch (RemoteException e) {
13883 throw new IllegalStateException("Process disappeared");
13884 } finally {
13885 if (fd != null) {
13886 try {
13887 fd.close();
13888 } catch (IOException e) {
13889 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013890 }
13891 }
13892 }
13893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013894 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13895 public void monitor() {
13896 synchronized (this) { }
13897 }
13898}