blob: cb9984a6ce1f49ea983341881f6fd0f7e50a25ca [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;
188
189 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
190 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
191
Dianne Hackborn1655be42009-05-08 14:29:01 -0700192 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700193 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 private static final String SYSTEM_SECURE = "ro.secure";
196
197 // This is the maximum number of application processes we would like
198 // to have running. Due to the asynchronous nature of things, we can
199 // temporarily go beyond this limit.
200 static final int MAX_PROCESSES = 2;
201
202 // Set to false to leave processes running indefinitely, relying on
203 // the kernel killing them as resources are required.
204 static final boolean ENFORCE_PROCESS_LIMIT = false;
205
206 // This is the maximum number of activities that we would like to have
207 // running at a given time.
208 static final int MAX_ACTIVITIES = 20;
209
210 // Maximum number of recent tasks that we can remember.
211 static final int MAX_RECENT_TASKS = 20;
212
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700213 // Amount of time after a call to stopAppSwitches() during which we will
214 // prevent further untrusted switches from happening.
215 static final long APP_SWITCH_DELAY_TIME = 5*1000;
216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 // How long until we reset a task when the user returns to it. Currently
218 // 30 minutes.
219 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
220
221 // Set to true to disable the icon that is shown while a new activity
222 // is being started.
223 static final boolean SHOW_APP_STARTING_ICON = true;
224
225 // How long we wait until giving up on the last activity to pause. This
226 // is short because it directly impacts the responsiveness of starting the
227 // next activity.
228 static final int PAUSE_TIMEOUT = 500;
229
230 /**
231 * How long we can hold the launch wake lock before giving up.
232 */
233 static final int LAUNCH_TIMEOUT = 10*1000;
234
235 // How long we wait for a launched process to attach to the activity manager
236 // before we decide it's never going to come up for real.
237 static final int PROC_START_TIMEOUT = 10*1000;
238
239 // How long we wait until giving up on the last activity telling us it
240 // is idle.
241 static final int IDLE_TIMEOUT = 10*1000;
242
243 // How long to wait after going idle before forcing apps to GC.
244 static final int GC_TIMEOUT = 5*1000;
245
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700246 // The minimum amount of time between successive GC requests for a process.
247 static final int GC_MIN_INTERVAL = 60*1000;
248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 // How long we wait until giving up on an activity telling us it has
250 // finished destroying itself.
251 static final int DESTROY_TIMEOUT = 10*1000;
252
253 // How long we allow a receiver to run before giving up on it.
254 static final int BROADCAST_TIMEOUT = 10*1000;
255
256 // How long we wait for a service to finish executing.
257 static final int SERVICE_TIMEOUT = 20*1000;
258
259 // How long a service needs to be running until restarting its process
260 // is no longer considered to be a relaunch of the service.
261 static final int SERVICE_RESTART_DURATION = 5*1000;
262
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700263 // How long a service needs to be running until it will start back at
264 // SERVICE_RESTART_DURATION after being killed.
265 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
266
267 // Multiplying factor to increase restart duration time by, for each time
268 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
269 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
270
271 // The minimum amount of time between restarting services that we allow.
272 // That is, when multiple services are restarting, we won't allow each
273 // to restart less than this amount of time from the last one.
274 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 // Maximum amount of time for there to be no activity on a service before
277 // we consider it non-essential and allow its process to go on the
278 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700279 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 // How long we wait until we timeout on key dispatching.
282 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
283
284 // The minimum time we allow between crashes, for us to consider this
285 // application to be bad and stop and its services and reject broadcasts.
286 static final int MIN_CRASH_INTERVAL = 60*1000;
287
288 // How long we wait until we timeout on key dispatching during instrumentation.
289 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
290
291 // OOM adjustments for processes in various states:
292
293 // This is a process without anything currently running in it. Definitely
294 // the first to go! Value set in system/rootdir/init.rc on startup.
295 // This value is initalized in the constructor, careful when refering to
296 // this static variable externally.
297 static int EMPTY_APP_ADJ;
298
299 // This is a process with a content provider that does not have any clients
300 // attached to it. If it did have any clients, its adjustment would be the
301 // one for the highest-priority of those processes.
302 static int CONTENT_PROVIDER_ADJ;
303
304 // This is a process only hosting activities that are not visible,
305 // so it can be killed without any disruption. Value set in
306 // system/rootdir/init.rc on startup.
307 final int HIDDEN_APP_MAX_ADJ;
308 static int HIDDEN_APP_MIN_ADJ;
309
The Android Open Source Project4df24232009-03-05 14:34:35 -0800310 // This is a process holding the home application -- we want to try
311 // avoiding killing it, even if it would normally be in the background,
312 // because the user interacts with it so much.
313 final int HOME_APP_ADJ;
314
Christopher Tate6fa95972009-06-05 18:43:55 -0700315 // This is a process currently hosting a backup operation. Killing it
316 // is not entirely fatal but is generally a bad idea.
317 final int BACKUP_APP_ADJ;
318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 // This is a process holding a secondary server -- killing it will not
320 // have much of an impact as far as the user is concerned. Value set in
321 // system/rootdir/init.rc on startup.
322 final int SECONDARY_SERVER_ADJ;
323
324 // This is a process only hosting activities that are visible to the
325 // user, so we'd prefer they don't disappear. Value set in
326 // system/rootdir/init.rc on startup.
327 final int VISIBLE_APP_ADJ;
328
329 // This is the process running the current foreground app. We'd really
330 // rather not kill it! Value set in system/rootdir/init.rc on startup.
331 final int FOREGROUND_APP_ADJ;
332
333 // This is a process running a core server, such as telephony. Definitely
334 // don't want to kill it, but doing so is not completely fatal.
335 static final int CORE_SERVER_ADJ = -12;
336
337 // The system process runs at the default adjustment.
338 static final int SYSTEM_ADJ = -16;
339
340 // Memory pages are 4K.
341 static final int PAGE_SIZE = 4*1024;
342
Jacek Surazski82a73df2009-06-17 14:33:18 +0200343 // System property defining error report receiver for system apps
344 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
345
346 // System property defining default error report receiver
347 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 // Corresponding memory levels for above adjustments.
350 final int EMPTY_APP_MEM;
351 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800352 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700353 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 final int SECONDARY_SERVER_MEM;
355 final int VISIBLE_APP_MEM;
356 final int FOREGROUND_APP_MEM;
357
358 final int MY_PID;
359
360 static final String[] EMPTY_STRING_ARRAY = new String[0];
361
362 enum ActivityState {
363 INITIALIZING,
364 RESUMED,
365 PAUSING,
366 PAUSED,
367 STOPPING,
368 STOPPED,
369 FINISHING,
370 DESTROYING,
371 DESTROYED
372 }
373
374 /**
375 * The back history of all previous (and possibly still
376 * running) activities. It contains HistoryRecord objects.
377 */
378 final ArrayList mHistory = new ArrayList();
379
380 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700381 * Description of a request to start a new activity, which has been held
382 * due to app switches being disabled.
383 */
384 class PendingActivityLaunch {
385 HistoryRecord r;
386 HistoryRecord sourceRecord;
387 Uri[] grantedUriPermissions;
388 int grantedMode;
389 boolean onlyIfNeeded;
390 }
391
392 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
393 = new ArrayList<PendingActivityLaunch>();
394
395 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 * List of all active broadcasts that are to be executed immediately
397 * (without waiting for another broadcast to finish). Currently this only
398 * contains broadcasts to registered receivers, to avoid spinning up
399 * a bunch of processes to execute IntentReceiver components.
400 */
401 final ArrayList<BroadcastRecord> mParallelBroadcasts
402 = new ArrayList<BroadcastRecord>();
403
404 /**
405 * List of all active broadcasts that are to be executed one at a time.
406 * The object at the top of the list is the currently activity broadcasts;
407 * those after it are waiting for the top to finish..
408 */
409 final ArrayList<BroadcastRecord> mOrderedBroadcasts
410 = new ArrayList<BroadcastRecord>();
411
412 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800413 * Historical data of past broadcasts, for debugging.
414 */
415 static final int MAX_BROADCAST_HISTORY = 100;
416 final BroadcastRecord[] mBroadcastHistory
417 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
418
419 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 * Set when we current have a BROADCAST_INTENT_MSG in flight.
421 */
422 boolean mBroadcastsScheduled = false;
423
424 /**
425 * Set to indicate whether to issue an onUserLeaving callback when a
426 * newly launched activity is being brought in front of us.
427 */
428 boolean mUserLeaving = false;
429
430 /**
431 * When we are in the process of pausing an activity, before starting the
432 * next one, this variable holds the activity that is currently being paused.
433 */
434 HistoryRecord mPausingActivity = null;
435
436 /**
437 * Current activity that is resumed, or null if there is none.
438 */
439 HistoryRecord mResumedActivity = null;
440
441 /**
442 * Activity we have told the window manager to have key focus.
443 */
444 HistoryRecord mFocusedActivity = null;
445
446 /**
447 * This is the last activity that we put into the paused state. This is
448 * used to determine if we need to do an activity transition while sleeping,
449 * when we normally hold the top activity paused.
450 */
451 HistoryRecord mLastPausedActivity = null;
452
453 /**
454 * List of activities that are waiting for a new activity
455 * to become visible before completing whatever operation they are
456 * supposed to do.
457 */
458 final ArrayList mWaitingVisibleActivities = new ArrayList();
459
460 /**
461 * List of activities that are ready to be stopped, but waiting
462 * for the next activity to settle down before doing so. It contains
463 * HistoryRecord objects.
464 */
465 final ArrayList<HistoryRecord> mStoppingActivities
466 = new ArrayList<HistoryRecord>();
467
468 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700469 * Animations that for the current transition have requested not to
470 * be considered for the transition animation.
471 */
472 final ArrayList<HistoryRecord> mNoAnimActivities
473 = new ArrayList<HistoryRecord>();
474
475 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 * List of intents that were used to start the most recent tasks.
477 */
478 final ArrayList<TaskRecord> mRecentTasks
479 = new ArrayList<TaskRecord>();
480
481 /**
482 * List of activities that are ready to be finished, but waiting
483 * for the previous activity to settle down before doing so. It contains
484 * HistoryRecord objects.
485 */
486 final ArrayList mFinishingActivities = new ArrayList();
487
488 /**
489 * All of the applications we currently have running organized by name.
490 * The keys are strings of the application package name (as
491 * returned by the package manager), and the keys are ApplicationRecord
492 * objects.
493 */
494 final ProcessMap<ProcessRecord> mProcessNames
495 = new ProcessMap<ProcessRecord>();
496
497 /**
498 * The last time that various processes have crashed.
499 */
500 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
501
502 /**
503 * Set of applications that we consider to be bad, and will reject
504 * incoming broadcasts from (which the user has no control over).
505 * Processes are added to this set when they have crashed twice within
506 * a minimum amount of time; they are removed from it when they are
507 * later restarted (hopefully due to some user action). The value is the
508 * time it was added to the list.
509 */
510 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
511
512 /**
513 * All of the processes we currently have running organized by pid.
514 * The keys are the pid running the application.
515 *
516 * <p>NOTE: This object is protected by its own lock, NOT the global
517 * activity manager lock!
518 */
519 final SparseArray<ProcessRecord> mPidsSelfLocked
520 = new SparseArray<ProcessRecord>();
521
522 /**
523 * All of the processes that have been forced to be foreground. The key
524 * is the pid of the caller who requested it (we hold a death
525 * link on it).
526 */
527 abstract class ForegroundToken implements IBinder.DeathRecipient {
528 int pid;
529 IBinder token;
530 }
531 final SparseArray<ForegroundToken> mForegroundProcesses
532 = new SparseArray<ForegroundToken>();
533
534 /**
535 * List of records for processes that someone had tried to start before the
536 * system was ready. We don't start them at that point, but ensure they
537 * are started by the time booting is complete.
538 */
539 final ArrayList<ProcessRecord> mProcessesOnHold
540 = new ArrayList<ProcessRecord>();
541
542 /**
543 * List of records for processes that we have started and are waiting
544 * for them to call back. This is really only needed when running in
545 * single processes mode, in which case we do not have a unique pid for
546 * each process.
547 */
548 final ArrayList<ProcessRecord> mStartingProcesses
549 = new ArrayList<ProcessRecord>();
550
551 /**
552 * List of persistent applications that are in the process
553 * of being started.
554 */
555 final ArrayList<ProcessRecord> mPersistentStartingProcesses
556 = new ArrayList<ProcessRecord>();
557
558 /**
559 * Processes that are being forcibly torn down.
560 */
561 final ArrayList<ProcessRecord> mRemovedProcesses
562 = new ArrayList<ProcessRecord>();
563
564 /**
565 * List of running applications, sorted by recent usage.
566 * The first entry in the list is the least recently used.
567 * It contains ApplicationRecord objects. This list does NOT include
568 * any persistent application records (since we never want to exit them).
569 */
570 final ArrayList<ProcessRecord> mLRUProcesses
571 = new ArrayList<ProcessRecord>();
572
573 /**
574 * List of processes that should gc as soon as things are idle.
575 */
576 final ArrayList<ProcessRecord> mProcessesToGc
577 = new ArrayList<ProcessRecord>();
578
579 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800580 * This is the process holding what we currently consider to be
581 * the "home" activity.
582 */
583 private ProcessRecord mHomeProcess;
584
585 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 * List of running activities, sorted by recent usage.
587 * The first entry in the list is the least recently used.
588 * It contains HistoryRecord objects.
589 */
590 private final ArrayList mLRUActivities = new ArrayList();
591
592 /**
593 * Set of PendingResultRecord objects that are currently active.
594 */
595 final HashSet mPendingResultRecords = new HashSet();
596
597 /**
598 * Set of IntentSenderRecord objects that are currently active.
599 */
600 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
601 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
602
603 /**
604 * Intent broadcast that we have tried to start, but are
605 * waiting for its application's process to be created. We only
606 * need one (instead of a list) because we always process broadcasts
607 * one at a time, so no others can be started while waiting for this
608 * one.
609 */
610 BroadcastRecord mPendingBroadcast = null;
611
612 /**
613 * Keeps track of all IIntentReceivers that have been registered for
614 * broadcasts. Hash keys are the receiver IBinder, hash value is
615 * a ReceiverList.
616 */
617 final HashMap mRegisteredReceivers = new HashMap();
618
619 /**
620 * Resolver for broadcast intents to registered receivers.
621 * Holds BroadcastFilter (subclass of IntentFilter).
622 */
623 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
624 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
625 @Override
626 protected boolean allowFilterResult(
627 BroadcastFilter filter, List<BroadcastFilter> dest) {
628 IBinder target = filter.receiverList.receiver.asBinder();
629 for (int i=dest.size()-1; i>=0; i--) {
630 if (dest.get(i).receiverList.receiver.asBinder() == target) {
631 return false;
632 }
633 }
634 return true;
635 }
636 };
637
638 /**
639 * State of all active sticky broadcasts. Keys are the action of the
640 * sticky Intent, values are an ArrayList of all broadcasted intents with
641 * that action (which should usually be one).
642 */
643 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
644 new HashMap<String, ArrayList<Intent>>();
645
646 /**
647 * All currently running services.
648 */
649 final HashMap<ComponentName, ServiceRecord> mServices =
650 new HashMap<ComponentName, ServiceRecord>();
651
652 /**
653 * All currently running services indexed by the Intent used to start them.
654 */
655 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
656 new HashMap<Intent.FilterComparison, ServiceRecord>();
657
658 /**
659 * All currently bound service connections. Keys are the IBinder of
660 * the client's IServiceConnection.
661 */
662 final HashMap<IBinder, ConnectionRecord> mServiceConnections
663 = new HashMap<IBinder, ConnectionRecord>();
664
665 /**
666 * List of services that we have been asked to start,
667 * but haven't yet been able to. It is used to hold start requests
668 * while waiting for their corresponding application thread to get
669 * going.
670 */
671 final ArrayList<ServiceRecord> mPendingServices
672 = new ArrayList<ServiceRecord>();
673
674 /**
675 * List of services that are scheduled to restart following a crash.
676 */
677 final ArrayList<ServiceRecord> mRestartingServices
678 = new ArrayList<ServiceRecord>();
679
680 /**
681 * List of services that are in the process of being stopped.
682 */
683 final ArrayList<ServiceRecord> mStoppingServices
684 = new ArrayList<ServiceRecord>();
685
686 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700687 * Backup/restore process management
688 */
689 String mBackupAppName = null;
690 BackupRecord mBackupTarget = null;
691
692 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 * List of PendingThumbnailsRecord objects of clients who are still
694 * waiting to receive all of the thumbnails for a task.
695 */
696 final ArrayList mPendingThumbnails = new ArrayList();
697
698 /**
699 * List of HistoryRecord objects that have been finished and must
700 * still report back to a pending thumbnail receiver.
701 */
702 final ArrayList mCancelledThumbnails = new ArrayList();
703
704 /**
705 * All of the currently running global content providers. Keys are a
706 * string containing the provider name and values are a
707 * ContentProviderRecord object containing the data about it. Note
708 * that a single provider may be published under multiple names, so
709 * there may be multiple entries here for a single one in mProvidersByClass.
710 */
711 final HashMap mProvidersByName = new HashMap();
712
713 /**
714 * All of the currently running global content providers. Keys are a
715 * string containing the provider's implementation class and values are a
716 * ContentProviderRecord object containing the data about it.
717 */
718 final HashMap mProvidersByClass = new HashMap();
719
720 /**
721 * List of content providers who have clients waiting for them. The
722 * application is currently being launched and the provider will be
723 * removed from this list once it is published.
724 */
725 final ArrayList mLaunchingProviders = new ArrayList();
726
727 /**
728 * Global set of specific Uri permissions that have been granted.
729 */
730 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
731 = new SparseArray<HashMap<Uri, UriPermission>>();
732
733 /**
734 * Thread-local storage used to carry caller permissions over through
735 * indirect content-provider access.
736 * @see #ActivityManagerService.openContentUri()
737 */
738 private class Identity {
739 public int pid;
740 public int uid;
741
742 Identity(int _pid, int _uid) {
743 pid = _pid;
744 uid = _uid;
745 }
746 }
747 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
748
749 /**
750 * All information we have collected about the runtime performance of
751 * any user id that can impact battery performance.
752 */
753 final BatteryStatsService mBatteryStatsService;
754
755 /**
756 * information about component usage
757 */
758 final UsageStatsService mUsageStatsService;
759
760 /**
761 * Current configuration information. HistoryRecord objects are given
762 * a reference to this object to indicate which configuration they are
763 * currently running in, so this object must be kept immutable.
764 */
765 Configuration mConfiguration = new Configuration();
766
767 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700768 * Hardware-reported OpenGLES version.
769 */
770 final int GL_ES_VERSION;
771
772 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 * List of initialization arguments to pass to all processes when binding applications to them.
774 * For example, references to the commonly used services.
775 */
776 HashMap<String, IBinder> mAppBindArgs;
777
778 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700779 * Temporary to avoid allocations. Protected by main lock.
780 */
781 final StringBuilder mStringBuilder = new StringBuilder(256);
782
783 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 * Used to control how we initialize the service.
785 */
786 boolean mStartRunning = false;
787 ComponentName mTopComponent;
788 String mTopAction;
789 String mTopData;
790 boolean mSystemReady = false;
791 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700792 boolean mWaitingUpdate = false;
793 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794
795 Context mContext;
796
797 int mFactoryTest;
798
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700799 boolean mCheckedForSetup;
800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700802 * The time at which we will allow normal application switches again,
803 * after a call to {@link #stopAppSwitches()}.
804 */
805 long mAppSwitchesAllowedTime;
806
807 /**
808 * This is set to true after the first switch after mAppSwitchesAllowedTime
809 * is set; any switches after that will clear the time.
810 */
811 boolean mDidAppSwitch;
812
813 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 * Set while we are wanting to sleep, to prevent any
815 * activities from being started/resumed.
816 */
817 boolean mSleeping = false;
818
819 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700820 * Set if we are shutting down the system, similar to sleeping.
821 */
822 boolean mShuttingDown = false;
823
824 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 * Set when the system is going to sleep, until we have
826 * successfully paused the current activity and released our wake lock.
827 * At that point the system is allowed to actually sleep.
828 */
829 PowerManager.WakeLock mGoingToSleep;
830
831 /**
832 * We don't want to allow the device to go to sleep while in the process
833 * of launching an activity. This is primarily to allow alarm intent
834 * receivers to launch an activity and get that to run before the device
835 * goes back to sleep.
836 */
837 PowerManager.WakeLock mLaunchingActivity;
838
839 /**
840 * Task identifier that activities are currently being started
841 * in. Incremented each time a new task is created.
842 * todo: Replace this with a TokenSpace class that generates non-repeating
843 * integers that won't wrap.
844 */
845 int mCurTask = 1;
846
847 /**
848 * Current sequence id for oom_adj computation traversal.
849 */
850 int mAdjSeq = 0;
851
852 /**
853 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
854 * is set, indicating the user wants processes started in such a way
855 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
856 * running in each process (thus no pre-initialized process, etc).
857 */
858 boolean mSimpleProcessManagement = false;
859
860 /**
861 * System monitoring: number of processes that died since the last
862 * N procs were started.
863 */
864 int[] mProcDeaths = new int[20];
865
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700866 /**
867 * This is set if we had to do a delayed dexopt of an app before launching
868 * it, to increasing the ANR timeouts in that case.
869 */
870 boolean mDidDexOpt;
871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 String mDebugApp = null;
873 boolean mWaitForDebugger = false;
874 boolean mDebugTransient = false;
875 String mOrigDebugApp = null;
876 boolean mOrigWaitForDebugger = false;
877 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700878 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700880 final RemoteCallbackList<IActivityWatcher> mWatchers
881 = new RemoteCallbackList<IActivityWatcher>();
882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 /**
884 * Callback of last caller to {@link #requestPss}.
885 */
886 Runnable mRequestPssCallback;
887
888 /**
889 * Remaining processes for which we are waiting results from the last
890 * call to {@link #requestPss}.
891 */
892 final ArrayList<ProcessRecord> mRequestPssList
893 = new ArrayList<ProcessRecord>();
894
895 /**
896 * Runtime statistics collection thread. This object's lock is used to
897 * protect all related state.
898 */
899 final Thread mProcessStatsThread;
900
901 /**
902 * Used to collect process stats when showing not responding dialog.
903 * Protected by mProcessStatsThread.
904 */
905 final ProcessStats mProcessStats = new ProcessStats(
906 MONITOR_THREAD_CPU_USAGE);
907 long mLastCpuTime = 0;
908 long mLastWriteTime = 0;
909
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700910 long mInitialStartTime = 0;
911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 /**
913 * Set to true after the system has finished booting.
914 */
915 boolean mBooted = false;
916
917 int mProcessLimit = 0;
918
919 WindowManagerService mWindowManager;
920
921 static ActivityManagerService mSelf;
922 static ActivityThread mSystemThread;
923
924 private final class AppDeathRecipient implements IBinder.DeathRecipient {
925 final ProcessRecord mApp;
926 final int mPid;
927 final IApplicationThread mAppThread;
928
929 AppDeathRecipient(ProcessRecord app, int pid,
930 IApplicationThread thread) {
931 if (localLOGV) Log.v(
932 TAG, "New death recipient " + this
933 + " for thread " + thread.asBinder());
934 mApp = app;
935 mPid = pid;
936 mAppThread = thread;
937 }
938
939 public void binderDied() {
940 if (localLOGV) Log.v(
941 TAG, "Death received in " + this
942 + " for thread " + mAppThread.asBinder());
943 removeRequestedPss(mApp);
944 synchronized(ActivityManagerService.this) {
945 appDiedLocked(mApp, mPid, mAppThread);
946 }
947 }
948 }
949
950 static final int SHOW_ERROR_MSG = 1;
951 static final int SHOW_NOT_RESPONDING_MSG = 2;
952 static final int SHOW_FACTORY_ERROR_MSG = 3;
953 static final int UPDATE_CONFIGURATION_MSG = 4;
954 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
955 static final int WAIT_FOR_DEBUGGER_MSG = 6;
956 static final int BROADCAST_INTENT_MSG = 7;
957 static final int BROADCAST_TIMEOUT_MSG = 8;
958 static final int PAUSE_TIMEOUT_MSG = 9;
959 static final int IDLE_TIMEOUT_MSG = 10;
960 static final int IDLE_NOW_MSG = 11;
961 static final int SERVICE_TIMEOUT_MSG = 12;
962 static final int UPDATE_TIME_ZONE = 13;
963 static final int SHOW_UID_ERROR_MSG = 14;
964 static final int IM_FEELING_LUCKY_MSG = 15;
965 static final int LAUNCH_TIMEOUT_MSG = 16;
966 static final int DESTROY_TIMEOUT_MSG = 17;
967 static final int SERVICE_ERROR_MSG = 18;
968 static final int RESUME_TOP_ACTIVITY_MSG = 19;
969 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700970 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700971 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972
973 AlertDialog mUidAlert;
974
975 final Handler mHandler = new Handler() {
976 //public Handler() {
977 // if (localLOGV) Log.v(TAG, "Handler started!");
978 //}
979
980 public void handleMessage(Message msg) {
981 switch (msg.what) {
982 case SHOW_ERROR_MSG: {
983 HashMap data = (HashMap) msg.obj;
984 byte[] crashData = (byte[])data.get("crashData");
985 if (crashData != null) {
986 // This needs to be *un*synchronized to avoid deadlock.
987 ContentResolver resolver = mContext.getContentResolver();
988 Checkin.reportCrash(resolver, crashData);
989 }
990 synchronized (ActivityManagerService.this) {
991 ProcessRecord proc = (ProcessRecord)data.get("app");
992 if (proc != null && proc.crashDialog != null) {
993 Log.e(TAG, "App already has crash dialog: " + proc);
994 return;
995 }
996 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700997 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 Dialog d = new AppErrorDialog(
999 mContext, res, proc,
1000 (Integer)data.get("flags"),
1001 (String)data.get("shortMsg"),
1002 (String)data.get("longMsg"));
1003 d.show();
1004 proc.crashDialog = d;
1005 } else {
1006 // The device is asleep, so just pretend that the user
1007 // saw a crash dialog and hit "force quit".
1008 res.set(0);
1009 }
1010 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001011
1012 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 } break;
1014 case SHOW_NOT_RESPONDING_MSG: {
1015 synchronized (ActivityManagerService.this) {
1016 HashMap data = (HashMap) msg.obj;
1017 ProcessRecord proc = (ProcessRecord)data.get("app");
1018 if (proc != null && proc.anrDialog != null) {
1019 Log.e(TAG, "App already has anr dialog: " + proc);
1020 return;
1021 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001022
1023 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1024 null, null, 0, null, null, null,
1025 false, false, MY_PID, Process.SYSTEM_UID);
1026
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1028 mContext, proc, (HistoryRecord)data.get("activity"));
1029 d.show();
1030 proc.anrDialog = d;
1031 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001032
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001033 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 } break;
1035 case SHOW_FACTORY_ERROR_MSG: {
1036 Dialog d = new FactoryErrorDialog(
1037 mContext, msg.getData().getCharSequence("msg"));
1038 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001039 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 } break;
1041 case UPDATE_CONFIGURATION_MSG: {
1042 final ContentResolver resolver = mContext.getContentResolver();
1043 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1044 } break;
1045 case GC_BACKGROUND_PROCESSES_MSG: {
1046 synchronized (ActivityManagerService.this) {
1047 performAppGcsIfAppropriateLocked();
1048 }
1049 } break;
1050 case WAIT_FOR_DEBUGGER_MSG: {
1051 synchronized (ActivityManagerService.this) {
1052 ProcessRecord app = (ProcessRecord)msg.obj;
1053 if (msg.arg1 != 0) {
1054 if (!app.waitedForDebugger) {
1055 Dialog d = new AppWaitingForDebuggerDialog(
1056 ActivityManagerService.this,
1057 mContext, app);
1058 app.waitDialog = d;
1059 app.waitedForDebugger = true;
1060 d.show();
1061 }
1062 } else {
1063 if (app.waitDialog != null) {
1064 app.waitDialog.dismiss();
1065 app.waitDialog = null;
1066 }
1067 }
1068 }
1069 } break;
1070 case BROADCAST_INTENT_MSG: {
1071 if (DEBUG_BROADCAST) Log.v(
1072 TAG, "Received BROADCAST_INTENT_MSG");
1073 processNextBroadcast(true);
1074 } break;
1075 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001076 if (mDidDexOpt) {
1077 mDidDexOpt = false;
1078 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1079 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1080 return;
1081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 broadcastTimeout();
1083 } break;
1084 case PAUSE_TIMEOUT_MSG: {
1085 IBinder token = (IBinder)msg.obj;
1086 // We don't at this point know if the activity is fullscreen,
1087 // so we need to be conservative and assume it isn't.
1088 Log.w(TAG, "Activity pause timeout for " + token);
1089 activityPaused(token, null, true);
1090 } break;
1091 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001092 if (mDidDexOpt) {
1093 mDidDexOpt = false;
1094 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1095 nmsg.obj = msg.obj;
1096 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1097 return;
1098 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 // We don't at this point know if the activity is fullscreen,
1100 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001101 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001103 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 } break;
1105 case DESTROY_TIMEOUT_MSG: {
1106 IBinder token = (IBinder)msg.obj;
1107 // We don't at this point know if the activity is fullscreen,
1108 // so we need to be conservative and assume it isn't.
1109 Log.w(TAG, "Activity destroy timeout for " + token);
1110 activityDestroyed(token);
1111 } break;
1112 case IDLE_NOW_MSG: {
1113 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001114 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 } break;
1116 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001117 if (mDidDexOpt) {
1118 mDidDexOpt = false;
1119 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1120 nmsg.obj = msg.obj;
1121 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1122 return;
1123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 serviceTimeout((ProcessRecord)msg.obj);
1125 } break;
1126 case UPDATE_TIME_ZONE: {
1127 synchronized (ActivityManagerService.this) {
1128 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1129 ProcessRecord r = mLRUProcesses.get(i);
1130 if (r.thread != null) {
1131 try {
1132 r.thread.updateTimeZone();
1133 } catch (RemoteException ex) {
1134 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1135 }
1136 }
1137 }
1138 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001139 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 case SHOW_UID_ERROR_MSG: {
1141 // XXX This is a temporary dialog, no need to localize.
1142 AlertDialog d = new BaseErrorDialog(mContext);
1143 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1144 d.setCancelable(false);
1145 d.setTitle("System UIDs Inconsistent");
1146 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1147 d.setButton("I'm Feeling Lucky",
1148 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1149 mUidAlert = d;
1150 d.show();
1151 } break;
1152 case IM_FEELING_LUCKY_MSG: {
1153 if (mUidAlert != null) {
1154 mUidAlert.dismiss();
1155 mUidAlert = null;
1156 }
1157 } break;
1158 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001159 if (mDidDexOpt) {
1160 mDidDexOpt = false;
1161 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1162 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1163 return;
1164 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 synchronized (ActivityManagerService.this) {
1166 if (mLaunchingActivity.isHeld()) {
1167 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1168 mLaunchingActivity.release();
1169 }
1170 }
1171 } break;
1172 case SERVICE_ERROR_MSG: {
1173 ServiceRecord srv = (ServiceRecord)msg.obj;
1174 // This needs to be *un*synchronized to avoid deadlock.
1175 Checkin.logEvent(mContext.getContentResolver(),
1176 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1177 srv.name.toShortString());
1178 } break;
1179 case RESUME_TOP_ACTIVITY_MSG: {
1180 synchronized (ActivityManagerService.this) {
1181 resumeTopActivityLocked(null);
1182 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001183 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001185 if (mDidDexOpt) {
1186 mDidDexOpt = false;
1187 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1188 nmsg.obj = msg.obj;
1189 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1190 return;
1191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 ProcessRecord app = (ProcessRecord)msg.obj;
1193 synchronized (ActivityManagerService.this) {
1194 processStartTimedOutLocked(app);
1195 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001196 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001197 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1198 synchronized (ActivityManagerService.this) {
1199 doPendingActivityLaunchesLocked(true);
1200 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001201 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001202 case KILL_APPLICATION_MSG: {
1203 synchronized (ActivityManagerService.this) {
1204 int uid = msg.arg1;
1205 boolean restart = (msg.arg2 == 1);
1206 String pkg = (String) msg.obj;
1207 uninstallPackageLocked(pkg, uid, restart);
1208 }
1209 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 }
1211 }
1212 };
1213
1214 public static void setSystemProcess() {
1215 try {
1216 ActivityManagerService m = mSelf;
1217
1218 ServiceManager.addService("activity", m);
1219 ServiceManager.addService("meminfo", new MemBinder(m));
1220 if (MONITOR_CPU_USAGE) {
1221 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1222 }
1223 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1224 ServiceManager.addService("activity.services", new ServicesBinder(m));
1225 ServiceManager.addService("activity.senders", new SendersBinder(m));
1226 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1227 ServiceManager.addService("permission", new PermissionController(m));
1228
1229 ApplicationInfo info =
1230 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001231 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001232 mSystemThread.installSystemApplicationInfo(info);
1233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 synchronized (mSelf) {
1235 ProcessRecord app = mSelf.newProcessRecordLocked(
1236 mSystemThread.getApplicationThread(), info,
1237 info.processName);
1238 app.persistent = true;
1239 app.pid = Process.myPid();
1240 app.maxAdj = SYSTEM_ADJ;
1241 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1242 synchronized (mSelf.mPidsSelfLocked) {
1243 mSelf.mPidsSelfLocked.put(app.pid, app);
1244 }
1245 mSelf.updateLRUListLocked(app, true);
1246 }
1247 } catch (PackageManager.NameNotFoundException e) {
1248 throw new RuntimeException(
1249 "Unable to find android system package", e);
1250 }
1251 }
1252
1253 public void setWindowManager(WindowManagerService wm) {
1254 mWindowManager = wm;
1255 }
1256
1257 public static final Context main(int factoryTest) {
1258 AThread thr = new AThread();
1259 thr.start();
1260
1261 synchronized (thr) {
1262 while (thr.mService == null) {
1263 try {
1264 thr.wait();
1265 } catch (InterruptedException e) {
1266 }
1267 }
1268 }
1269
1270 ActivityManagerService m = thr.mService;
1271 mSelf = m;
1272 ActivityThread at = ActivityThread.systemMain();
1273 mSystemThread = at;
1274 Context context = at.getSystemContext();
1275 m.mContext = context;
1276 m.mFactoryTest = factoryTest;
1277 PowerManager pm =
1278 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1279 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1280 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1281 m.mLaunchingActivity.setReferenceCounted(false);
1282
1283 m.mBatteryStatsService.publish(context);
1284 m.mUsageStatsService.publish(context);
1285
1286 synchronized (thr) {
1287 thr.mReady = true;
1288 thr.notifyAll();
1289 }
1290
1291 m.startRunning(null, null, null, null);
1292
1293 return context;
1294 }
1295
1296 public static ActivityManagerService self() {
1297 return mSelf;
1298 }
1299
1300 static class AThread extends Thread {
1301 ActivityManagerService mService;
1302 boolean mReady = false;
1303
1304 public AThread() {
1305 super("ActivityManager");
1306 }
1307
1308 public void run() {
1309 Looper.prepare();
1310
1311 android.os.Process.setThreadPriority(
1312 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1313
1314 ActivityManagerService m = new ActivityManagerService();
1315
1316 synchronized (this) {
1317 mService = m;
1318 notifyAll();
1319 }
1320
1321 synchronized (this) {
1322 while (!mReady) {
1323 try {
1324 wait();
1325 } catch (InterruptedException e) {
1326 }
1327 }
1328 }
1329
1330 Looper.loop();
1331 }
1332 }
1333
1334 static class BroadcastsBinder extends Binder {
1335 ActivityManagerService mActivityManagerService;
1336 BroadcastsBinder(ActivityManagerService activityManagerService) {
1337 mActivityManagerService = activityManagerService;
1338 }
1339
1340 @Override
1341 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1342 mActivityManagerService.dumpBroadcasts(pw);
1343 }
1344 }
1345
1346 static class ServicesBinder extends Binder {
1347 ActivityManagerService mActivityManagerService;
1348 ServicesBinder(ActivityManagerService activityManagerService) {
1349 mActivityManagerService = activityManagerService;
1350 }
1351
1352 @Override
1353 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1354 mActivityManagerService.dumpServices(pw);
1355 }
1356 }
1357
1358 static class SendersBinder extends Binder {
1359 ActivityManagerService mActivityManagerService;
1360 SendersBinder(ActivityManagerService activityManagerService) {
1361 mActivityManagerService = activityManagerService;
1362 }
1363
1364 @Override
1365 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1366 mActivityManagerService.dumpSenders(pw);
1367 }
1368 }
1369
1370 static class ProvidersBinder extends Binder {
1371 ActivityManagerService mActivityManagerService;
1372 ProvidersBinder(ActivityManagerService activityManagerService) {
1373 mActivityManagerService = activityManagerService;
1374 }
1375
1376 @Override
1377 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1378 mActivityManagerService.dumpProviders(pw);
1379 }
1380 }
1381
1382 static class MemBinder extends Binder {
1383 ActivityManagerService mActivityManagerService;
1384 MemBinder(ActivityManagerService activityManagerService) {
1385 mActivityManagerService = activityManagerService;
1386 }
1387
1388 @Override
1389 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1390 ActivityManagerService service = mActivityManagerService;
1391 ArrayList<ProcessRecord> procs;
1392 synchronized (mActivityManagerService) {
1393 if (args != null && args.length > 0
1394 && args[0].charAt(0) != '-') {
1395 procs = new ArrayList<ProcessRecord>();
1396 int pid = -1;
1397 try {
1398 pid = Integer.parseInt(args[0]);
1399 } catch (NumberFormatException e) {
1400
1401 }
1402 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1403 ProcessRecord proc = service.mLRUProcesses.get(i);
1404 if (proc.pid == pid) {
1405 procs.add(proc);
1406 } else if (proc.processName.equals(args[0])) {
1407 procs.add(proc);
1408 }
1409 }
1410 if (procs.size() <= 0) {
1411 pw.println("No process found for: " + args[0]);
1412 return;
1413 }
1414 } else {
1415 procs = service.mLRUProcesses;
1416 }
1417 }
1418 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1419 }
1420 }
1421
1422 static class CpuBinder extends Binder {
1423 ActivityManagerService mActivityManagerService;
1424 CpuBinder(ActivityManagerService activityManagerService) {
1425 mActivityManagerService = activityManagerService;
1426 }
1427
1428 @Override
1429 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1430 synchronized (mActivityManagerService.mProcessStatsThread) {
1431 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1432 }
1433 }
1434 }
1435
1436 private ActivityManagerService() {
1437 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1438 if (v != null && Integer.getInteger(v) != 0) {
1439 mSimpleProcessManagement = true;
1440 }
1441 v = System.getenv("ANDROID_DEBUG_APP");
1442 if (v != null) {
1443 mSimpleProcessManagement = true;
1444 }
1445
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001446 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 MY_PID = Process.myPid();
1449
1450 File dataDir = Environment.getDataDirectory();
1451 File systemDir = new File(dataDir, "system");
1452 systemDir.mkdirs();
1453 mBatteryStatsService = new BatteryStatsService(new File(
1454 systemDir, "batterystats.bin").toString());
1455 mBatteryStatsService.getActiveStatistics().readLocked();
1456 mBatteryStatsService.getActiveStatistics().writeLocked();
1457
1458 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001459 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460
Jack Palevichb90d28c2009-07-22 15:35:24 -07001461 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1462 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 mConfiguration.makeDefault();
1465 mProcessStats.init();
1466
1467 // Add ourself to the Watchdog monitors.
1468 Watchdog.getInstance().addMonitor(this);
1469
1470 // These values are set in system/rootdir/init.rc on startup.
1471 FOREGROUND_APP_ADJ =
1472 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1473 VISIBLE_APP_ADJ =
1474 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1475 SECONDARY_SERVER_ADJ =
1476 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001477 BACKUP_APP_ADJ =
1478 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001479 HOME_APP_ADJ =
1480 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 HIDDEN_APP_MIN_ADJ =
1482 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1483 CONTENT_PROVIDER_ADJ =
1484 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1485 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1486 EMPTY_APP_ADJ =
1487 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1488 FOREGROUND_APP_MEM =
1489 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1490 VISIBLE_APP_MEM =
1491 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1492 SECONDARY_SERVER_MEM =
1493 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001494 BACKUP_APP_MEM =
1495 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001496 HOME_APP_MEM =
1497 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 HIDDEN_APP_MEM =
1499 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1500 EMPTY_APP_MEM =
1501 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1502
1503 mProcessStatsThread = new Thread("ProcessStats") {
1504 public void run() {
1505 while (true) {
1506 try {
1507 try {
1508 synchronized(this) {
1509 final long now = SystemClock.uptimeMillis();
1510 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1511 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1512 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1513 // + ", write delay=" + nextWriteDelay);
1514 if (nextWriteDelay < nextCpuDelay) {
1515 nextCpuDelay = nextWriteDelay;
1516 }
1517 if (nextCpuDelay > 0) {
1518 this.wait(nextCpuDelay);
1519 }
1520 }
1521 } catch (InterruptedException e) {
1522 }
1523
1524 updateCpuStatsNow();
1525 } catch (Exception e) {
1526 Log.e(TAG, "Unexpected exception collecting process stats", e);
1527 }
1528 }
1529 }
1530 };
1531 mProcessStatsThread.start();
1532 }
1533
1534 @Override
1535 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1536 throws RemoteException {
1537 try {
1538 return super.onTransact(code, data, reply, flags);
1539 } catch (RuntimeException e) {
1540 // The activity manager only throws security exceptions, so let's
1541 // log all others.
1542 if (!(e instanceof SecurityException)) {
1543 Log.e(TAG, "Activity Manager Crash", e);
1544 }
1545 throw e;
1546 }
1547 }
1548
1549 void updateCpuStats() {
1550 synchronized (mProcessStatsThread) {
1551 final long now = SystemClock.uptimeMillis();
1552 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1553 mProcessStatsThread.notify();
1554 }
1555 }
1556 }
1557
1558 void updateCpuStatsNow() {
1559 synchronized (mProcessStatsThread) {
1560 final long now = SystemClock.uptimeMillis();
1561 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 if (MONITOR_CPU_USAGE &&
1564 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1565 mLastCpuTime = now;
1566 haveNewCpuStats = true;
1567 mProcessStats.update();
1568 //Log.i(TAG, mProcessStats.printCurrentState());
1569 //Log.i(TAG, "Total CPU usage: "
1570 // + mProcessStats.getTotalCpuPercent() + "%");
1571
1572 // Log the cpu usage if the property is set.
1573 if ("true".equals(SystemProperties.get("events.cpu"))) {
1574 int user = mProcessStats.getLastUserTime();
1575 int system = mProcessStats.getLastSystemTime();
1576 int iowait = mProcessStats.getLastIoWaitTime();
1577 int irq = mProcessStats.getLastIrqTime();
1578 int softIrq = mProcessStats.getLastSoftIrqTime();
1579 int idle = mProcessStats.getLastIdleTime();
1580
1581 int total = user + system + iowait + irq + softIrq + idle;
1582 if (total == 0) total = 1;
1583
1584 EventLog.writeEvent(LOG_CPU,
1585 ((user+system+iowait+irq+softIrq) * 100) / total,
1586 (user * 100) / total,
1587 (system * 100) / total,
1588 (iowait * 100) / total,
1589 (irq * 100) / total,
1590 (softIrq * 100) / total);
1591 }
1592 }
1593
Amith Yamasanie43530a2009-08-21 13:11:37 -07001594 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001595 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001596 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 synchronized(mPidsSelfLocked) {
1598 if (haveNewCpuStats) {
1599 if (mBatteryStatsService.isOnBattery()) {
1600 final int N = mProcessStats.countWorkingStats();
1601 for (int i=0; i<N; i++) {
1602 ProcessStats.Stats st
1603 = mProcessStats.getWorkingStats(i);
1604 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1605 if (pr != null) {
1606 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1607 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001608 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001609 } else {
1610 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001611 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001612 if (ps != null) {
1613 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001614 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 }
1617 }
1618 }
1619 }
1620 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1623 mLastWriteTime = now;
1624 mBatteryStatsService.getActiveStatistics().writeLocked();
1625 }
1626 }
1627 }
1628 }
1629
1630 /**
1631 * Initialize the application bind args. These are passed to each
1632 * process when the bindApplication() IPC is sent to the process. They're
1633 * lazily setup to make sure the services are running when they're asked for.
1634 */
1635 private HashMap<String, IBinder> getCommonServicesLocked() {
1636 if (mAppBindArgs == null) {
1637 mAppBindArgs = new HashMap<String, IBinder>();
1638
1639 // Setup the application init args
1640 mAppBindArgs.put("package", ServiceManager.getService("package"));
1641 mAppBindArgs.put("window", ServiceManager.getService("window"));
1642 mAppBindArgs.put(Context.ALARM_SERVICE,
1643 ServiceManager.getService(Context.ALARM_SERVICE));
1644 }
1645 return mAppBindArgs;
1646 }
1647
1648 private final void setFocusedActivityLocked(HistoryRecord r) {
1649 if (mFocusedActivity != r) {
1650 mFocusedActivity = r;
1651 mWindowManager.setFocusedApp(r, true);
1652 }
1653 }
1654
1655 private final void updateLRUListLocked(ProcessRecord app,
1656 boolean oomAdj) {
1657 // put it on the LRU to keep track of when it should be exited.
1658 int lrui = mLRUProcesses.indexOf(app);
1659 if (lrui >= 0) mLRUProcesses.remove(lrui);
1660 mLRUProcesses.add(app);
1661 //Log.i(TAG, "Putting proc to front: " + app.processName);
1662 if (oomAdj) {
1663 updateOomAdjLocked();
1664 }
1665 }
1666
1667 private final boolean updateLRUListLocked(HistoryRecord r) {
1668 final boolean hadit = mLRUActivities.remove(r);
1669 mLRUActivities.add(r);
1670 return hadit;
1671 }
1672
1673 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1674 int i = mHistory.size()-1;
1675 while (i >= 0) {
1676 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1677 if (!r.finishing && r != notTop) {
1678 return r;
1679 }
1680 i--;
1681 }
1682 return null;
1683 }
1684
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001685 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1686 int i = mHistory.size()-1;
1687 while (i >= 0) {
1688 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1689 if (!r.finishing && !r.delayedResume && r != notTop) {
1690 return r;
1691 }
1692 i--;
1693 }
1694 return null;
1695 }
1696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 /**
1698 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001699 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 *
1701 * @param token If non-null, any history records matching this token will be skipped.
1702 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1703 *
1704 * @return Returns the HistoryRecord of the next activity on the stack.
1705 */
1706 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1707 int i = mHistory.size()-1;
1708 while (i >= 0) {
1709 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1710 // Note: the taskId check depends on real taskId fields being non-zero
1711 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1712 return r;
1713 }
1714 i--;
1715 }
1716 return null;
1717 }
1718
1719 private final ProcessRecord getProcessRecordLocked(
1720 String processName, int uid) {
1721 if (uid == Process.SYSTEM_UID) {
1722 // The system gets to run in any process. If there are multiple
1723 // processes with the same uid, just pick the first (this
1724 // should never happen).
1725 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1726 processName);
1727 return procs != null ? procs.valueAt(0) : null;
1728 }
1729 ProcessRecord proc = mProcessNames.get(processName, uid);
1730 return proc;
1731 }
1732
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001733 private void ensurePackageDexOpt(String packageName) {
1734 IPackageManager pm = ActivityThread.getPackageManager();
1735 try {
1736 if (pm.performDexOpt(packageName)) {
1737 mDidDexOpt = true;
1738 }
1739 } catch (RemoteException e) {
1740 }
1741 }
1742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 private boolean isNextTransitionForward() {
1744 int transit = mWindowManager.getPendingAppTransition();
1745 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1746 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1747 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1748 }
1749
1750 private final boolean realStartActivityLocked(HistoryRecord r,
1751 ProcessRecord app, boolean andResume, boolean checkConfig)
1752 throws RemoteException {
1753
1754 r.startFreezingScreenLocked(app, 0);
1755 mWindowManager.setAppVisibility(r, true);
1756
1757 // Have the window manager re-evaluate the orientation of
1758 // the screen based on the new activity order. Note that
1759 // as a result of this, it can call back into the activity
1760 // manager with a new orientation. We don't care about that,
1761 // because the activity is not currently running so we are
1762 // just restarting it anyway.
1763 if (checkConfig) {
1764 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001765 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 r.mayFreezeScreenLocked(app) ? r : null);
1767 updateConfigurationLocked(config, r);
1768 }
1769
1770 r.app = app;
1771
1772 if (localLOGV) Log.v(TAG, "Launching: " + r);
1773
1774 int idx = app.activities.indexOf(r);
1775 if (idx < 0) {
1776 app.activities.add(r);
1777 }
1778 updateLRUListLocked(app, true);
1779
1780 try {
1781 if (app.thread == null) {
1782 throw new RemoteException();
1783 }
1784 List<ResultInfo> results = null;
1785 List<Intent> newIntents = null;
1786 if (andResume) {
1787 results = r.results;
1788 newIntents = r.newIntents;
1789 }
1790 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1791 + " icicle=" + r.icicle
1792 + " with results=" + results + " newIntents=" + newIntents
1793 + " andResume=" + andResume);
1794 if (andResume) {
1795 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1796 System.identityHashCode(r),
1797 r.task.taskId, r.shortComponentName);
1798 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001799 if (r.isHomeActivity) {
1800 mHomeProcess = app;
1801 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001802 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001804 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 r.info, r.icicle, results, newIntents, !andResume,
1806 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 } catch (RemoteException e) {
1808 if (r.launchFailed) {
1809 // This is the second time we failed -- finish activity
1810 // and give up.
1811 Log.e(TAG, "Second failure launching "
1812 + r.intent.getComponent().flattenToShortString()
1813 + ", giving up", e);
1814 appDiedLocked(app, app.pid, app.thread);
1815 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1816 "2nd-crash");
1817 return false;
1818 }
1819
1820 // This is the first time we failed -- restart process and
1821 // retry.
1822 app.activities.remove(r);
1823 throw e;
1824 }
1825
1826 r.launchFailed = false;
1827 if (updateLRUListLocked(r)) {
1828 Log.w(TAG, "Activity " + r
1829 + " being launched, but already in LRU list");
1830 }
1831
1832 if (andResume) {
1833 // As part of the process of launching, ActivityThread also performs
1834 // a resume.
1835 r.state = ActivityState.RESUMED;
1836 r.icicle = null;
1837 r.haveState = false;
1838 r.stopped = false;
1839 mResumedActivity = r;
1840 r.task.touchActiveTime();
1841 completeResumeLocked(r);
1842 pauseIfSleepingLocked();
1843 } else {
1844 // This activity is not starting in the resumed state... which
1845 // should look like we asked it to pause+stop (but remain visible),
1846 // and it has done so and reported back the current icicle and
1847 // other state.
1848 r.state = ActivityState.STOPPED;
1849 r.stopped = true;
1850 }
1851
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001852 // Launch the new version setup screen if needed. We do this -after-
1853 // launching the initial activity (that is, home), so that it can have
1854 // a chance to initialize itself while in the background, making the
1855 // switch back to it faster and look better.
1856 startSetupActivityLocked();
1857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858 return true;
1859 }
1860
1861 private final void startSpecificActivityLocked(HistoryRecord r,
1862 boolean andResume, boolean checkConfig) {
1863 // Is this activity's application already running?
1864 ProcessRecord app = getProcessRecordLocked(r.processName,
1865 r.info.applicationInfo.uid);
1866
1867 if (r.startTime == 0) {
1868 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001869 if (mInitialStartTime == 0) {
1870 mInitialStartTime = r.startTime;
1871 }
1872 } else if (mInitialStartTime == 0) {
1873 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 }
1875
1876 if (app != null && app.thread != null) {
1877 try {
1878 realStartActivityLocked(r, app, andResume, checkConfig);
1879 return;
1880 } catch (RemoteException e) {
1881 Log.w(TAG, "Exception when starting activity "
1882 + r.intent.getComponent().flattenToShortString(), e);
1883 }
1884
1885 // If a dead object exception was thrown -- fall through to
1886 // restart the application.
1887 }
1888
1889 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001890 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 }
1892
1893 private final ProcessRecord startProcessLocked(String processName,
1894 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001895 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1897 // We don't have to do anything more if:
1898 // (1) There is an existing application record; and
1899 // (2) The caller doesn't think it is dead, OR there is no thread
1900 // object attached to it so we know it couldn't have crashed; and
1901 // (3) There is a pid assigned to it, so it is either starting or
1902 // already running.
1903 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1904 + " app=" + app + " knownToBeDead=" + knownToBeDead
1905 + " thread=" + (app != null ? app.thread : null)
1906 + " pid=" + (app != null ? app.pid : -1));
1907 if (app != null &&
1908 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1909 return app;
1910 }
1911
1912 String hostingNameStr = hostingName != null
1913 ? hostingName.flattenToShortString() : null;
1914
1915 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1916 // If we are in the background, then check to see if this process
1917 // is bad. If so, we will just silently fail.
1918 if (mBadProcesses.get(info.processName, info.uid) != null) {
1919 return null;
1920 }
1921 } else {
1922 // When the user is explicitly starting a process, then clear its
1923 // crash count so that we won't make it bad until they see at
1924 // least one crash dialog again, and make the process good again
1925 // if it had been bad.
1926 mProcessCrashTimes.remove(info.processName, info.uid);
1927 if (mBadProcesses.get(info.processName, info.uid) != null) {
1928 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1929 info.processName);
1930 mBadProcesses.remove(info.processName, info.uid);
1931 if (app != null) {
1932 app.bad = false;
1933 }
1934 }
1935 }
1936
1937 if (app == null) {
1938 app = newProcessRecordLocked(null, info, processName);
1939 mProcessNames.put(processName, info.uid, app);
1940 } else {
1941 // If this is a new package in the process, add the package to the list
1942 app.addPackage(info.packageName);
1943 }
1944
1945 // If the system is not ready yet, then hold off on starting this
1946 // process until it is.
1947 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001948 && !isAllowedWhileBooting(info)
1949 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 if (!mProcessesOnHold.contains(app)) {
1951 mProcessesOnHold.add(app);
1952 }
1953 return app;
1954 }
1955
1956 startProcessLocked(app, hostingType, hostingNameStr);
1957 return (app.pid != 0) ? app : null;
1958 }
1959
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001960 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1961 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1962 }
1963
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001964 private final void startProcessLocked(ProcessRecord app,
1965 String hostingType, String hostingNameStr) {
1966 if (app.pid > 0 && app.pid != MY_PID) {
1967 synchronized (mPidsSelfLocked) {
1968 mPidsSelfLocked.remove(app.pid);
1969 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1970 }
1971 app.pid = 0;
1972 }
1973
1974 mProcessesOnHold.remove(app);
1975
1976 updateCpuStats();
1977
1978 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1979 mProcDeaths[0] = 0;
1980
1981 try {
1982 int uid = app.info.uid;
1983 int[] gids = null;
1984 try {
1985 gids = mContext.getPackageManager().getPackageGids(
1986 app.info.packageName);
1987 } catch (PackageManager.NameNotFoundException e) {
1988 Log.w(TAG, "Unable to retrieve gids", e);
1989 }
1990 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1991 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1992 && mTopComponent != null
1993 && app.processName.equals(mTopComponent.getPackageName())) {
1994 uid = 0;
1995 }
1996 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1997 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1998 uid = 0;
1999 }
2000 }
2001 int debugFlags = 0;
2002 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
2003 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
2004 }
2005 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
2006 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
2007 }
2008 if ("1".equals(SystemProperties.get("debug.assert"))) {
2009 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2010 }
2011 int pid = Process.start("android.app.ActivityThread",
2012 mSimpleProcessManagement ? app.processName : null, uid, uid,
2013 gids, debugFlags, null);
2014 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2015 synchronized (bs) {
2016 if (bs.isOnBattery()) {
2017 app.batteryStats.incStartsLocked();
2018 }
2019 }
2020
2021 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2022 app.processName, hostingType,
2023 hostingNameStr != null ? hostingNameStr : "");
2024
2025 if (app.persistent) {
2026 Watchdog.getInstance().processStarted(app, app.processName, pid);
2027 }
2028
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002029 StringBuilder buf = mStringBuilder;
2030 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 buf.append("Start proc ");
2032 buf.append(app.processName);
2033 buf.append(" for ");
2034 buf.append(hostingType);
2035 if (hostingNameStr != null) {
2036 buf.append(" ");
2037 buf.append(hostingNameStr);
2038 }
2039 buf.append(": pid=");
2040 buf.append(pid);
2041 buf.append(" uid=");
2042 buf.append(uid);
2043 buf.append(" gids={");
2044 if (gids != null) {
2045 for (int gi=0; gi<gids.length; gi++) {
2046 if (gi != 0) buf.append(", ");
2047 buf.append(gids[gi]);
2048
2049 }
2050 }
2051 buf.append("}");
2052 Log.i(TAG, buf.toString());
2053 if (pid == 0 || pid == MY_PID) {
2054 // Processes are being emulated with threads.
2055 app.pid = MY_PID;
2056 app.removed = false;
2057 mStartingProcesses.add(app);
2058 } else if (pid > 0) {
2059 app.pid = pid;
2060 app.removed = false;
2061 synchronized (mPidsSelfLocked) {
2062 this.mPidsSelfLocked.put(pid, app);
2063 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2064 msg.obj = app;
2065 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2066 }
2067 } else {
2068 app.pid = 0;
2069 RuntimeException e = new RuntimeException(
2070 "Failure starting process " + app.processName
2071 + ": returned pid=" + pid);
2072 Log.e(TAG, e.getMessage(), e);
2073 }
2074 } catch (RuntimeException e) {
2075 // XXX do better error recovery.
2076 app.pid = 0;
2077 Log.e(TAG, "Failure starting process " + app.processName, e);
2078 }
2079 }
2080
2081 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2082 if (mPausingActivity != null) {
2083 RuntimeException e = new RuntimeException();
2084 Log.e(TAG, "Trying to pause when pause is already pending for "
2085 + mPausingActivity, e);
2086 }
2087 HistoryRecord prev = mResumedActivity;
2088 if (prev == null) {
2089 RuntimeException e = new RuntimeException();
2090 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2091 resumeTopActivityLocked(null);
2092 return;
2093 }
2094 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2095 mResumedActivity = null;
2096 mPausingActivity = prev;
2097 mLastPausedActivity = prev;
2098 prev.state = ActivityState.PAUSING;
2099 prev.task.touchActiveTime();
2100
2101 updateCpuStats();
2102
2103 if (prev.app != null && prev.app.thread != null) {
2104 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2105 try {
2106 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2107 System.identityHashCode(prev),
2108 prev.shortComponentName);
2109 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2110 prev.configChangeFlags);
2111 updateUsageStats(prev, false);
2112 } catch (Exception e) {
2113 // Ignore exception, if process died other code will cleanup.
2114 Log.w(TAG, "Exception thrown during pause", e);
2115 mPausingActivity = null;
2116 mLastPausedActivity = null;
2117 }
2118 } else {
2119 mPausingActivity = null;
2120 mLastPausedActivity = null;
2121 }
2122
2123 // If we are not going to sleep, we want to ensure the device is
2124 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002125 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002126 mLaunchingActivity.acquire();
2127 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2128 // To be safe, don't allow the wake lock to be held for too long.
2129 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2130 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2131 }
2132 }
2133
2134
2135 if (mPausingActivity != null) {
2136 // Have the window manager pause its key dispatching until the new
2137 // activity has started. If we're pausing the activity just because
2138 // the screen is being turned off and the UI is sleeping, don't interrupt
2139 // key dispatch; the same activity will pick it up again on wakeup.
2140 if (!uiSleeping) {
2141 prev.pauseKeyDispatchingLocked();
2142 } else {
2143 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2144 }
2145
2146 // Schedule a pause timeout in case the app doesn't respond.
2147 // We don't give it much time because this directly impacts the
2148 // responsiveness seen by the user.
2149 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2150 msg.obj = prev;
2151 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2152 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2153 } else {
2154 // This activity failed to schedule the
2155 // pause, so just treat it as being paused now.
2156 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2157 resumeTopActivityLocked(null);
2158 }
2159 }
2160
2161 private final void completePauseLocked() {
2162 HistoryRecord prev = mPausingActivity;
2163 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2164
2165 if (prev != null) {
2166 if (prev.finishing) {
2167 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2168 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2169 } else if (prev.app != null) {
2170 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2171 if (prev.waitingVisible) {
2172 prev.waitingVisible = false;
2173 mWaitingVisibleActivities.remove(prev);
2174 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2175 TAG, "Complete pause, no longer waiting: " + prev);
2176 }
2177 if (prev.configDestroy) {
2178 // The previous is being paused because the configuration
2179 // is changing, which means it is actually stopping...
2180 // To juggle the fact that we are also starting a new
2181 // instance right now, we need to first completely stop
2182 // the current instance before starting the new one.
2183 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2184 destroyActivityLocked(prev, true);
2185 } else {
2186 mStoppingActivities.add(prev);
2187 if (mStoppingActivities.size() > 3) {
2188 // If we already have a few activities waiting to stop,
2189 // then give up on things going idle and start clearing
2190 // them out.
2191 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2192 Message msg = Message.obtain();
2193 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2194 mHandler.sendMessage(msg);
2195 }
2196 }
2197 } else {
2198 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2199 prev = null;
2200 }
2201 mPausingActivity = null;
2202 }
2203
Dianne Hackborn55280a92009-05-07 15:53:46 -07002204 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002205 resumeTopActivityLocked(prev);
2206 } else {
2207 if (mGoingToSleep.isHeld()) {
2208 mGoingToSleep.release();
2209 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002210 if (mShuttingDown) {
2211 notifyAll();
2212 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 }
2214
2215 if (prev != null) {
2216 prev.resumeKeyDispatchingLocked();
2217 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002218
2219 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2220 long diff = 0;
2221 synchronized (mProcessStatsThread) {
2222 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2223 }
2224 if (diff > 0) {
2225 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2226 synchronized (bsi) {
2227 BatteryStatsImpl.Uid.Proc ps =
2228 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2229 prev.info.packageName);
2230 if (ps != null) {
2231 ps.addForegroundTimeLocked(diff);
2232 }
2233 }
2234 }
2235 }
2236 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002237 }
2238
2239 /**
2240 * Once we know that we have asked an application to put an activity in
2241 * the resumed state (either by launching it or explicitly telling it),
2242 * this function updates the rest of our state to match that fact.
2243 */
2244 private final void completeResumeLocked(HistoryRecord next) {
2245 next.idle = false;
2246 next.results = null;
2247 next.newIntents = null;
2248
2249 // schedule an idle timeout in case the app doesn't do it for us.
2250 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2251 msg.obj = next;
2252 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2253
2254 if (false) {
2255 // The activity was never told to pause, so just keep
2256 // things going as-is. To maintain our own state,
2257 // we need to emulate it coming back and saying it is
2258 // idle.
2259 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2260 msg.obj = next;
2261 mHandler.sendMessage(msg);
2262 }
2263
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002264 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002266 next.thumbnail = null;
2267 setFocusedActivityLocked(next);
2268 next.resumeKeyDispatchingLocked();
2269 ensureActivitiesVisibleLocked(null, 0);
2270 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002271 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002272
2273 // Mark the point when the activity is resuming
2274 // TODO: To be more accurate, the mark should be before the onCreate,
2275 // not after the onResume. But for subsequent starts, onResume is fine.
2276 if (next.app != null) {
2277 synchronized (mProcessStatsThread) {
2278 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2279 }
2280 } else {
2281 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2282 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002283 }
2284
2285 /**
2286 * Make sure that all activities that need to be visible (that is, they
2287 * currently can be seen by the user) actually are.
2288 */
2289 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2290 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2291 if (DEBUG_VISBILITY) Log.v(
2292 TAG, "ensureActivitiesVisible behind " + top
2293 + " configChanges=0x" + Integer.toHexString(configChanges));
2294
2295 // If the top activity is not fullscreen, then we need to
2296 // make sure any activities under it are now visible.
2297 final int count = mHistory.size();
2298 int i = count-1;
2299 while (mHistory.get(i) != top) {
2300 i--;
2301 }
2302 HistoryRecord r;
2303 boolean behindFullscreen = false;
2304 for (; i>=0; i--) {
2305 r = (HistoryRecord)mHistory.get(i);
2306 if (DEBUG_VISBILITY) Log.v(
2307 TAG, "Make visible? " + r + " finishing=" + r.finishing
2308 + " state=" + r.state);
2309 if (r.finishing) {
2310 continue;
2311 }
2312
2313 final boolean doThisProcess = onlyThisProcess == null
2314 || onlyThisProcess.equals(r.processName);
2315
2316 // First: if this is not the current activity being started, make
2317 // sure it matches the current configuration.
2318 if (r != starting && doThisProcess) {
2319 ensureActivityConfigurationLocked(r, 0);
2320 }
2321
2322 if (r.app == null || r.app.thread == null) {
2323 if (onlyThisProcess == null
2324 || onlyThisProcess.equals(r.processName)) {
2325 // This activity needs to be visible, but isn't even
2326 // running... get it started, but don't resume it
2327 // at this point.
2328 if (DEBUG_VISBILITY) Log.v(
2329 TAG, "Start and freeze screen for " + r);
2330 if (r != starting) {
2331 r.startFreezingScreenLocked(r.app, configChanges);
2332 }
2333 if (!r.visible) {
2334 if (DEBUG_VISBILITY) Log.v(
2335 TAG, "Starting and making visible: " + r);
2336 mWindowManager.setAppVisibility(r, true);
2337 }
2338 if (r != starting) {
2339 startSpecificActivityLocked(r, false, false);
2340 }
2341 }
2342
2343 } else if (r.visible) {
2344 // If this activity is already visible, then there is nothing
2345 // else to do here.
2346 if (DEBUG_VISBILITY) Log.v(
2347 TAG, "Skipping: already visible at " + r);
2348 r.stopFreezingScreenLocked(false);
2349
2350 } else if (onlyThisProcess == null) {
2351 // This activity is not currently visible, but is running.
2352 // Tell it to become visible.
2353 r.visible = true;
2354 if (r.state != ActivityState.RESUMED && r != starting) {
2355 // If this activity is paused, tell it
2356 // to now show its window.
2357 if (DEBUG_VISBILITY) Log.v(
2358 TAG, "Making visible and scheduling visibility: " + r);
2359 try {
2360 mWindowManager.setAppVisibility(r, true);
2361 r.app.thread.scheduleWindowVisibility(r, true);
2362 r.stopFreezingScreenLocked(false);
2363 } catch (Exception e) {
2364 // Just skip on any failure; we'll make it
2365 // visible when it next restarts.
2366 Log.w(TAG, "Exception thrown making visibile: "
2367 + r.intent.getComponent(), e);
2368 }
2369 }
2370 }
2371
2372 // Aggregate current change flags.
2373 configChanges |= r.configChangeFlags;
2374
2375 if (r.fullscreen) {
2376 // At this point, nothing else needs to be shown
2377 if (DEBUG_VISBILITY) Log.v(
2378 TAG, "Stopping: fullscreen at " + r);
2379 behindFullscreen = true;
2380 i--;
2381 break;
2382 }
2383 }
2384
2385 // Now for any activities that aren't visible to the user, make
2386 // sure they no longer are keeping the screen frozen.
2387 while (i >= 0) {
2388 r = (HistoryRecord)mHistory.get(i);
2389 if (DEBUG_VISBILITY) Log.v(
2390 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2391 + " state=" + r.state
2392 + " behindFullscreen=" + behindFullscreen);
2393 if (!r.finishing) {
2394 if (behindFullscreen) {
2395 if (r.visible) {
2396 if (DEBUG_VISBILITY) Log.v(
2397 TAG, "Making invisible: " + r);
2398 r.visible = false;
2399 try {
2400 mWindowManager.setAppVisibility(r, false);
2401 if ((r.state == ActivityState.STOPPING
2402 || r.state == ActivityState.STOPPED)
2403 && r.app != null && r.app.thread != null) {
2404 if (DEBUG_VISBILITY) Log.v(
2405 TAG, "Scheduling invisibility: " + r);
2406 r.app.thread.scheduleWindowVisibility(r, false);
2407 }
2408 } catch (Exception e) {
2409 // Just skip on any failure; we'll make it
2410 // visible when it next restarts.
2411 Log.w(TAG, "Exception thrown making hidden: "
2412 + r.intent.getComponent(), e);
2413 }
2414 } else {
2415 if (DEBUG_VISBILITY) Log.v(
2416 TAG, "Already invisible: " + r);
2417 }
2418 } else if (r.fullscreen) {
2419 if (DEBUG_VISBILITY) Log.v(
2420 TAG, "Now behindFullscreen: " + r);
2421 behindFullscreen = true;
2422 }
2423 }
2424 i--;
2425 }
2426 }
2427
2428 /**
2429 * Version of ensureActivitiesVisible that can easily be called anywhere.
2430 */
2431 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2432 int configChanges) {
2433 HistoryRecord r = topRunningActivityLocked(null);
2434 if (r != null) {
2435 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2436 }
2437 }
2438
2439 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2440 if (resumed) {
2441 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2442 } else {
2443 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2444 }
2445 }
2446
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002447 private boolean startHomeActivityLocked() {
2448 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2449 && mTopAction == null) {
2450 // We are running in factory test mode, but unable to find
2451 // the factory test app, so just sit around displaying the
2452 // error message and don't try to start anything.
2453 return false;
2454 }
2455 Intent intent = new Intent(
2456 mTopAction,
2457 mTopData != null ? Uri.parse(mTopData) : null);
2458 intent.setComponent(mTopComponent);
2459 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2460 intent.addCategory(Intent.CATEGORY_HOME);
2461 }
2462 ActivityInfo aInfo =
2463 intent.resolveActivityInfo(mContext.getPackageManager(),
2464 STOCK_PM_FLAGS);
2465 if (aInfo != null) {
2466 intent.setComponent(new ComponentName(
2467 aInfo.applicationInfo.packageName, aInfo.name));
2468 // Don't do this if the home app is currently being
2469 // instrumented.
2470 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2471 aInfo.applicationInfo.uid);
2472 if (app == null || app.instrumentationClass == null) {
2473 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2474 startActivityLocked(null, intent, null, null, 0, aInfo,
2475 null, null, 0, 0, 0, false, false);
2476 }
2477 }
2478
2479
2480 return true;
2481 }
2482
2483 /**
2484 * Starts the "new version setup screen" if appropriate.
2485 */
2486 private void startSetupActivityLocked() {
2487 // Only do this once per boot.
2488 if (mCheckedForSetup) {
2489 return;
2490 }
2491
2492 // We will show this screen if the current one is a different
2493 // version than the last one shown, and we are not running in
2494 // low-level factory test mode.
2495 final ContentResolver resolver = mContext.getContentResolver();
2496 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2497 Settings.Secure.getInt(resolver,
2498 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2499 mCheckedForSetup = true;
2500
2501 // See if we should be showing the platform update setup UI.
2502 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2503 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2504 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2505
2506 // We don't allow third party apps to replace this.
2507 ResolveInfo ri = null;
2508 for (int i=0; ris != null && i<ris.size(); i++) {
2509 if ((ris.get(i).activityInfo.applicationInfo.flags
2510 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2511 ri = ris.get(i);
2512 break;
2513 }
2514 }
2515
2516 if (ri != null) {
2517 String vers = ri.activityInfo.metaData != null
2518 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2519 : null;
2520 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2521 vers = ri.activityInfo.applicationInfo.metaData.getString(
2522 Intent.METADATA_SETUP_VERSION);
2523 }
2524 String lastVers = Settings.Secure.getString(
2525 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2526 if (vers != null && !vers.equals(lastVers)) {
2527 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2528 intent.setComponent(new ComponentName(
2529 ri.activityInfo.packageName, ri.activityInfo.name));
2530 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2531 null, null, 0, 0, 0, false, false);
2532 }
2533 }
2534 }
2535 }
2536
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002537 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002538 //Log.i(TAG, "**** REPORT RESUME: " + r);
2539
2540 final int identHash = System.identityHashCode(r);
2541 updateUsageStats(r, true);
2542
2543 int i = mWatchers.beginBroadcast();
2544 while (i > 0) {
2545 i--;
2546 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2547 if (w != null) {
2548 try {
2549 w.activityResuming(identHash);
2550 } catch (RemoteException e) {
2551 }
2552 }
2553 }
2554 mWatchers.finishBroadcast();
2555 }
2556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002557 /**
2558 * Ensure that the top activity in the stack is resumed.
2559 *
2560 * @param prev The previously resumed activity, for when in the process
2561 * of pausing; can be null to call from elsewhere.
2562 *
2563 * @return Returns true if something is being resumed, or false if
2564 * nothing happened.
2565 */
2566 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2567 // Find the first activity that is not finishing.
2568 HistoryRecord next = topRunningActivityLocked(null);
2569
2570 // Remember how we'll process this pause/resume situation, and ensure
2571 // that the state is reset however we wind up proceeding.
2572 final boolean userLeaving = mUserLeaving;
2573 mUserLeaving = false;
2574
2575 if (next == null) {
2576 // There are no more activities! Let's just start up the
2577 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002578 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 }
2580
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002581 next.delayedResume = false;
2582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002583 // If the top activity is the resumed one, nothing to do.
2584 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2585 // Make sure we have executed any pending transitions, since there
2586 // should be nothing left to do at this point.
2587 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002588 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589 return false;
2590 }
2591
2592 // If we are sleeping, and there is no resumed activity, and the top
2593 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002594 if ((mSleeping || mShuttingDown)
2595 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002596 // Make sure we have executed any pending transitions, since there
2597 // should be nothing left to do at this point.
2598 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002599 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002600 return false;
2601 }
2602
2603 // The activity may be waiting for stop, but that is no longer
2604 // appropriate for it.
2605 mStoppingActivities.remove(next);
2606 mWaitingVisibleActivities.remove(next);
2607
2608 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2609
2610 // If we are currently pausing an activity, then don't do anything
2611 // until that is done.
2612 if (mPausingActivity != null) {
2613 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2614 return false;
2615 }
2616
2617 // We need to start pausing the current activity so the top one
2618 // can be resumed...
2619 if (mResumedActivity != null) {
2620 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2621 startPausingLocked(userLeaving, false);
2622 return true;
2623 }
2624
2625 if (prev != null && prev != next) {
2626 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2627 prev.waitingVisible = true;
2628 mWaitingVisibleActivities.add(prev);
2629 if (DEBUG_SWITCH) Log.v(
2630 TAG, "Resuming top, waiting visible to hide: " + prev);
2631 } else {
2632 // The next activity is already visible, so hide the previous
2633 // activity's windows right now so we can show the new one ASAP.
2634 // We only do this if the previous is finishing, which should mean
2635 // it is on top of the one being resumed so hiding it quickly
2636 // is good. Otherwise, we want to do the normal route of allowing
2637 // the resumed activity to be shown so we can decide if the
2638 // previous should actually be hidden depending on whether the
2639 // new one is found to be full-screen or not.
2640 if (prev.finishing) {
2641 mWindowManager.setAppVisibility(prev, false);
2642 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2643 + prev + ", waitingVisible="
2644 + (prev != null ? prev.waitingVisible : null)
2645 + ", nowVisible=" + next.nowVisible);
2646 } else {
2647 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2648 + prev + ", waitingVisible="
2649 + (prev != null ? prev.waitingVisible : null)
2650 + ", nowVisible=" + next.nowVisible);
2651 }
2652 }
2653 }
2654
2655 // We are starting up the next activity, so tell the window manager
2656 // that the previous one will be hidden soon. This way it can know
2657 // to ignore it when computing the desired screen orientation.
2658 if (prev != null) {
2659 if (prev.finishing) {
2660 if (DEBUG_TRANSITION) Log.v(TAG,
2661 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002662 if (mNoAnimActivities.contains(prev)) {
2663 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2664 } else {
2665 mWindowManager.prepareAppTransition(prev.task == next.task
2666 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2667 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002669 mWindowManager.setAppWillBeHidden(prev);
2670 mWindowManager.setAppVisibility(prev, false);
2671 } else {
2672 if (DEBUG_TRANSITION) Log.v(TAG,
2673 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002674 if (mNoAnimActivities.contains(next)) {
2675 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2676 } else {
2677 mWindowManager.prepareAppTransition(prev.task == next.task
2678 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2679 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002681 }
2682 if (false) {
2683 mWindowManager.setAppWillBeHidden(prev);
2684 mWindowManager.setAppVisibility(prev, false);
2685 }
2686 } else if (mHistory.size() > 1) {
2687 if (DEBUG_TRANSITION) Log.v(TAG,
2688 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002689 if (mNoAnimActivities.contains(next)) {
2690 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2691 } else {
2692 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2693 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694 }
2695
2696 if (next.app != null && next.app.thread != null) {
2697 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2698
2699 // This activity is now becoming visible.
2700 mWindowManager.setAppVisibility(next, true);
2701
2702 HistoryRecord lastResumedActivity = mResumedActivity;
2703 ActivityState lastState = next.state;
2704
2705 updateCpuStats();
2706
2707 next.state = ActivityState.RESUMED;
2708 mResumedActivity = next;
2709 next.task.touchActiveTime();
2710 updateLRUListLocked(next.app, true);
2711 updateLRUListLocked(next);
2712
2713 // Have the window manager re-evaluate the orientation of
2714 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002715 boolean updated;
2716 synchronized (this) {
2717 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2718 mConfiguration,
2719 next.mayFreezeScreenLocked(next.app) ? next : null);
2720 if (config != null) {
2721 /*
2722 * Explicitly restore the locale to the one from the
2723 * old configuration, since the one that comes back from
2724 * the window manager has the default (boot) locale.
2725 *
2726 * It looks like previously the locale picker only worked
2727 * by coincidence: usually it would do its setting of
2728 * the locale after the activity transition, so it didn't
2729 * matter that this lost it. With the synchronized
2730 * block now keeping them from happening at the same time,
2731 * this one always would happen second and undo what the
2732 * locale picker had just done.
2733 */
2734 config.locale = mConfiguration.locale;
2735 next.frozenBeforeDestroy = true;
2736 }
2737 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002738 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002739 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 // The configuration update wasn't able to keep the existing
2741 // instance of the activity, and instead started a new one.
2742 // We should be all done, but let's just make sure our activity
2743 // is still at the top and schedule another run if something
2744 // weird happened.
2745 HistoryRecord nextNext = topRunningActivityLocked(null);
2746 if (DEBUG_SWITCH) Log.i(TAG,
2747 "Activity config changed during resume: " + next
2748 + ", new next: " + nextNext);
2749 if (nextNext != next) {
2750 // Do over!
2751 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2752 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002753 setFocusedActivityLocked(next);
2754 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002755 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002756 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002757 return true;
2758 }
2759
2760 try {
2761 // Deliver all pending results.
2762 ArrayList a = next.results;
2763 if (a != null) {
2764 final int N = a.size();
2765 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002766 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002767 TAG, "Delivering results to " + next
2768 + ": " + a);
2769 next.app.thread.scheduleSendResult(next, a);
2770 }
2771 }
2772
2773 if (next.newIntents != null) {
2774 next.app.thread.scheduleNewIntent(next.newIntents, next);
2775 }
2776
2777 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2778 System.identityHashCode(next),
2779 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002780
2781 next.app.thread.scheduleResumeActivity(next,
2782 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002784 pauseIfSleepingLocked();
2785
2786 } catch (Exception e) {
2787 // Whoops, need to restart this activity!
2788 next.state = lastState;
2789 mResumedActivity = lastResumedActivity;
2790 if (Config.LOGD) Log.d(TAG,
2791 "Restarting because process died: " + next);
2792 if (!next.hasBeenLaunched) {
2793 next.hasBeenLaunched = true;
2794 } else {
2795 if (SHOW_APP_STARTING_ICON) {
2796 mWindowManager.setAppStartingWindow(
2797 next, next.packageName, next.theme,
2798 next.nonLocalizedLabel,
2799 next.labelRes, next.icon, null, true);
2800 }
2801 }
2802 startSpecificActivityLocked(next, true, false);
2803 return true;
2804 }
2805
2806 // From this point on, if something goes wrong there is no way
2807 // to recover the activity.
2808 try {
2809 next.visible = true;
2810 completeResumeLocked(next);
2811 } catch (Exception e) {
2812 // If any exception gets thrown, toss away this
2813 // activity and try the next one.
2814 Log.w(TAG, "Exception thrown during resume of " + next, e);
2815 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2816 "resume-exception");
2817 return true;
2818 }
2819
2820 // Didn't need to use the icicle, and it is now out of date.
2821 next.icicle = null;
2822 next.haveState = false;
2823 next.stopped = false;
2824
2825 } else {
2826 // Whoops, need to restart this activity!
2827 if (!next.hasBeenLaunched) {
2828 next.hasBeenLaunched = true;
2829 } else {
2830 if (SHOW_APP_STARTING_ICON) {
2831 mWindowManager.setAppStartingWindow(
2832 next, next.packageName, next.theme,
2833 next.nonLocalizedLabel,
2834 next.labelRes, next.icon, null, true);
2835 }
2836 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2837 }
2838 startSpecificActivityLocked(next, true, true);
2839 }
2840
2841 return true;
2842 }
2843
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002844 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2845 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002846 final int NH = mHistory.size();
2847
2848 int addPos = -1;
2849
2850 if (!newTask) {
2851 // If starting in an existing task, find where that is...
2852 HistoryRecord next = null;
2853 boolean startIt = true;
2854 for (int i = NH-1; i >= 0; i--) {
2855 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2856 if (p.finishing) {
2857 continue;
2858 }
2859 if (p.task == r.task) {
2860 // Here it is! Now, if this is not yet visible to the
2861 // user, then just add it without starting; it will
2862 // get started when the user navigates back to it.
2863 addPos = i+1;
2864 if (!startIt) {
2865 mHistory.add(addPos, r);
2866 r.inHistory = true;
2867 r.task.numActivities++;
2868 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2869 r.info.screenOrientation, r.fullscreen);
2870 if (VALIDATE_TOKENS) {
2871 mWindowManager.validateAppTokens(mHistory);
2872 }
2873 return;
2874 }
2875 break;
2876 }
2877 if (p.fullscreen) {
2878 startIt = false;
2879 }
2880 next = p;
2881 }
2882 }
2883
2884 // Place a new activity at top of stack, so it is next to interact
2885 // with the user.
2886 if (addPos < 0) {
2887 addPos = mHistory.size();
2888 }
2889
2890 // If we are not placing the new activity frontmost, we do not want
2891 // to deliver the onUserLeaving callback to the actual frontmost
2892 // activity
2893 if (addPos < NH) {
2894 mUserLeaving = false;
2895 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2896 }
2897
2898 // Slot the activity into the history stack and proceed
2899 mHistory.add(addPos, r);
2900 r.inHistory = true;
2901 r.frontOfTask = newTask;
2902 r.task.numActivities++;
2903 if (NH > 0) {
2904 // We want to show the starting preview window if we are
2905 // switching to a new task, or the next activity's process is
2906 // not currently running.
2907 boolean showStartingIcon = newTask;
2908 ProcessRecord proc = r.app;
2909 if (proc == null) {
2910 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2911 }
2912 if (proc == null || proc.thread == null) {
2913 showStartingIcon = true;
2914 }
2915 if (DEBUG_TRANSITION) Log.v(TAG,
2916 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002917 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2918 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2919 mNoAnimActivities.add(r);
2920 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2921 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2922 mNoAnimActivities.remove(r);
2923 } else {
2924 mWindowManager.prepareAppTransition(newTask
2925 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2926 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2927 mNoAnimActivities.remove(r);
2928 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002929 mWindowManager.addAppToken(
2930 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2931 boolean doShow = true;
2932 if (newTask) {
2933 // Even though this activity is starting fresh, we still need
2934 // to reset it to make sure we apply affinities to move any
2935 // existing activities from other tasks in to it.
2936 // If the caller has requested that the target task be
2937 // reset, then do so.
2938 if ((r.intent.getFlags()
2939 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2940 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002941 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002942 }
2943 }
2944 if (SHOW_APP_STARTING_ICON && doShow) {
2945 // Figure out if we are transitioning from another activity that is
2946 // "has the same starting icon" as the next one. This allows the
2947 // window manager to keep the previous window it had previously
2948 // created, if it still had one.
2949 HistoryRecord prev = mResumedActivity;
2950 if (prev != null) {
2951 // We don't want to reuse the previous starting preview if:
2952 // (1) The current activity is in a different task.
2953 if (prev.task != r.task) prev = null;
2954 // (2) The current activity is already displayed.
2955 else if (prev.nowVisible) prev = null;
2956 }
2957 mWindowManager.setAppStartingWindow(
2958 r, r.packageName, r.theme, r.nonLocalizedLabel,
2959 r.labelRes, r.icon, prev, showStartingIcon);
2960 }
2961 } else {
2962 // If this is the first activity, don't do any fancy animations,
2963 // because there is nothing for it to animate on top of.
2964 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2965 r.info.screenOrientation, r.fullscreen);
2966 }
2967 if (VALIDATE_TOKENS) {
2968 mWindowManager.validateAppTokens(mHistory);
2969 }
2970
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002971 if (doResume) {
2972 resumeTopActivityLocked(null);
2973 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002974 }
2975
2976 /**
2977 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002978 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2979 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 * an instance of that activity in the stack and, if found, finish all
2981 * activities on top of it and return the instance.
2982 *
2983 * @param newR Description of the new activity being started.
2984 * @return Returns the old activity that should be continue to be used,
2985 * or null if none was found.
2986 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002987 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002988 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002989 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002990
2991 // First find the requested task.
2992 while (i > 0) {
2993 i--;
2994 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2995 if (r.task.taskId == taskId) {
2996 i++;
2997 break;
2998 }
2999 }
3000
3001 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003002 while (i > 0) {
3003 i--;
3004 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3005 if (r.finishing) {
3006 continue;
3007 }
3008 if (r.task.taskId != taskId) {
3009 return null;
3010 }
3011 if (r.realActivity.equals(newR.realActivity)) {
3012 // Here it is! Now finish everything in front...
3013 HistoryRecord ret = r;
3014 if (doClear) {
3015 while (i < (mHistory.size()-1)) {
3016 i++;
3017 r = (HistoryRecord)mHistory.get(i);
3018 if (r.finishing) {
3019 continue;
3020 }
3021 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
3022 null, "clear")) {
3023 i--;
3024 }
3025 }
3026 }
3027
3028 // Finally, if this is a normal launch mode (that is, not
3029 // expecting onNewIntent()), then we will finish the current
3030 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003031 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3032 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003033 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003034 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003035 if (index >= 0) {
3036 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3037 null, "clear");
3038 }
3039 return null;
3040 }
3041 }
3042
3043 return ret;
3044 }
3045 }
3046
3047 return null;
3048 }
3049
3050 /**
3051 * Find the activity in the history stack within the given task. Returns
3052 * the index within the history at which it's found, or < 0 if not found.
3053 */
3054 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3055 int i = mHistory.size();
3056 while (i > 0) {
3057 i--;
3058 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3059 if (candidate.task.taskId != task) {
3060 break;
3061 }
3062 if (candidate.realActivity.equals(r.realActivity)) {
3063 return i;
3064 }
3065 }
3066
3067 return -1;
3068 }
3069
3070 /**
3071 * Reorder the history stack so that the activity at the given index is
3072 * brought to the front.
3073 */
3074 private final HistoryRecord moveActivityToFrontLocked(int where) {
3075 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3076 int top = mHistory.size();
3077 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3078 mHistory.add(top, newTop);
3079 oldTop.frontOfTask = false;
3080 newTop.frontOfTask = true;
3081 return newTop;
3082 }
3083
3084 /**
3085 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3086 * method will be called at the proper time.
3087 */
3088 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3089 boolean sent = false;
3090 if (r.state == ActivityState.RESUMED
3091 && r.app != null && r.app.thread != null) {
3092 try {
3093 ArrayList<Intent> ar = new ArrayList<Intent>();
3094 ar.add(new Intent(intent));
3095 r.app.thread.scheduleNewIntent(ar, r);
3096 sent = true;
3097 } catch (Exception e) {
3098 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3099 }
3100 }
3101 if (!sent) {
3102 r.addNewIntentLocked(new Intent(intent));
3103 }
3104 }
3105
3106 private final void logStartActivity(int tag, HistoryRecord r,
3107 TaskRecord task) {
3108 EventLog.writeEvent(tag,
3109 System.identityHashCode(r), task.taskId,
3110 r.shortComponentName, r.intent.getAction(),
3111 r.intent.getType(), r.intent.getDataString(),
3112 r.intent.getFlags());
3113 }
3114
3115 private final int startActivityLocked(IApplicationThread caller,
3116 Intent intent, String resolvedType,
3117 Uri[] grantedUriPermissions,
3118 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3119 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003120 int callingPid, int callingUid, boolean onlyIfNeeded,
3121 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003122 Log.i(TAG, "Starting activity: " + intent);
3123
3124 HistoryRecord sourceRecord = null;
3125 HistoryRecord resultRecord = null;
3126 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003127 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003128 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3130 if (index >= 0) {
3131 sourceRecord = (HistoryRecord)mHistory.get(index);
3132 if (requestCode >= 0 && !sourceRecord.finishing) {
3133 resultRecord = sourceRecord;
3134 }
3135 }
3136 }
3137
3138 int launchFlags = intent.getFlags();
3139
3140 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3141 && sourceRecord != null) {
3142 // Transfer the result target from the source activity to the new
3143 // one being started, including any failures.
3144 if (requestCode >= 0) {
3145 return START_FORWARD_AND_REQUEST_CONFLICT;
3146 }
3147 resultRecord = sourceRecord.resultTo;
3148 resultWho = sourceRecord.resultWho;
3149 requestCode = sourceRecord.requestCode;
3150 sourceRecord.resultTo = null;
3151 if (resultRecord != null) {
3152 resultRecord.removeResultsLocked(
3153 sourceRecord, resultWho, requestCode);
3154 }
3155 }
3156
3157 int err = START_SUCCESS;
3158
3159 if (intent.getComponent() == null) {
3160 // We couldn't find a class that can handle the given Intent.
3161 // That's the end of that!
3162 err = START_INTENT_NOT_RESOLVED;
3163 }
3164
3165 if (err == START_SUCCESS && aInfo == null) {
3166 // We couldn't find the specific class specified in the Intent.
3167 // Also the end of the line.
3168 err = START_CLASS_NOT_FOUND;
3169 }
3170
3171 ProcessRecord callerApp = null;
3172 if (err == START_SUCCESS && caller != null) {
3173 callerApp = getRecordForAppLocked(caller);
3174 if (callerApp != null) {
3175 callingPid = callerApp.pid;
3176 callingUid = callerApp.info.uid;
3177 } else {
3178 Log.w(TAG, "Unable to find app for caller " + caller
3179 + " (pid=" + callingPid + ") when starting: "
3180 + intent.toString());
3181 err = START_PERMISSION_DENIED;
3182 }
3183 }
3184
3185 if (err != START_SUCCESS) {
3186 if (resultRecord != null) {
3187 sendActivityResultLocked(-1,
3188 resultRecord, resultWho, requestCode,
3189 Activity.RESULT_CANCELED, null);
3190 }
3191 return err;
3192 }
3193
3194 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3195 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3196 if (perm != PackageManager.PERMISSION_GRANTED) {
3197 if (resultRecord != null) {
3198 sendActivityResultLocked(-1,
3199 resultRecord, resultWho, requestCode,
3200 Activity.RESULT_CANCELED, null);
3201 }
3202 String msg = "Permission Denial: starting " + intent.toString()
3203 + " from " + callerApp + " (pid=" + callingPid
3204 + ", uid=" + callingUid + ")"
3205 + " requires " + aInfo.permission;
3206 Log.w(TAG, msg);
3207 throw new SecurityException(msg);
3208 }
3209
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003210 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211 boolean abort = false;
3212 try {
3213 // The Intent we give to the watcher has the extra data
3214 // stripped off, since it can contain private information.
3215 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003216 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 aInfo.applicationInfo.packageName);
3218 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003219 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 }
3221
3222 if (abort) {
3223 if (resultRecord != null) {
3224 sendActivityResultLocked(-1,
3225 resultRecord, resultWho, requestCode,
3226 Activity.RESULT_CANCELED, null);
3227 }
3228 // We pretend to the caller that it was really started, but
3229 // they will just get a cancel result.
3230 return START_SUCCESS;
3231 }
3232 }
3233
3234 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3235 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003236 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003238 if (mResumedActivity == null
3239 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3240 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3241 PendingActivityLaunch pal = new PendingActivityLaunch();
3242 pal.r = r;
3243 pal.sourceRecord = sourceRecord;
3244 pal.grantedUriPermissions = grantedUriPermissions;
3245 pal.grantedMode = grantedMode;
3246 pal.onlyIfNeeded = onlyIfNeeded;
3247 mPendingActivityLaunches.add(pal);
3248 return START_SWITCHES_CANCELED;
3249 }
3250 }
3251
3252 if (mDidAppSwitch) {
3253 // This is the second allowed switch since we stopped switches,
3254 // so now just generally allow switches. Use case: user presses
3255 // home (switches disabled, switch to home, mDidAppSwitch now true);
3256 // user taps a home icon (coming from home so allowed, we hit here
3257 // and now allow anyone to switch again).
3258 mAppSwitchesAllowedTime = 0;
3259 } else {
3260 mDidAppSwitch = true;
3261 }
3262
3263 doPendingActivityLaunchesLocked(false);
3264
3265 return startActivityUncheckedLocked(r, sourceRecord,
3266 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3267 }
3268
3269 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3270 final int N = mPendingActivityLaunches.size();
3271 if (N <= 0) {
3272 return;
3273 }
3274 for (int i=0; i<N; i++) {
3275 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3276 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3277 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3278 doResume && i == (N-1));
3279 }
3280 mPendingActivityLaunches.clear();
3281 }
3282
3283 private final int startActivityUncheckedLocked(HistoryRecord r,
3284 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3285 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3286 final Intent intent = r.intent;
3287 final int callingUid = r.launchedFromUid;
3288
3289 int launchFlags = intent.getFlags();
3290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003291 // We'll invoke onUserLeaving before onPause only if the launching
3292 // activity did not explicitly state that this is an automated launch.
3293 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3294 if (DEBUG_USER_LEAVING) Log.v(TAG,
3295 "startActivity() => mUserLeaving=" + mUserLeaving);
3296
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003297 // If the caller has asked not to resume at this point, we make note
3298 // of this in the record so that we can skip it when trying to find
3299 // the top running activity.
3300 if (!doResume) {
3301 r.delayedResume = true;
3302 }
3303
3304 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3305 != 0 ? r : null;
3306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 // If the onlyIfNeeded flag is set, then we can do this if the activity
3308 // being launched is the same as the one making the call... or, as
3309 // a special case, if we do not know the caller then we count the
3310 // current top activity as the caller.
3311 if (onlyIfNeeded) {
3312 HistoryRecord checkedCaller = sourceRecord;
3313 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003314 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315 }
3316 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3317 // Caller is not the same as launcher, so always needed.
3318 onlyIfNeeded = false;
3319 }
3320 }
3321
3322 if (grantedUriPermissions != null && callingUid > 0) {
3323 for (int i=0; i<grantedUriPermissions.length; i++) {
3324 grantUriPermissionLocked(callingUid, r.packageName,
3325 grantedUriPermissions[i], grantedMode, r);
3326 }
3327 }
3328
3329 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3330 intent, r);
3331
3332 if (sourceRecord == null) {
3333 // This activity is not being started from another... in this
3334 // case we -always- start a new task.
3335 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3336 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3337 + intent);
3338 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3339 }
3340 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3341 // The original activity who is starting us is running as a single
3342 // instance... this new activity it is starting must go on its
3343 // own task.
3344 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3345 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3346 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3347 // The activity being started is a single instance... it always
3348 // gets launched into its own task.
3349 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3350 }
3351
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003352 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003353 // For whatever reason this activity is being launched into a new
3354 // task... yet the caller has requested a result back. Well, that
3355 // is pretty messed up, so instead immediately send back a cancel
3356 // and let the new task continue launched as normal without a
3357 // dependency on its originator.
3358 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3359 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003360 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 Activity.RESULT_CANCELED, null);
3362 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 }
3364
3365 boolean addingToTask = false;
3366 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3367 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3368 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3369 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3370 // If bring to front is requested, and no result is requested, and
3371 // we can find a task that was started with this same
3372 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003373 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 // See if there is a task to bring to the front. If this is
3375 // a SINGLE_INSTANCE activity, there can be one and only one
3376 // instance of it in the history, and it is always in its own
3377 // unique task, so we do a special search.
3378 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3379 ? findTaskLocked(intent, r.info)
3380 : findActivityLocked(intent, r.info);
3381 if (taskTop != null) {
3382 if (taskTop.task.intent == null) {
3383 // This task was started because of movement of
3384 // the activity based on affinity... now that we
3385 // are actually launching it, we can assign the
3386 // base intent.
3387 taskTop.task.setIntent(intent, r.info);
3388 }
3389 // If the target task is not in the front, then we need
3390 // to bring it to the front... except... well, with
3391 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3392 // to have the same behavior as if a new instance was
3393 // being started, which means not bringing it to the front
3394 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003395 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 if (curTop.task != taskTop.task) {
3397 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3398 boolean callerAtFront = sourceRecord == null
3399 || curTop.task == sourceRecord.task;
3400 if (callerAtFront) {
3401 // We really do want to push this one into the
3402 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003403 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003404 }
3405 }
3406 // If the caller has requested that the target task be
3407 // reset, then do so.
3408 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3409 taskTop = resetTaskIfNeededLocked(taskTop, r);
3410 }
3411 if (onlyIfNeeded) {
3412 // We don't need to start a new activity, and
3413 // the client said not to do anything if that
3414 // is the case, so this is it! And for paranoia, make
3415 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003416 if (doResume) {
3417 resumeTopActivityLocked(null);
3418 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003419 return START_RETURN_INTENT_TO_CALLER;
3420 }
3421 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3422 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3423 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3424 // In this situation we want to remove all activities
3425 // from the task up to the one being started. In most
3426 // cases this means we are resetting the task to its
3427 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003428 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003429 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 if (top != null) {
3431 if (top.frontOfTask) {
3432 // Activity aliases may mean we use different
3433 // intents for the top activity, so make sure
3434 // the task now has the identity of the new
3435 // intent.
3436 top.task.setIntent(r.intent, r.info);
3437 }
3438 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3439 deliverNewIntentLocked(top, r.intent);
3440 } else {
3441 // A special case: we need to
3442 // start the activity because it is not currently
3443 // running, and the caller has asked to clear the
3444 // current task to have this activity at the top.
3445 addingToTask = true;
3446 // Now pretend like this activity is being started
3447 // by the top of its task, so it is put in the
3448 // right place.
3449 sourceRecord = taskTop;
3450 }
3451 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3452 // In this case the top activity on the task is the
3453 // same as the one being launched, so we take that
3454 // as a request to bring the task to the foreground.
3455 // If the top activity in the task is the root
3456 // activity, deliver this new intent to it if it
3457 // desires.
3458 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3459 && taskTop.realActivity.equals(r.realActivity)) {
3460 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3461 if (taskTop.frontOfTask) {
3462 taskTop.task.setIntent(r.intent, r.info);
3463 }
3464 deliverNewIntentLocked(taskTop, r.intent);
3465 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3466 // In this case we are launching the root activity
3467 // of the task, but with a different intent. We
3468 // should start a new instance on top.
3469 addingToTask = true;
3470 sourceRecord = taskTop;
3471 }
3472 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3473 // In this case an activity is being launched in to an
3474 // existing task, without resetting that task. This
3475 // is typically the situation of launching an activity
3476 // from a notification or shortcut. We want to place
3477 // the new activity on top of the current task.
3478 addingToTask = true;
3479 sourceRecord = taskTop;
3480 } else if (!taskTop.task.rootWasReset) {
3481 // In this case we are launching in to an existing task
3482 // that has not yet been started from its front door.
3483 // The current task has been brought to the front.
3484 // Ideally, we'd probably like to place this new task
3485 // at the bottom of its stack, but that's a little hard
3486 // to do with the current organization of the code so
3487 // for now we'll just drop it.
3488 taskTop.task.setIntent(r.intent, r.info);
3489 }
3490 if (!addingToTask) {
3491 // We didn't do anything... but it was needed (a.k.a., client
3492 // don't use that intent!) And for paranoia, make
3493 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003494 if (doResume) {
3495 resumeTopActivityLocked(null);
3496 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003497 return START_TASK_TO_FRONT;
3498 }
3499 }
3500 }
3501 }
3502
3503 //String uri = r.intent.toURI();
3504 //Intent intent2 = new Intent(uri);
3505 //Log.i(TAG, "Given intent: " + r.intent);
3506 //Log.i(TAG, "URI is: " + uri);
3507 //Log.i(TAG, "To intent: " + intent2);
3508
3509 if (r.packageName != null) {
3510 // If the activity being launched is the same as the one currently
3511 // at the top, then we need to check if it should only be launched
3512 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003513 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3514 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003515 if (top.realActivity.equals(r.realActivity)) {
3516 if (top.app != null && top.app.thread != null) {
3517 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3518 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3519 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3520 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3521 // For paranoia, make sure we have correctly
3522 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003523 if (doResume) {
3524 resumeTopActivityLocked(null);
3525 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003526 if (onlyIfNeeded) {
3527 // We don't need to start a new activity, and
3528 // the client said not to do anything if that
3529 // is the case, so this is it!
3530 return START_RETURN_INTENT_TO_CALLER;
3531 }
3532 deliverNewIntentLocked(top, r.intent);
3533 return START_DELIVERED_TO_TOP;
3534 }
3535 }
3536 }
3537 }
3538
3539 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003540 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003541 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003542 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003543 Activity.RESULT_CANCELED, null);
3544 }
3545 return START_CLASS_NOT_FOUND;
3546 }
3547
3548 boolean newTask = false;
3549
3550 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003551 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003552 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3553 // todo: should do better management of integers.
3554 mCurTask++;
3555 if (mCurTask <= 0) {
3556 mCurTask = 1;
3557 }
3558 r.task = new TaskRecord(mCurTask, r.info, intent,
3559 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3560 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3561 + " in new task " + r.task);
3562 newTask = true;
3563 addRecentTask(r.task);
3564
3565 } else if (sourceRecord != null) {
3566 if (!addingToTask &&
3567 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3568 // In this case, we are adding the activity to an existing
3569 // task, but the caller has asked to clear that task if the
3570 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003571 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003572 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 if (top != null) {
3574 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3575 deliverNewIntentLocked(top, r.intent);
3576 // For paranoia, make sure we have correctly
3577 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003578 if (doResume) {
3579 resumeTopActivityLocked(null);
3580 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003581 return START_DELIVERED_TO_TOP;
3582 }
3583 } else if (!addingToTask &&
3584 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3585 // In this case, we are launching an activity in our own task
3586 // that may already be running somewhere in the history, and
3587 // we want to shuffle it to the front of the stack if so.
3588 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3589 if (where >= 0) {
3590 HistoryRecord top = moveActivityToFrontLocked(where);
3591 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3592 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003593 if (doResume) {
3594 resumeTopActivityLocked(null);
3595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003596 return START_DELIVERED_TO_TOP;
3597 }
3598 }
3599 // An existing activity is starting this new activity, so we want
3600 // to keep the new one in the same task as the one that is starting
3601 // it.
3602 r.task = sourceRecord.task;
3603 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3604 + " in existing task " + r.task);
3605
3606 } else {
3607 // This not being started from an existing activity, and not part
3608 // of a new task... just put it in the top task, though these days
3609 // this case should never happen.
3610 final int N = mHistory.size();
3611 HistoryRecord prev =
3612 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3613 r.task = prev != null
3614 ? prev.task
3615 : new TaskRecord(mCurTask, r.info, intent,
3616 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3617 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3618 + " in new guessed " + r.task);
3619 }
3620 if (newTask) {
3621 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3622 }
3623 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003624 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003625 return START_SUCCESS;
3626 }
3627
3628 public final int startActivity(IApplicationThread caller,
3629 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3630 int grantedMode, IBinder resultTo,
3631 String resultWho, int requestCode, boolean onlyIfNeeded,
3632 boolean debug) {
3633 // Refuse possible leaked file descriptors
3634 if (intent != null && intent.hasFileDescriptors()) {
3635 throw new IllegalArgumentException("File descriptors passed in Intent");
3636 }
3637
The Android Open Source Project4df24232009-03-05 14:34:35 -08003638 final boolean componentSpecified = intent.getComponent() != null;
3639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003640 // Don't modify the client's object!
3641 intent = new Intent(intent);
3642
3643 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003644 ActivityInfo aInfo;
3645 try {
3646 ResolveInfo rInfo =
3647 ActivityThread.getPackageManager().resolveIntent(
3648 intent, resolvedType,
3649 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003650 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003651 aInfo = rInfo != null ? rInfo.activityInfo : null;
3652 } catch (RemoteException e) {
3653 aInfo = null;
3654 }
3655
3656 if (aInfo != null) {
3657 // Store the found target back into the intent, because now that
3658 // we have it we never want to do this again. For example, if the
3659 // user navigates back to this point in the history, we should
3660 // always restart the exact same activity.
3661 intent.setComponent(new ComponentName(
3662 aInfo.applicationInfo.packageName, aInfo.name));
3663
3664 // Don't debug things in the system process
3665 if (debug) {
3666 if (!aInfo.processName.equals("system")) {
3667 setDebugApp(aInfo.processName, true, false);
3668 }
3669 }
3670 }
3671
3672 synchronized(this) {
3673 final long origId = Binder.clearCallingIdentity();
3674 int res = startActivityLocked(caller, intent, resolvedType,
3675 grantedUriPermissions, grantedMode, aInfo,
3676 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003677 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003678 Binder.restoreCallingIdentity(origId);
3679 return res;
3680 }
3681 }
3682
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003683 public int startActivityIntentSender(IApplicationThread caller,
3684 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003685 IBinder resultTo, String resultWho, int requestCode,
3686 int flagsMask, int flagsValues) {
3687 // Refuse possible leaked file descriptors
3688 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3689 throw new IllegalArgumentException("File descriptors passed in Intent");
3690 }
3691
3692 IIntentSender sender = intent.getTarget();
3693 if (!(sender instanceof PendingIntentRecord)) {
3694 throw new IllegalArgumentException("Bad PendingIntent object");
3695 }
3696
3697 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003698
3699 synchronized (this) {
3700 // If this is coming from the currently resumed activity, it is
3701 // effectively saying that app switches are allowed at this point.
3702 if (mResumedActivity != null
3703 && mResumedActivity.info.applicationInfo.uid ==
3704 Binder.getCallingUid()) {
3705 mAppSwitchesAllowedTime = 0;
3706 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003707 }
3708
3709 return pir.sendInner(0, fillInIntent, resolvedType,
3710 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3711 }
3712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713 public boolean startNextMatchingActivity(IBinder callingActivity,
3714 Intent intent) {
3715 // Refuse possible leaked file descriptors
3716 if (intent != null && intent.hasFileDescriptors() == true) {
3717 throw new IllegalArgumentException("File descriptors passed in Intent");
3718 }
3719
3720 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003721 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 if (index < 0) {
3723 return false;
3724 }
3725 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3726 if (r.app == null || r.app.thread == null) {
3727 // The caller is not running... d'oh!
3728 return false;
3729 }
3730 intent = new Intent(intent);
3731 // The caller is not allowed to change the data.
3732 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3733 // And we are resetting to find the next component...
3734 intent.setComponent(null);
3735
3736 ActivityInfo aInfo = null;
3737 try {
3738 List<ResolveInfo> resolves =
3739 ActivityThread.getPackageManager().queryIntentActivities(
3740 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003741 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003742
3743 // Look for the original activity in the list...
3744 final int N = resolves != null ? resolves.size() : 0;
3745 for (int i=0; i<N; i++) {
3746 ResolveInfo rInfo = resolves.get(i);
3747 if (rInfo.activityInfo.packageName.equals(r.packageName)
3748 && rInfo.activityInfo.name.equals(r.info.name)) {
3749 // We found the current one... the next matching is
3750 // after it.
3751 i++;
3752 if (i<N) {
3753 aInfo = resolves.get(i).activityInfo;
3754 }
3755 break;
3756 }
3757 }
3758 } catch (RemoteException e) {
3759 }
3760
3761 if (aInfo == null) {
3762 // Nobody who is next!
3763 return false;
3764 }
3765
3766 intent.setComponent(new ComponentName(
3767 aInfo.applicationInfo.packageName, aInfo.name));
3768 intent.setFlags(intent.getFlags()&~(
3769 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3770 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3771 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3772 Intent.FLAG_ACTIVITY_NEW_TASK));
3773
3774 // Okay now we need to start the new activity, replacing the
3775 // currently running activity. This is a little tricky because
3776 // we want to start the new one as if the current one is finished,
3777 // but not finish the current one first so that there is no flicker.
3778 // And thus...
3779 final boolean wasFinishing = r.finishing;
3780 r.finishing = true;
3781
3782 // Propagate reply information over to the new activity.
3783 final HistoryRecord resultTo = r.resultTo;
3784 final String resultWho = r.resultWho;
3785 final int requestCode = r.requestCode;
3786 r.resultTo = null;
3787 if (resultTo != null) {
3788 resultTo.removeResultsLocked(r, resultWho, requestCode);
3789 }
3790
3791 final long origId = Binder.clearCallingIdentity();
3792 // XXX we are not dealing with propagating grantedUriPermissions...
3793 // those are not yet exposed to user code, so there is no need.
3794 int res = startActivityLocked(r.app.thread, intent,
3795 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003796 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003797 Binder.restoreCallingIdentity(origId);
3798
3799 r.finishing = wasFinishing;
3800 if (res != START_SUCCESS) {
3801 return false;
3802 }
3803 return true;
3804 }
3805 }
3806
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003807 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003808 Intent intent, String resolvedType, IBinder resultTo,
3809 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003810
3811 // This is so super not safe, that only the system (or okay root)
3812 // can do it.
3813 final int callingUid = Binder.getCallingUid();
3814 if (callingUid != 0 && callingUid != Process.myUid()) {
3815 throw new SecurityException(
3816 "startActivityInPackage only available to the system");
3817 }
3818
The Android Open Source Project4df24232009-03-05 14:34:35 -08003819 final boolean componentSpecified = intent.getComponent() != null;
3820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003821 // Don't modify the client's object!
3822 intent = new Intent(intent);
3823
3824 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003825 ActivityInfo aInfo;
3826 try {
3827 ResolveInfo rInfo =
3828 ActivityThread.getPackageManager().resolveIntent(
3829 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003830 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003831 aInfo = rInfo != null ? rInfo.activityInfo : null;
3832 } catch (RemoteException e) {
3833 aInfo = null;
3834 }
3835
3836 if (aInfo != null) {
3837 // Store the found target back into the intent, because now that
3838 // we have it we never want to do this again. For example, if the
3839 // user navigates back to this point in the history, we should
3840 // always restart the exact same activity.
3841 intent.setComponent(new ComponentName(
3842 aInfo.applicationInfo.packageName, aInfo.name));
3843 }
3844
3845 synchronized(this) {
3846 return startActivityLocked(null, intent, resolvedType,
3847 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003848 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003849 }
3850 }
3851
3852 private final void addRecentTask(TaskRecord task) {
3853 // Remove any existing entries that are the same kind of task.
3854 int N = mRecentTasks.size();
3855 for (int i=0; i<N; i++) {
3856 TaskRecord tr = mRecentTasks.get(i);
3857 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3858 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3859 mRecentTasks.remove(i);
3860 i--;
3861 N--;
3862 if (task.intent == null) {
3863 // If the new recent task we are adding is not fully
3864 // specified, then replace it with the existing recent task.
3865 task = tr;
3866 }
3867 }
3868 }
3869 if (N >= MAX_RECENT_TASKS) {
3870 mRecentTasks.remove(N-1);
3871 }
3872 mRecentTasks.add(0, task);
3873 }
3874
3875 public void setRequestedOrientation(IBinder token,
3876 int requestedOrientation) {
3877 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003878 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003879 if (index < 0) {
3880 return;
3881 }
3882 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3883 final long origId = Binder.clearCallingIdentity();
3884 mWindowManager.setAppOrientation(r, requestedOrientation);
3885 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003886 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003887 r.mayFreezeScreenLocked(r.app) ? r : null);
3888 if (config != null) {
3889 r.frozenBeforeDestroy = true;
3890 if (!updateConfigurationLocked(config, r)) {
3891 resumeTopActivityLocked(null);
3892 }
3893 }
3894 Binder.restoreCallingIdentity(origId);
3895 }
3896 }
3897
3898 public int getRequestedOrientation(IBinder token) {
3899 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003900 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003901 if (index < 0) {
3902 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3903 }
3904 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3905 return mWindowManager.getAppOrientation(r);
3906 }
3907 }
3908
3909 private final void stopActivityLocked(HistoryRecord r) {
3910 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3911 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3912 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3913 if (!r.finishing) {
3914 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3915 "no-history");
3916 }
3917 } else if (r.app != null && r.app.thread != null) {
3918 if (mFocusedActivity == r) {
3919 setFocusedActivityLocked(topRunningActivityLocked(null));
3920 }
3921 r.resumeKeyDispatchingLocked();
3922 try {
3923 r.stopped = false;
3924 r.state = ActivityState.STOPPING;
3925 if (DEBUG_VISBILITY) Log.v(
3926 TAG, "Stopping visible=" + r.visible + " for " + r);
3927 if (!r.visible) {
3928 mWindowManager.setAppVisibility(r, false);
3929 }
3930 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3931 } catch (Exception e) {
3932 // Maybe just ignore exceptions here... if the process
3933 // has crashed, our death notification will clean things
3934 // up.
3935 Log.w(TAG, "Exception thrown during pause", e);
3936 // Just in case, assume it to be stopped.
3937 r.stopped = true;
3938 r.state = ActivityState.STOPPED;
3939 if (r.configDestroy) {
3940 destroyActivityLocked(r, true);
3941 }
3942 }
3943 }
3944 }
3945
3946 /**
3947 * @return Returns true if the activity is being finished, false if for
3948 * some reason it is being left as-is.
3949 */
3950 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3951 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003952 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003953 TAG, "Finishing activity: token=" + token
3954 + ", result=" + resultCode + ", data=" + resultData);
3955
Dianne Hackborn75b03852009-06-12 15:43:26 -07003956 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003957 if (index < 0) {
3958 return false;
3959 }
3960 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3961
3962 // Is this the last activity left?
3963 boolean lastActivity = true;
3964 for (int i=mHistory.size()-1; i>=0; i--) {
3965 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3966 if (!p.finishing && p != r) {
3967 lastActivity = false;
3968 break;
3969 }
3970 }
3971
3972 // If this is the last activity, but it is the home activity, then
3973 // just don't finish it.
3974 if (lastActivity) {
3975 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3976 return false;
3977 }
3978 }
3979
3980 finishActivityLocked(r, index, resultCode, resultData, reason);
3981 return true;
3982 }
3983
3984 /**
3985 * @return Returns true if this activity has been removed from the history
3986 * list, or false if it is still in the list and will be removed later.
3987 */
3988 private final boolean finishActivityLocked(HistoryRecord r, int index,
3989 int resultCode, Intent resultData, String reason) {
3990 if (r.finishing) {
3991 Log.w(TAG, "Duplicate finish request for " + r);
3992 return false;
3993 }
3994
3995 r.finishing = true;
3996 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3997 System.identityHashCode(r),
3998 r.task.taskId, r.shortComponentName, reason);
3999 r.task.numActivities--;
4000 if (r.frontOfTask && index < (mHistory.size()-1)) {
4001 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
4002 if (next.task == r.task) {
4003 next.frontOfTask = true;
4004 }
4005 }
4006
4007 r.pauseKeyDispatchingLocked();
4008 if (mFocusedActivity == r) {
4009 setFocusedActivityLocked(topRunningActivityLocked(null));
4010 }
4011
4012 // send the result
4013 HistoryRecord resultTo = r.resultTo;
4014 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07004015 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
4016 + " who=" + r.resultWho + " req=" + r.requestCode
4017 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004018 if (r.info.applicationInfo.uid > 0) {
4019 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
4020 r.packageName, resultData, r);
4021 }
4022 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
4023 resultData);
4024 r.resultTo = null;
4025 }
Chris Tate8a7dc172009-03-24 20:11:42 -07004026 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004027
4028 // Make sure this HistoryRecord is not holding on to other resources,
4029 // because clients have remote IPC references to this object so we
4030 // can't assume that will go away and want to avoid circular IPC refs.
4031 r.results = null;
4032 r.pendingResults = null;
4033 r.newIntents = null;
4034 r.icicle = null;
4035
4036 if (mPendingThumbnails.size() > 0) {
4037 // There are clients waiting to receive thumbnails so, in case
4038 // this is an activity that someone is waiting for, add it
4039 // to the pending list so we can correctly update the clients.
4040 mCancelledThumbnails.add(r);
4041 }
4042
4043 if (mResumedActivity == r) {
4044 boolean endTask = index <= 0
4045 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4046 if (DEBUG_TRANSITION) Log.v(TAG,
4047 "Prepare close transition: finishing " + r);
4048 mWindowManager.prepareAppTransition(endTask
4049 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4050 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4051
4052 // Tell window manager to prepare for this one to be removed.
4053 mWindowManager.setAppVisibility(r, false);
4054
4055 if (mPausingActivity == null) {
4056 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4057 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4058 startPausingLocked(false, false);
4059 }
4060
4061 } else if (r.state != ActivityState.PAUSING) {
4062 // If the activity is PAUSING, we will complete the finish once
4063 // it is done pausing; else we can just directly finish it here.
4064 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4065 return finishCurrentActivityLocked(r, index,
4066 FINISH_AFTER_PAUSE) == null;
4067 } else {
4068 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4069 }
4070
4071 return false;
4072 }
4073
4074 private static final int FINISH_IMMEDIATELY = 0;
4075 private static final int FINISH_AFTER_PAUSE = 1;
4076 private static final int FINISH_AFTER_VISIBLE = 2;
4077
4078 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4079 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004080 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004081 if (index < 0) {
4082 return null;
4083 }
4084
4085 return finishCurrentActivityLocked(r, index, mode);
4086 }
4087
4088 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4089 int index, int mode) {
4090 // First things first: if this activity is currently visible,
4091 // and the resumed activity is not yet visible, then hold off on
4092 // finishing until the resumed one becomes visible.
4093 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4094 if (!mStoppingActivities.contains(r)) {
4095 mStoppingActivities.add(r);
4096 if (mStoppingActivities.size() > 3) {
4097 // If we already have a few activities waiting to stop,
4098 // then give up on things going idle and start clearing
4099 // them out.
4100 Message msg = Message.obtain();
4101 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4102 mHandler.sendMessage(msg);
4103 }
4104 }
4105 r.state = ActivityState.STOPPING;
4106 updateOomAdjLocked();
4107 return r;
4108 }
4109
4110 // make sure the record is cleaned out of other places.
4111 mStoppingActivities.remove(r);
4112 mWaitingVisibleActivities.remove(r);
4113 if (mResumedActivity == r) {
4114 mResumedActivity = null;
4115 }
4116 final ActivityState prevState = r.state;
4117 r.state = ActivityState.FINISHING;
4118
4119 if (mode == FINISH_IMMEDIATELY
4120 || prevState == ActivityState.STOPPED
4121 || prevState == ActivityState.INITIALIZING) {
4122 // If this activity is already stopped, we can just finish
4123 // it right now.
4124 return destroyActivityLocked(r, true) ? null : r;
4125 } else {
4126 // Need to go through the full pause cycle to get this
4127 // activity into the stopped state and then finish it.
4128 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4129 mFinishingActivities.add(r);
4130 resumeTopActivityLocked(null);
4131 }
4132 return r;
4133 }
4134
4135 /**
4136 * This is the internal entry point for handling Activity.finish().
4137 *
4138 * @param token The Binder token referencing the Activity we want to finish.
4139 * @param resultCode Result code, if any, from this Activity.
4140 * @param resultData Result data (Intent), if any, from this Activity.
4141 *
4142 * @result Returns true if the activity successfully finished, or false if it is still running.
4143 */
4144 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4145 // Refuse possible leaked file descriptors
4146 if (resultData != null && resultData.hasFileDescriptors() == true) {
4147 throw new IllegalArgumentException("File descriptors passed in Intent");
4148 }
4149
4150 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004151 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004152 // Find the first activity that is not finishing.
4153 HistoryRecord next = topRunningActivityLocked(token, 0);
4154 if (next != null) {
4155 // ask watcher if this is allowed
4156 boolean resumeOK = true;
4157 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004158 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004159 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004160 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004161 }
4162
4163 if (!resumeOK) {
4164 return false;
4165 }
4166 }
4167 }
4168 final long origId = Binder.clearCallingIdentity();
4169 boolean res = requestFinishActivityLocked(token, resultCode,
4170 resultData, "app-request");
4171 Binder.restoreCallingIdentity(origId);
4172 return res;
4173 }
4174 }
4175
4176 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4177 String resultWho, int requestCode, int resultCode, Intent data) {
4178
4179 if (callingUid > 0) {
4180 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4181 data, r);
4182 }
4183
The Android Open Source Project10592532009-03-18 17:39:46 -07004184 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4185 + " : who=" + resultWho + " req=" + requestCode
4186 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004187 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4188 try {
4189 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4190 list.add(new ResultInfo(resultWho, requestCode,
4191 resultCode, data));
4192 r.app.thread.scheduleSendResult(r, list);
4193 return;
4194 } catch (Exception e) {
4195 Log.w(TAG, "Exception thrown sending result to " + r, e);
4196 }
4197 }
4198
4199 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4200 }
4201
4202 public final void finishSubActivity(IBinder token, String resultWho,
4203 int requestCode) {
4204 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004205 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004206 if (index < 0) {
4207 return;
4208 }
4209 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4210
4211 final long origId = Binder.clearCallingIdentity();
4212
4213 int i;
4214 for (i=mHistory.size()-1; i>=0; i--) {
4215 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4216 if (r.resultTo == self && r.requestCode == requestCode) {
4217 if ((r.resultWho == null && resultWho == null) ||
4218 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4219 finishActivityLocked(r, i,
4220 Activity.RESULT_CANCELED, null, "request-sub");
4221 }
4222 }
4223 }
4224
4225 Binder.restoreCallingIdentity(origId);
4226 }
4227 }
4228
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004229 public void overridePendingTransition(IBinder token, String packageName,
4230 int enterAnim, int exitAnim) {
4231 synchronized(this) {
4232 int index = indexOfTokenLocked(token);
4233 if (index < 0) {
4234 return;
4235 }
4236 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4237
4238 final long origId = Binder.clearCallingIdentity();
4239
4240 if (self.state == ActivityState.RESUMED
4241 || self.state == ActivityState.PAUSING) {
4242 mWindowManager.overridePendingAppTransition(packageName,
4243 enterAnim, exitAnim);
4244 }
4245
4246 Binder.restoreCallingIdentity(origId);
4247 }
4248 }
4249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004250 /**
4251 * Perform clean-up of service connections in an activity record.
4252 */
4253 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4254 // Throw away any services that have been bound by this activity.
4255 if (r.connections != null) {
4256 Iterator<ConnectionRecord> it = r.connections.iterator();
4257 while (it.hasNext()) {
4258 ConnectionRecord c = it.next();
4259 removeConnectionLocked(c, null, r);
4260 }
4261 r.connections = null;
4262 }
4263 }
4264
4265 /**
4266 * Perform the common clean-up of an activity record. This is called both
4267 * as part of destroyActivityLocked() (when destroying the client-side
4268 * representation) and cleaning things up as a result of its hosting
4269 * processing going away, in which case there is no remaining client-side
4270 * state to destroy so only the cleanup here is needed.
4271 */
4272 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4273 if (mResumedActivity == r) {
4274 mResumedActivity = null;
4275 }
4276 if (mFocusedActivity == r) {
4277 mFocusedActivity = null;
4278 }
4279
4280 r.configDestroy = false;
4281 r.frozenBeforeDestroy = false;
4282
4283 // Make sure this record is no longer in the pending finishes list.
4284 // This could happen, for example, if we are trimming activities
4285 // down to the max limit while they are still waiting to finish.
4286 mFinishingActivities.remove(r);
4287 mWaitingVisibleActivities.remove(r);
4288
4289 // Remove any pending results.
4290 if (r.finishing && r.pendingResults != null) {
4291 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4292 PendingIntentRecord rec = apr.get();
4293 if (rec != null) {
4294 cancelIntentSenderLocked(rec, false);
4295 }
4296 }
4297 r.pendingResults = null;
4298 }
4299
4300 if (cleanServices) {
4301 cleanUpActivityServicesLocked(r);
4302 }
4303
4304 if (mPendingThumbnails.size() > 0) {
4305 // There are clients waiting to receive thumbnails so, in case
4306 // this is an activity that someone is waiting for, add it
4307 // to the pending list so we can correctly update the clients.
4308 mCancelledThumbnails.add(r);
4309 }
4310
4311 // Get rid of any pending idle timeouts.
4312 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4313 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4314 }
4315
4316 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4317 if (r.state != ActivityState.DESTROYED) {
4318 mHistory.remove(r);
4319 r.inHistory = false;
4320 r.state = ActivityState.DESTROYED;
4321 mWindowManager.removeAppToken(r);
4322 if (VALIDATE_TOKENS) {
4323 mWindowManager.validateAppTokens(mHistory);
4324 }
4325 cleanUpActivityServicesLocked(r);
4326 removeActivityUriPermissionsLocked(r);
4327 }
4328 }
4329
4330 /**
4331 * Destroy the current CLIENT SIDE instance of an activity. This may be
4332 * called both when actually finishing an activity, or when performing
4333 * a configuration switch where we destroy the current client-side object
4334 * but then create a new client-side object for this same HistoryRecord.
4335 */
4336 private final boolean destroyActivityLocked(HistoryRecord r,
4337 boolean removeFromApp) {
4338 if (DEBUG_SWITCH) Log.v(
4339 TAG, "Removing activity: token=" + r
4340 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4341 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4342 System.identityHashCode(r),
4343 r.task.taskId, r.shortComponentName);
4344
4345 boolean removedFromHistory = false;
4346
4347 cleanUpActivityLocked(r, false);
4348
4349 if (r.app != null) {
4350 if (removeFromApp) {
4351 int idx = r.app.activities.indexOf(r);
4352 if (idx >= 0) {
4353 r.app.activities.remove(idx);
4354 }
4355 if (r.persistent) {
4356 decPersistentCountLocked(r.app);
4357 }
4358 }
4359
4360 boolean skipDestroy = false;
4361
4362 try {
4363 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4364 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4365 r.configChangeFlags);
4366 } catch (Exception e) {
4367 // We can just ignore exceptions here... if the process
4368 // has crashed, our death notification will clean things
4369 // up.
4370 //Log.w(TAG, "Exception thrown during finish", e);
4371 if (r.finishing) {
4372 removeActivityFromHistoryLocked(r);
4373 removedFromHistory = true;
4374 skipDestroy = true;
4375 }
4376 }
4377
4378 r.app = null;
4379 r.nowVisible = false;
4380
4381 if (r.finishing && !skipDestroy) {
4382 r.state = ActivityState.DESTROYING;
4383 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4384 msg.obj = r;
4385 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4386 } else {
4387 r.state = ActivityState.DESTROYED;
4388 }
4389 } else {
4390 // remove this record from the history.
4391 if (r.finishing) {
4392 removeActivityFromHistoryLocked(r);
4393 removedFromHistory = true;
4394 } else {
4395 r.state = ActivityState.DESTROYED;
4396 }
4397 }
4398
4399 r.configChangeFlags = 0;
4400
4401 if (!mLRUActivities.remove(r)) {
4402 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4403 }
4404
4405 return removedFromHistory;
4406 }
4407
4408 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4409 ProcessRecord app)
4410 {
4411 int i = list.size();
4412 if (localLOGV) Log.v(
4413 TAG, "Removing app " + app + " from list " + list
4414 + " with " + i + " entries");
4415 while (i > 0) {
4416 i--;
4417 HistoryRecord r = (HistoryRecord)list.get(i);
4418 if (localLOGV) Log.v(
4419 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4420 if (r.app == app) {
4421 if (localLOGV) Log.v(TAG, "Removing this entry!");
4422 list.remove(i);
4423 }
4424 }
4425 }
4426
4427 /**
4428 * Main function for removing an existing process from the activity manager
4429 * as a result of that process going away. Clears out all connections
4430 * to the process.
4431 */
4432 private final void handleAppDiedLocked(ProcessRecord app,
4433 boolean restarting) {
4434 cleanUpApplicationRecordLocked(app, restarting, -1);
4435 if (!restarting) {
4436 mLRUProcesses.remove(app);
4437 }
4438
4439 // Just in case...
4440 if (mPausingActivity != null && mPausingActivity.app == app) {
4441 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4442 mPausingActivity = null;
4443 }
4444 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4445 mLastPausedActivity = null;
4446 }
4447
4448 // Remove this application's activities from active lists.
4449 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4450 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4451 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4452 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4453
4454 boolean atTop = true;
4455 boolean hasVisibleActivities = false;
4456
4457 // Clean out the history list.
4458 int i = mHistory.size();
4459 if (localLOGV) Log.v(
4460 TAG, "Removing app " + app + " from history with " + i + " entries");
4461 while (i > 0) {
4462 i--;
4463 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4464 if (localLOGV) Log.v(
4465 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4466 if (r.app == app) {
4467 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4468 if (localLOGV) Log.v(
4469 TAG, "Removing this entry! frozen=" + r.haveState
4470 + " finishing=" + r.finishing);
4471 mHistory.remove(i);
4472
4473 r.inHistory = false;
4474 mWindowManager.removeAppToken(r);
4475 if (VALIDATE_TOKENS) {
4476 mWindowManager.validateAppTokens(mHistory);
4477 }
4478 removeActivityUriPermissionsLocked(r);
4479
4480 } else {
4481 // We have the current state for this activity, so
4482 // it can be restarted later when needed.
4483 if (localLOGV) Log.v(
4484 TAG, "Keeping entry, setting app to null");
4485 if (r.visible) {
4486 hasVisibleActivities = true;
4487 }
4488 r.app = null;
4489 r.nowVisible = false;
4490 if (!r.haveState) {
4491 r.icicle = null;
4492 }
4493 }
4494
4495 cleanUpActivityLocked(r, true);
4496 r.state = ActivityState.STOPPED;
4497 }
4498 atTop = false;
4499 }
4500
4501 app.activities.clear();
4502
4503 if (app.instrumentationClass != null) {
4504 Log.w(TAG, "Crash of app " + app.processName
4505 + " running instrumentation " + app.instrumentationClass);
4506 Bundle info = new Bundle();
4507 info.putString("shortMsg", "Process crashed.");
4508 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4509 }
4510
4511 if (!restarting) {
4512 if (!resumeTopActivityLocked(null)) {
4513 // If there was nothing to resume, and we are not already
4514 // restarting this process, but there is a visible activity that
4515 // is hosted by the process... then make sure all visible
4516 // activities are running, taking care of restarting this
4517 // process.
4518 if (hasVisibleActivities) {
4519 ensureActivitiesVisibleLocked(null, 0);
4520 }
4521 }
4522 }
4523 }
4524
4525 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4526 IBinder threadBinder = thread.asBinder();
4527
4528 // Find the application record.
4529 int count = mLRUProcesses.size();
4530 int i;
4531 for (i=0; i<count; i++) {
4532 ProcessRecord rec = mLRUProcesses.get(i);
4533 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4534 return i;
4535 }
4536 }
4537 return -1;
4538 }
4539
4540 private final ProcessRecord getRecordForAppLocked(
4541 IApplicationThread thread) {
4542 if (thread == null) {
4543 return null;
4544 }
4545
4546 int appIndex = getLRURecordIndexForAppLocked(thread);
4547 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4548 }
4549
4550 private final void appDiedLocked(ProcessRecord app, int pid,
4551 IApplicationThread thread) {
4552
4553 mProcDeaths[0]++;
4554
4555 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4556 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4557 + ") has died.");
4558 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4559 if (localLOGV) Log.v(
4560 TAG, "Dying app: " + app + ", pid: " + pid
4561 + ", thread: " + thread.asBinder());
4562 boolean doLowMem = app.instrumentationClass == null;
4563 handleAppDiedLocked(app, false);
4564
4565 if (doLowMem) {
4566 // If there are no longer any background processes running,
4567 // and the app that died was not running instrumentation,
4568 // then tell everyone we are now low on memory.
4569 boolean haveBg = false;
4570 int count = mLRUProcesses.size();
4571 int i;
4572 for (i=0; i<count; i++) {
4573 ProcessRecord rec = mLRUProcesses.get(i);
4574 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4575 haveBg = true;
4576 break;
4577 }
4578 }
4579
4580 if (!haveBg) {
4581 Log.i(TAG, "Low Memory: No more background processes.");
4582 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004583 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004584 for (i=0; i<count; i++) {
4585 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004586 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004587 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4588 // The low memory report is overriding any current
4589 // state for a GC request. Make sure to do
4590 // visible/foreground processes first.
4591 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4592 rec.lastRequestedGc = 0;
4593 } else {
4594 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004595 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004596 rec.reportLowMemory = true;
4597 rec.lastLowMemory = now;
4598 mProcessesToGc.remove(rec);
4599 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004600 }
4601 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004602 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004603 }
4604 }
4605 } else if (Config.LOGD) {
4606 Log.d(TAG, "Received spurious death notification for thread "
4607 + thread.asBinder());
4608 }
4609 }
4610
4611 final String readFile(String filename) {
4612 try {
4613 FileInputStream fs = new FileInputStream(filename);
4614 byte[] inp = new byte[8192];
4615 int size = fs.read(inp);
4616 fs.close();
4617 return new String(inp, 0, 0, size);
4618 } catch (java.io.IOException e) {
4619 }
4620 return "";
4621 }
4622
4623 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004624 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004625 if (app.notResponding || app.crashing) {
4626 return;
4627 }
4628
4629 // Log the ANR to the event log.
4630 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4631
4632 // If we are on a secure build and the application is not interesting to the user (it is
4633 // not visible or in the background), just kill it instead of displaying a dialog.
4634 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4635 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4636 Process.killProcess(app.pid);
4637 return;
4638 }
4639
4640 // DeviceMonitor.start();
4641
4642 String processInfo = null;
4643 if (MONITOR_CPU_USAGE) {
4644 updateCpuStatsNow();
4645 synchronized (mProcessStatsThread) {
4646 processInfo = mProcessStats.printCurrentState();
4647 }
4648 }
4649
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004650 StringBuilder info = mStringBuilder;
4651 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004652 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004653 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004654 if (reportedActivity != null && reportedActivity.app != null) {
4655 info.append(" (last in ");
4656 info.append(reportedActivity.app.processName);
4657 info.append(")");
4658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004659 if (annotation != null) {
4660 info.append("\nAnnotation: ");
4661 info.append(annotation);
4662 }
4663 if (MONITOR_CPU_USAGE) {
4664 info.append("\nCPU usage:\n");
4665 info.append(processInfo);
4666 }
4667 Log.i(TAG, info.toString());
4668
4669 // The application is not responding. Dump as many thread traces as we can.
4670 boolean fileDump = prepareTraceFile(true);
4671 if (!fileDump) {
4672 // Dumping traces to the log, just dump the process that isn't responding so
4673 // we don't overflow the log
4674 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4675 } else {
4676 // Dumping traces to a file so dump all active processes we know about
4677 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004678 // First, these are the most important processes.
4679 final int[] imppids = new int[3];
4680 int i=0;
4681 imppids[0] = app.pid;
4682 i++;
4683 if (reportedActivity != null && reportedActivity.app != null
4684 && reportedActivity.app.thread != null
4685 && reportedActivity.app.pid != app.pid) {
4686 imppids[i] = reportedActivity.app.pid;
4687 i++;
4688 }
4689 imppids[i] = Process.myPid();
4690 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4691 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4692 synchronized (this) {
4693 try {
4694 wait(200);
4695 } catch (InterruptedException e) {
4696 }
4697 }
4698 }
4699 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004700 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004701 boolean done = false;
4702 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4703 if (imppids[j] == r.pid) {
4704 done = true;
4705 break;
4706 }
4707 }
4708 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004709 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004710 synchronized (this) {
4711 try {
4712 wait(200);
4713 } catch (InterruptedException e) {
4714 }
4715 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004716 }
4717 }
4718 }
4719 }
4720
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004721 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004722 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004723 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004724 app.pid, info.toString());
4725 if (res != 0) {
4726 if (res < 0) {
4727 // wait until the SIGQUIT has had a chance to process before killing the
4728 // process.
4729 try {
4730 wait(2000);
4731 } catch (InterruptedException e) {
4732 }
4733
4734 Process.killProcess(app.pid);
4735 return;
4736 }
4737 }
4738 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004739 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004740 }
4741 }
4742
4743 makeAppNotRespondingLocked(app,
4744 activity != null ? activity.shortComponentName : null,
4745 annotation != null ? "ANR " + annotation : "ANR",
4746 info.toString(), null);
4747 Message msg = Message.obtain();
4748 HashMap map = new HashMap();
4749 msg.what = SHOW_NOT_RESPONDING_MSG;
4750 msg.obj = map;
4751 map.put("app", app);
4752 if (activity != null) {
4753 map.put("activity", activity);
4754 }
4755
4756 mHandler.sendMessage(msg);
4757 return;
4758 }
4759
4760 /**
4761 * If a stack trace file has been configured, prepare the filesystem
4762 * by creating the directory if it doesn't exist and optionally
4763 * removing the old trace file.
4764 *
4765 * @param removeExisting If set, the existing trace file will be removed.
4766 * @return Returns true if the trace file preparations succeeded
4767 */
4768 public static boolean prepareTraceFile(boolean removeExisting) {
4769 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4770 boolean fileReady = false;
4771 if (!TextUtils.isEmpty(tracesPath)) {
4772 File f = new File(tracesPath);
4773 if (!f.exists()) {
4774 // Ensure the enclosing directory exists
4775 File dir = f.getParentFile();
4776 if (!dir.exists()) {
4777 fileReady = dir.mkdirs();
4778 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004779 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004780 } else if (dir.isDirectory()) {
4781 fileReady = true;
4782 }
4783 } else if (removeExisting) {
4784 // Remove the previous traces file, so we don't fill the disk.
4785 // The VM will recreate it
4786 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4787 fileReady = f.delete();
4788 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004789
4790 if (removeExisting) {
4791 try {
4792 f.createNewFile();
4793 FileUtils.setPermissions(f.getAbsolutePath(),
4794 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4795 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4796 fileReady = true;
4797 } catch (IOException e) {
4798 Log.w(TAG, "Unable to make ANR traces file", e);
4799 }
4800 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004801 }
4802
4803 return fileReady;
4804 }
4805
4806
4807 private final void decPersistentCountLocked(ProcessRecord app)
4808 {
4809 app.persistentActivities--;
4810 if (app.persistentActivities > 0) {
4811 // Still more of 'em...
4812 return;
4813 }
4814 if (app.persistent) {
4815 // Ah, but the application itself is persistent. Whatever!
4816 return;
4817 }
4818
4819 // App is no longer persistent... make sure it and the ones
4820 // following it in the LRU list have the correc oom_adj.
4821 updateOomAdjLocked();
4822 }
4823
4824 public void setPersistent(IBinder token, boolean isPersistent) {
4825 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4826 != PackageManager.PERMISSION_GRANTED) {
4827 String msg = "Permission Denial: setPersistent() from pid="
4828 + Binder.getCallingPid()
4829 + ", uid=" + Binder.getCallingUid()
4830 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4831 Log.w(TAG, msg);
4832 throw new SecurityException(msg);
4833 }
4834
4835 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004836 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004837 if (index < 0) {
4838 return;
4839 }
4840 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4841 ProcessRecord app = r.app;
4842
4843 if (localLOGV) Log.v(
4844 TAG, "Setting persistence " + isPersistent + ": " + r);
4845
4846 if (isPersistent) {
4847 if (r.persistent) {
4848 // Okay okay, I heard you already!
4849 if (localLOGV) Log.v(TAG, "Already persistent!");
4850 return;
4851 }
4852 r.persistent = true;
4853 app.persistentActivities++;
4854 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4855 if (app.persistentActivities > 1) {
4856 // We aren't the first...
4857 if (localLOGV) Log.v(TAG, "Not the first!");
4858 return;
4859 }
4860 if (app.persistent) {
4861 // This would be redundant.
4862 if (localLOGV) Log.v(TAG, "App is persistent!");
4863 return;
4864 }
4865
4866 // App is now persistent... make sure it and the ones
4867 // following it now have the correct oom_adj.
4868 final long origId = Binder.clearCallingIdentity();
4869 updateOomAdjLocked();
4870 Binder.restoreCallingIdentity(origId);
4871
4872 } else {
4873 if (!r.persistent) {
4874 // Okay okay, I heard you already!
4875 return;
4876 }
4877 r.persistent = false;
4878 final long origId = Binder.clearCallingIdentity();
4879 decPersistentCountLocked(app);
4880 Binder.restoreCallingIdentity(origId);
4881
4882 }
4883 }
4884 }
4885
4886 public boolean clearApplicationUserData(final String packageName,
4887 final IPackageDataObserver observer) {
4888 int uid = Binder.getCallingUid();
4889 int pid = Binder.getCallingPid();
4890 long callingId = Binder.clearCallingIdentity();
4891 try {
4892 IPackageManager pm = ActivityThread.getPackageManager();
4893 int pkgUid = -1;
4894 synchronized(this) {
4895 try {
4896 pkgUid = pm.getPackageUid(packageName);
4897 } catch (RemoteException e) {
4898 }
4899 if (pkgUid == -1) {
4900 Log.w(TAG, "Invalid packageName:" + packageName);
4901 return false;
4902 }
4903 if (uid == pkgUid || checkComponentPermission(
4904 android.Manifest.permission.CLEAR_APP_USER_DATA,
4905 pid, uid, -1)
4906 == PackageManager.PERMISSION_GRANTED) {
4907 restartPackageLocked(packageName, pkgUid);
4908 } else {
4909 throw new SecurityException(pid+" does not have permission:"+
4910 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4911 "for process:"+packageName);
4912 }
4913 }
4914
4915 try {
4916 //clear application user data
4917 pm.clearApplicationUserData(packageName, observer);
4918 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4919 Uri.fromParts("package", packageName, null));
4920 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4921 broadcastIntentLocked(null, null, intent,
4922 null, null, 0, null, null, null,
4923 false, false, MY_PID, Process.SYSTEM_UID);
4924 } catch (RemoteException e) {
4925 }
4926 } finally {
4927 Binder.restoreCallingIdentity(callingId);
4928 }
4929 return true;
4930 }
4931
4932 public void restartPackage(final String packageName) {
4933 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4934 != PackageManager.PERMISSION_GRANTED) {
4935 String msg = "Permission Denial: restartPackage() from pid="
4936 + Binder.getCallingPid()
4937 + ", uid=" + Binder.getCallingUid()
4938 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4939 Log.w(TAG, msg);
4940 throw new SecurityException(msg);
4941 }
4942
4943 long callingId = Binder.clearCallingIdentity();
4944 try {
4945 IPackageManager pm = ActivityThread.getPackageManager();
4946 int pkgUid = -1;
4947 synchronized(this) {
4948 try {
4949 pkgUid = pm.getPackageUid(packageName);
4950 } catch (RemoteException e) {
4951 }
4952 if (pkgUid == -1) {
4953 Log.w(TAG, "Invalid packageName: " + packageName);
4954 return;
4955 }
4956 restartPackageLocked(packageName, pkgUid);
4957 }
4958 } finally {
4959 Binder.restoreCallingIdentity(callingId);
4960 }
4961 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004962
4963 /*
4964 * The pkg name and uid have to be specified.
4965 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4966 */
4967 public void killApplicationWithUid(String pkg, int uid) {
4968 if (pkg == null) {
4969 return;
4970 }
4971 // Make sure the uid is valid.
4972 if (uid < 0) {
4973 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4974 return;
4975 }
4976 int callerUid = Binder.getCallingUid();
4977 // Only the system server can kill an application
4978 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004979 // Post an aysnc message to kill the application
4980 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4981 msg.arg1 = uid;
4982 msg.arg2 = 0;
4983 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004984 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004985 } else {
4986 throw new SecurityException(callerUid + " cannot kill pkg: " +
4987 pkg);
4988 }
4989 }
4990
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004991 public void closeSystemDialogs(String reason) {
4992 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4993 if (reason != null) {
4994 intent.putExtra("reason", reason);
4995 }
4996
4997 final int uid = Binder.getCallingUid();
4998 final long origId = Binder.clearCallingIdentity();
4999 synchronized (this) {
5000 int i = mWatchers.beginBroadcast();
5001 while (i > 0) {
5002 i--;
5003 IActivityWatcher w = mWatchers.getBroadcastItem(i);
5004 if (w != null) {
5005 try {
5006 w.closingSystemDialogs(reason);
5007 } catch (RemoteException e) {
5008 }
5009 }
5010 }
5011 mWatchers.finishBroadcast();
5012
Dianne Hackbornffa42482009-09-23 22:20:11 -07005013 mWindowManager.closeSystemDialogs(reason);
5014
5015 for (i=mHistory.size()-1; i>=0; i--) {
5016 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5017 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
5018 finishActivityLocked(r, i,
5019 Activity.RESULT_CANCELED, null, "close-sys");
5020 }
5021 }
5022
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005023 broadcastIntentLocked(null, null, intent, null,
5024 null, 0, null, null, null, false, false, -1, uid);
5025 }
5026 Binder.restoreCallingIdentity(origId);
5027 }
5028
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005029 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005030 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005031 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5032 for (int i=pids.length-1; i>=0; i--) {
5033 infos[i] = new Debug.MemoryInfo();
5034 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005035 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005036 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005037 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005038
5039 public void killApplicationProcess(String processName, int uid) {
5040 if (processName == null) {
5041 return;
5042 }
5043
5044 int callerUid = Binder.getCallingUid();
5045 // Only the system server can kill an application
5046 if (callerUid == Process.SYSTEM_UID) {
5047 synchronized (this) {
5048 ProcessRecord app = getProcessRecordLocked(processName, uid);
5049 if (app != null) {
5050 try {
5051 app.thread.scheduleSuicide();
5052 } catch (RemoteException e) {
5053 // If the other end already died, then our work here is done.
5054 }
5055 } else {
5056 Log.w(TAG, "Process/uid not found attempting kill of "
5057 + processName + " / " + uid);
5058 }
5059 }
5060 } else {
5061 throw new SecurityException(callerUid + " cannot kill app process: " +
5062 processName);
5063 }
5064 }
5065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005066 private void restartPackageLocked(final String packageName, int uid) {
5067 uninstallPackageLocked(packageName, uid, false);
5068 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5069 Uri.fromParts("package", packageName, null));
5070 intent.putExtra(Intent.EXTRA_UID, uid);
5071 broadcastIntentLocked(null, null, intent,
5072 null, null, 0, null, null, null,
5073 false, false, MY_PID, Process.SYSTEM_UID);
5074 }
5075
5076 private final void uninstallPackageLocked(String name, int uid,
5077 boolean callerWillRestart) {
5078 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5079
5080 int i, N;
5081
5082 final String procNamePrefix = name + ":";
5083 if (uid < 0) {
5084 try {
5085 uid = ActivityThread.getPackageManager().getPackageUid(name);
5086 } catch (RemoteException e) {
5087 }
5088 }
5089
5090 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5091 while (badApps.hasNext()) {
5092 SparseArray<Long> ba = badApps.next();
5093 if (ba.get(uid) != null) {
5094 badApps.remove();
5095 }
5096 }
5097
5098 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5099
5100 // Remove all processes this package may have touched: all with the
5101 // same UID (except for the system or root user), and all whose name
5102 // matches the package name.
5103 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5104 final int NA = apps.size();
5105 for (int ia=0; ia<NA; ia++) {
5106 ProcessRecord app = apps.valueAt(ia);
5107 if (app.removed) {
5108 procs.add(app);
5109 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5110 || app.processName.equals(name)
5111 || app.processName.startsWith(procNamePrefix)) {
5112 app.removed = true;
5113 procs.add(app);
5114 }
5115 }
5116 }
5117
5118 N = procs.size();
5119 for (i=0; i<N; i++) {
5120 removeProcessLocked(procs.get(i), callerWillRestart);
5121 }
5122
5123 for (i=mHistory.size()-1; i>=0; i--) {
5124 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5125 if (r.packageName.equals(name)) {
5126 if (Config.LOGD) Log.d(
5127 TAG, " Force finishing activity "
5128 + r.intent.getComponent().flattenToShortString());
5129 if (r.app != null) {
5130 r.app.removed = true;
5131 }
5132 r.app = null;
5133 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5134 }
5135 }
5136
5137 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5138 for (ServiceRecord service : mServices.values()) {
5139 if (service.packageName.equals(name)) {
5140 if (service.app != null) {
5141 service.app.removed = true;
5142 }
5143 service.app = null;
5144 services.add(service);
5145 }
5146 }
5147
5148 N = services.size();
5149 for (i=0; i<N; i++) {
5150 bringDownServiceLocked(services.get(i), true);
5151 }
5152
5153 resumeTopActivityLocked(null);
5154 }
5155
5156 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5157 final String name = app.processName;
5158 final int uid = app.info.uid;
5159 if (Config.LOGD) Log.d(
5160 TAG, "Force removing process " + app + " (" + name
5161 + "/" + uid + ")");
5162
5163 mProcessNames.remove(name, uid);
5164 boolean needRestart = false;
5165 if (app.pid > 0 && app.pid != MY_PID) {
5166 int pid = app.pid;
5167 synchronized (mPidsSelfLocked) {
5168 mPidsSelfLocked.remove(pid);
5169 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5170 }
5171 handleAppDiedLocked(app, true);
5172 mLRUProcesses.remove(app);
5173 Process.killProcess(pid);
5174
5175 if (app.persistent) {
5176 if (!callerWillRestart) {
5177 addAppLocked(app.info);
5178 } else {
5179 needRestart = true;
5180 }
5181 }
5182 } else {
5183 mRemovedProcesses.add(app);
5184 }
5185
5186 return needRestart;
5187 }
5188
5189 private final void processStartTimedOutLocked(ProcessRecord app) {
5190 final int pid = app.pid;
5191 boolean gone = false;
5192 synchronized (mPidsSelfLocked) {
5193 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5194 if (knownApp != null && knownApp.thread == null) {
5195 mPidsSelfLocked.remove(pid);
5196 gone = true;
5197 }
5198 }
5199
5200 if (gone) {
5201 Log.w(TAG, "Process " + app + " failed to attach");
5202 mProcessNames.remove(app.processName, app.info.uid);
5203 Process.killProcess(pid);
5204 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5205 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5206 mPendingBroadcast = null;
5207 scheduleBroadcastsLocked();
5208 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005209 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5210 Log.w(TAG, "Unattached app died before backup, skipping");
5211 try {
5212 IBackupManager bm = IBackupManager.Stub.asInterface(
5213 ServiceManager.getService(Context.BACKUP_SERVICE));
5214 bm.agentDisconnected(app.info.packageName);
5215 } catch (RemoteException e) {
5216 // Can't happen; the backup manager is local
5217 }
5218 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005219 } else {
5220 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5221 }
5222 }
5223
5224 private final boolean attachApplicationLocked(IApplicationThread thread,
5225 int pid) {
5226
5227 // Find the application record that is being attached... either via
5228 // the pid if we are running in multiple processes, or just pull the
5229 // next app record if we are emulating process with anonymous threads.
5230 ProcessRecord app;
5231 if (pid != MY_PID && pid >= 0) {
5232 synchronized (mPidsSelfLocked) {
5233 app = mPidsSelfLocked.get(pid);
5234 }
5235 } else if (mStartingProcesses.size() > 0) {
5236 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005237 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005238 } else {
5239 app = null;
5240 }
5241
5242 if (app == null) {
5243 Log.w(TAG, "No pending application record for pid " + pid
5244 + " (IApplicationThread " + thread + "); dropping process");
5245 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5246 if (pid > 0 && pid != MY_PID) {
5247 Process.killProcess(pid);
5248 } else {
5249 try {
5250 thread.scheduleExit();
5251 } catch (Exception e) {
5252 // Ignore exceptions.
5253 }
5254 }
5255 return false;
5256 }
5257
5258 // If this application record is still attached to a previous
5259 // process, clean it up now.
5260 if (app.thread != null) {
5261 handleAppDiedLocked(app, true);
5262 }
5263
5264 // Tell the process all about itself.
5265
5266 if (localLOGV) Log.v(
5267 TAG, "Binding process pid " + pid + " to record " + app);
5268
5269 String processName = app.processName;
5270 try {
5271 thread.asBinder().linkToDeath(new AppDeathRecipient(
5272 app, pid, thread), 0);
5273 } catch (RemoteException e) {
5274 app.resetPackageList();
5275 startProcessLocked(app, "link fail", processName);
5276 return false;
5277 }
5278
5279 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5280
5281 app.thread = thread;
5282 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005283 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005284 app.forcingToForeground = null;
5285 app.foregroundServices = false;
5286 app.debugging = false;
5287
5288 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5289
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005290 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5291 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005292
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005293 if (!normalMode) {
5294 Log.i(TAG, "Launching preboot mode app: " + app);
5295 }
5296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005297 if (localLOGV) Log.v(
5298 TAG, "New app record " + app
5299 + " thread=" + thread.asBinder() + " pid=" + pid);
5300 try {
5301 int testMode = IApplicationThread.DEBUG_OFF;
5302 if (mDebugApp != null && mDebugApp.equals(processName)) {
5303 testMode = mWaitForDebugger
5304 ? IApplicationThread.DEBUG_WAIT
5305 : IApplicationThread.DEBUG_ON;
5306 app.debugging = true;
5307 if (mDebugTransient) {
5308 mDebugApp = mOrigDebugApp;
5309 mWaitForDebugger = mOrigWaitForDebugger;
5310 }
5311 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005312
Christopher Tate181fafa2009-05-14 11:12:14 -07005313 // If the app is being launched for restore or full backup, set it up specially
5314 boolean isRestrictedBackupMode = false;
5315 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5316 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5317 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5318 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005319
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005320 ensurePackageDexOpt(app.instrumentationInfo != null
5321 ? app.instrumentationInfo.packageName
5322 : app.info.packageName);
5323 if (app.instrumentationClass != null) {
5324 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005325 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005326 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5327 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005328 thread.bindApplication(processName, app.instrumentationInfo != null
5329 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005330 app.instrumentationClass, app.instrumentationProfileFile,
5331 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005332 isRestrictedBackupMode || !normalMode,
5333 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005334 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005335 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005336 } catch (Exception e) {
5337 // todo: Yikes! What should we do? For now we will try to
5338 // start another process, but that could easily get us in
5339 // an infinite loop of restarting processes...
5340 Log.w(TAG, "Exception thrown during bind!", e);
5341
5342 app.resetPackageList();
5343 startProcessLocked(app, "bind fail", processName);
5344 return false;
5345 }
5346
5347 // Remove this record from the list of starting applications.
5348 mPersistentStartingProcesses.remove(app);
5349 mProcessesOnHold.remove(app);
5350
5351 boolean badApp = false;
5352 boolean didSomething = false;
5353
5354 // See if the top visible activity is waiting to run in this process...
5355 HistoryRecord hr = topRunningActivityLocked(null);
5356 if (hr != null) {
5357 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5358 && processName.equals(hr.processName)) {
5359 try {
5360 if (realStartActivityLocked(hr, app, true, true)) {
5361 didSomething = true;
5362 }
5363 } catch (Exception e) {
5364 Log.w(TAG, "Exception in new application when starting activity "
5365 + hr.intent.getComponent().flattenToShortString(), e);
5366 badApp = true;
5367 }
5368 } else {
5369 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5370 }
5371 }
5372
5373 // Find any services that should be running in this process...
5374 if (!badApp && mPendingServices.size() > 0) {
5375 ServiceRecord sr = null;
5376 try {
5377 for (int i=0; i<mPendingServices.size(); i++) {
5378 sr = mPendingServices.get(i);
5379 if (app.info.uid != sr.appInfo.uid
5380 || !processName.equals(sr.processName)) {
5381 continue;
5382 }
5383
5384 mPendingServices.remove(i);
5385 i--;
5386 realStartServiceLocked(sr, app);
5387 didSomething = true;
5388 }
5389 } catch (Exception e) {
5390 Log.w(TAG, "Exception in new application when starting service "
5391 + sr.shortName, e);
5392 badApp = true;
5393 }
5394 }
5395
5396 // Check if the next broadcast receiver is in this process...
5397 BroadcastRecord br = mPendingBroadcast;
5398 if (!badApp && br != null && br.curApp == app) {
5399 try {
5400 mPendingBroadcast = null;
5401 processCurBroadcastLocked(br, app);
5402 didSomething = true;
5403 } catch (Exception e) {
5404 Log.w(TAG, "Exception in new application when starting receiver "
5405 + br.curComponent.flattenToShortString(), e);
5406 badApp = true;
5407 logBroadcastReceiverDiscard(br);
5408 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5409 br.resultExtras, br.resultAbort, true);
5410 scheduleBroadcastsLocked();
5411 }
5412 }
5413
Christopher Tate181fafa2009-05-14 11:12:14 -07005414 // Check whether the next backup agent is in this process...
5415 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5416 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005417 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005418 try {
5419 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5420 } catch (Exception e) {
5421 Log.w(TAG, "Exception scheduling backup agent creation: ");
5422 e.printStackTrace();
5423 }
5424 }
5425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005426 if (badApp) {
5427 // todo: Also need to kill application to deal with all
5428 // kinds of exceptions.
5429 handleAppDiedLocked(app, false);
5430 return false;
5431 }
5432
5433 if (!didSomething) {
5434 updateOomAdjLocked();
5435 }
5436
5437 return true;
5438 }
5439
5440 public final void attachApplication(IApplicationThread thread) {
5441 synchronized (this) {
5442 int callingPid = Binder.getCallingPid();
5443 final long origId = Binder.clearCallingIdentity();
5444 attachApplicationLocked(thread, callingPid);
5445 Binder.restoreCallingIdentity(origId);
5446 }
5447 }
5448
Dianne Hackborne88846e2009-09-30 21:34:25 -07005449 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005450 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005451 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005452 Binder.restoreCallingIdentity(origId);
5453 }
5454
5455 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5456 boolean remove) {
5457 int N = mStoppingActivities.size();
5458 if (N <= 0) return null;
5459
5460 ArrayList<HistoryRecord> stops = null;
5461
5462 final boolean nowVisible = mResumedActivity != null
5463 && mResumedActivity.nowVisible
5464 && !mResumedActivity.waitingVisible;
5465 for (int i=0; i<N; i++) {
5466 HistoryRecord s = mStoppingActivities.get(i);
5467 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5468 + nowVisible + " waitingVisible=" + s.waitingVisible
5469 + " finishing=" + s.finishing);
5470 if (s.waitingVisible && nowVisible) {
5471 mWaitingVisibleActivities.remove(s);
5472 s.waitingVisible = false;
5473 if (s.finishing) {
5474 // If this activity is finishing, it is sitting on top of
5475 // everyone else but we now know it is no longer needed...
5476 // so get rid of it. Otherwise, we need to go through the
5477 // normal flow and hide it once we determine that it is
5478 // hidden by the activities in front of it.
5479 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5480 mWindowManager.setAppVisibility(s, false);
5481 }
5482 }
5483 if (!s.waitingVisible && remove) {
5484 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5485 if (stops == null) {
5486 stops = new ArrayList<HistoryRecord>();
5487 }
5488 stops.add(s);
5489 mStoppingActivities.remove(i);
5490 N--;
5491 i--;
5492 }
5493 }
5494
5495 return stops;
5496 }
5497
5498 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005499 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5500 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005501 mWindowManager.enableScreenAfterBoot();
5502 }
5503
Dianne Hackborne88846e2009-09-30 21:34:25 -07005504 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5505 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005506 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5507
5508 ArrayList<HistoryRecord> stops = null;
5509 ArrayList<HistoryRecord> finishes = null;
5510 ArrayList<HistoryRecord> thumbnails = null;
5511 int NS = 0;
5512 int NF = 0;
5513 int NT = 0;
5514 IApplicationThread sendThumbnail = null;
5515 boolean booting = false;
5516 boolean enableScreen = false;
5517
5518 synchronized (this) {
5519 if (token != null) {
5520 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5521 }
5522
5523 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005524 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005525 if (index >= 0) {
5526 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5527
Dianne Hackborne88846e2009-09-30 21:34:25 -07005528 // This is a hack to semi-deal with a race condition
5529 // in the client where it can be constructed with a
5530 // newer configuration from when we asked it to launch.
5531 // We'll update with whatever configuration it now says
5532 // it used to launch.
5533 if (config != null) {
5534 r.configuration = config;
5535 }
5536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005537 // No longer need to keep the device awake.
5538 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5539 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5540 mLaunchingActivity.release();
5541 }
5542
5543 // We are now idle. If someone is waiting for a thumbnail from
5544 // us, we can now deliver.
5545 r.idle = true;
5546 scheduleAppGcsLocked();
5547 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5548 sendThumbnail = r.app.thread;
5549 r.thumbnailNeeded = false;
5550 }
5551
5552 // If this activity is fullscreen, set up to hide those under it.
5553
5554 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5555 ensureActivitiesVisibleLocked(null, 0);
5556
5557 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5558 if (!mBooted && !fromTimeout) {
5559 mBooted = true;
5560 enableScreen = true;
5561 }
5562 }
5563
5564 // Atomically retrieve all of the other things to do.
5565 stops = processStoppingActivitiesLocked(true);
5566 NS = stops != null ? stops.size() : 0;
5567 if ((NF=mFinishingActivities.size()) > 0) {
5568 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5569 mFinishingActivities.clear();
5570 }
5571 if ((NT=mCancelledThumbnails.size()) > 0) {
5572 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5573 mCancelledThumbnails.clear();
5574 }
5575
5576 booting = mBooting;
5577 mBooting = false;
5578 }
5579
5580 int i;
5581
5582 // Send thumbnail if requested.
5583 if (sendThumbnail != null) {
5584 try {
5585 sendThumbnail.requestThumbnail(token);
5586 } catch (Exception e) {
5587 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5588 sendPendingThumbnail(null, token, null, null, true);
5589 }
5590 }
5591
5592 // Stop any activities that are scheduled to do so but have been
5593 // waiting for the next one to start.
5594 for (i=0; i<NS; i++) {
5595 HistoryRecord r = (HistoryRecord)stops.get(i);
5596 synchronized (this) {
5597 if (r.finishing) {
5598 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5599 } else {
5600 stopActivityLocked(r);
5601 }
5602 }
5603 }
5604
5605 // Finish any activities that are scheduled to do so but have been
5606 // waiting for the next one to start.
5607 for (i=0; i<NF; i++) {
5608 HistoryRecord r = (HistoryRecord)finishes.get(i);
5609 synchronized (this) {
5610 destroyActivityLocked(r, true);
5611 }
5612 }
5613
5614 // Report back to any thumbnail receivers.
5615 for (i=0; i<NT; i++) {
5616 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5617 sendPendingThumbnail(r, null, null, null, true);
5618 }
5619
5620 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005621 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005622 }
5623
5624 trimApplications();
5625 //dump();
5626 //mWindowManager.dump();
5627
5628 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005629 enableScreenAfterBoot();
5630 }
5631 }
5632
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005633 final void finishBooting() {
5634 // Ensure that any processes we had put on hold are now started
5635 // up.
5636 final int NP = mProcessesOnHold.size();
5637 if (NP > 0) {
5638 ArrayList<ProcessRecord> procs =
5639 new ArrayList<ProcessRecord>(mProcessesOnHold);
5640 for (int ip=0; ip<NP; ip++) {
5641 this.startProcessLocked(procs.get(ip), "on-hold", null);
5642 }
5643 }
5644 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5645 // Tell anyone interested that we are done booting!
5646 synchronized (this) {
5647 broadcastIntentLocked(null, null,
5648 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5649 null, null, 0, null, null,
5650 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5651 false, false, MY_PID, Process.SYSTEM_UID);
5652 }
5653 }
5654 }
5655
5656 final void ensureBootCompleted() {
5657 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005658 boolean enableScreen;
5659 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005660 booting = mBooting;
5661 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005662 enableScreen = !mBooted;
5663 mBooted = true;
5664 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005665
5666 if (booting) {
5667 finishBooting();
5668 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005669
5670 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005671 enableScreenAfterBoot();
5672 }
5673 }
5674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005675 public final void activityPaused(IBinder token, Bundle icicle) {
5676 // Refuse possible leaked file descriptors
5677 if (icicle != null && icicle.hasFileDescriptors()) {
5678 throw new IllegalArgumentException("File descriptors passed in Bundle");
5679 }
5680
5681 final long origId = Binder.clearCallingIdentity();
5682 activityPaused(token, icicle, false);
5683 Binder.restoreCallingIdentity(origId);
5684 }
5685
5686 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5687 if (DEBUG_PAUSE) Log.v(
5688 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5689 + ", timeout=" + timeout);
5690
5691 HistoryRecord r = null;
5692
5693 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005694 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005695 if (index >= 0) {
5696 r = (HistoryRecord)mHistory.get(index);
5697 if (!timeout) {
5698 r.icicle = icicle;
5699 r.haveState = true;
5700 }
5701 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5702 if (mPausingActivity == r) {
5703 r.state = ActivityState.PAUSED;
5704 completePauseLocked();
5705 } else {
5706 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5707 System.identityHashCode(r), r.shortComponentName,
5708 mPausingActivity != null
5709 ? mPausingActivity.shortComponentName : "(none)");
5710 }
5711 }
5712 }
5713 }
5714
5715 public final void activityStopped(IBinder token, Bitmap thumbnail,
5716 CharSequence description) {
5717 if (localLOGV) Log.v(
5718 TAG, "Activity stopped: token=" + token);
5719
5720 HistoryRecord r = null;
5721
5722 final long origId = Binder.clearCallingIdentity();
5723
5724 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005725 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005726 if (index >= 0) {
5727 r = (HistoryRecord)mHistory.get(index);
5728 r.thumbnail = thumbnail;
5729 r.description = description;
5730 r.stopped = true;
5731 r.state = ActivityState.STOPPED;
5732 if (!r.finishing) {
5733 if (r.configDestroy) {
5734 destroyActivityLocked(r, true);
5735 resumeTopActivityLocked(null);
5736 }
5737 }
5738 }
5739 }
5740
5741 if (r != null) {
5742 sendPendingThumbnail(r, null, null, null, false);
5743 }
5744
5745 trimApplications();
5746
5747 Binder.restoreCallingIdentity(origId);
5748 }
5749
5750 public final void activityDestroyed(IBinder token) {
5751 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5752 synchronized (this) {
5753 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5754
Dianne Hackborn75b03852009-06-12 15:43:26 -07005755 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005756 if (index >= 0) {
5757 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5758 if (r.state == ActivityState.DESTROYING) {
5759 final long origId = Binder.clearCallingIdentity();
5760 removeActivityFromHistoryLocked(r);
5761 Binder.restoreCallingIdentity(origId);
5762 }
5763 }
5764 }
5765 }
5766
5767 public String getCallingPackage(IBinder token) {
5768 synchronized (this) {
5769 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005770 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005771 }
5772 }
5773
5774 public ComponentName getCallingActivity(IBinder token) {
5775 synchronized (this) {
5776 HistoryRecord r = getCallingRecordLocked(token);
5777 return r != null ? r.intent.getComponent() : null;
5778 }
5779 }
5780
5781 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005782 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005783 if (index >= 0) {
5784 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5785 if (r != null) {
5786 return r.resultTo;
5787 }
5788 }
5789 return null;
5790 }
5791
5792 public ComponentName getActivityClassForToken(IBinder token) {
5793 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005794 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005795 if (index >= 0) {
5796 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5797 return r.intent.getComponent();
5798 }
5799 return null;
5800 }
5801 }
5802
5803 public String getPackageForToken(IBinder token) {
5804 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005805 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005806 if (index >= 0) {
5807 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5808 return r.packageName;
5809 }
5810 return null;
5811 }
5812 }
5813
5814 public IIntentSender getIntentSender(int type,
5815 String packageName, IBinder token, String resultWho,
5816 int requestCode, Intent intent, String resolvedType, int flags) {
5817 // Refuse possible leaked file descriptors
5818 if (intent != null && intent.hasFileDescriptors() == true) {
5819 throw new IllegalArgumentException("File descriptors passed in Intent");
5820 }
5821
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005822 if (type == INTENT_SENDER_BROADCAST) {
5823 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5824 throw new IllegalArgumentException(
5825 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5826 }
5827 }
5828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005829 synchronized(this) {
5830 int callingUid = Binder.getCallingUid();
5831 try {
5832 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5833 Process.supportsProcesses()) {
5834 int uid = ActivityThread.getPackageManager()
5835 .getPackageUid(packageName);
5836 if (uid != Binder.getCallingUid()) {
5837 String msg = "Permission Denial: getIntentSender() from pid="
5838 + Binder.getCallingPid()
5839 + ", uid=" + Binder.getCallingUid()
5840 + ", (need uid=" + uid + ")"
5841 + " is not allowed to send as package " + packageName;
5842 Log.w(TAG, msg);
5843 throw new SecurityException(msg);
5844 }
5845 }
5846 } catch (RemoteException e) {
5847 throw new SecurityException(e);
5848 }
5849 HistoryRecord activity = null;
5850 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005851 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005852 if (index < 0) {
5853 return null;
5854 }
5855 activity = (HistoryRecord)mHistory.get(index);
5856 if (activity.finishing) {
5857 return null;
5858 }
5859 }
5860
5861 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5862 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5863 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5864 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5865 |PendingIntent.FLAG_UPDATE_CURRENT);
5866
5867 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5868 type, packageName, activity, resultWho,
5869 requestCode, intent, resolvedType, flags);
5870 WeakReference<PendingIntentRecord> ref;
5871 ref = mIntentSenderRecords.get(key);
5872 PendingIntentRecord rec = ref != null ? ref.get() : null;
5873 if (rec != null) {
5874 if (!cancelCurrent) {
5875 if (updateCurrent) {
5876 rec.key.requestIntent.replaceExtras(intent);
5877 }
5878 return rec;
5879 }
5880 rec.canceled = true;
5881 mIntentSenderRecords.remove(key);
5882 }
5883 if (noCreate) {
5884 return rec;
5885 }
5886 rec = new PendingIntentRecord(this, key, callingUid);
5887 mIntentSenderRecords.put(key, rec.ref);
5888 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5889 if (activity.pendingResults == null) {
5890 activity.pendingResults
5891 = new HashSet<WeakReference<PendingIntentRecord>>();
5892 }
5893 activity.pendingResults.add(rec.ref);
5894 }
5895 return rec;
5896 }
5897 }
5898
5899 public void cancelIntentSender(IIntentSender sender) {
5900 if (!(sender instanceof PendingIntentRecord)) {
5901 return;
5902 }
5903 synchronized(this) {
5904 PendingIntentRecord rec = (PendingIntentRecord)sender;
5905 try {
5906 int uid = ActivityThread.getPackageManager()
5907 .getPackageUid(rec.key.packageName);
5908 if (uid != Binder.getCallingUid()) {
5909 String msg = "Permission Denial: cancelIntentSender() from pid="
5910 + Binder.getCallingPid()
5911 + ", uid=" + Binder.getCallingUid()
5912 + " is not allowed to cancel packges "
5913 + rec.key.packageName;
5914 Log.w(TAG, msg);
5915 throw new SecurityException(msg);
5916 }
5917 } catch (RemoteException e) {
5918 throw new SecurityException(e);
5919 }
5920 cancelIntentSenderLocked(rec, true);
5921 }
5922 }
5923
5924 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5925 rec.canceled = true;
5926 mIntentSenderRecords.remove(rec.key);
5927 if (cleanActivity && rec.key.activity != null) {
5928 rec.key.activity.pendingResults.remove(rec.ref);
5929 }
5930 }
5931
5932 public String getPackageForIntentSender(IIntentSender pendingResult) {
5933 if (!(pendingResult instanceof PendingIntentRecord)) {
5934 return null;
5935 }
5936 synchronized(this) {
5937 try {
5938 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5939 return res.key.packageName;
5940 } catch (ClassCastException e) {
5941 }
5942 }
5943 return null;
5944 }
5945
5946 public void setProcessLimit(int max) {
5947 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5948 "setProcessLimit()");
5949 mProcessLimit = max;
5950 }
5951
5952 public int getProcessLimit() {
5953 return mProcessLimit;
5954 }
5955
5956 void foregroundTokenDied(ForegroundToken token) {
5957 synchronized (ActivityManagerService.this) {
5958 synchronized (mPidsSelfLocked) {
5959 ForegroundToken cur
5960 = mForegroundProcesses.get(token.pid);
5961 if (cur != token) {
5962 return;
5963 }
5964 mForegroundProcesses.remove(token.pid);
5965 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5966 if (pr == null) {
5967 return;
5968 }
5969 pr.forcingToForeground = null;
5970 pr.foregroundServices = false;
5971 }
5972 updateOomAdjLocked();
5973 }
5974 }
5975
5976 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5977 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5978 "setProcessForeground()");
5979 synchronized(this) {
5980 boolean changed = false;
5981
5982 synchronized (mPidsSelfLocked) {
5983 ProcessRecord pr = mPidsSelfLocked.get(pid);
5984 if (pr == null) {
5985 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5986 return;
5987 }
5988 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5989 if (oldToken != null) {
5990 oldToken.token.unlinkToDeath(oldToken, 0);
5991 mForegroundProcesses.remove(pid);
5992 pr.forcingToForeground = null;
5993 changed = true;
5994 }
5995 if (isForeground && token != null) {
5996 ForegroundToken newToken = new ForegroundToken() {
5997 public void binderDied() {
5998 foregroundTokenDied(this);
5999 }
6000 };
6001 newToken.pid = pid;
6002 newToken.token = token;
6003 try {
6004 token.linkToDeath(newToken, 0);
6005 mForegroundProcesses.put(pid, newToken);
6006 pr.forcingToForeground = token;
6007 changed = true;
6008 } catch (RemoteException e) {
6009 // If the process died while doing this, we will later
6010 // do the cleanup with the process death link.
6011 }
6012 }
6013 }
6014
6015 if (changed) {
6016 updateOomAdjLocked();
6017 }
6018 }
6019 }
6020
6021 // =========================================================
6022 // PERMISSIONS
6023 // =========================================================
6024
6025 static class PermissionController extends IPermissionController.Stub {
6026 ActivityManagerService mActivityManagerService;
6027 PermissionController(ActivityManagerService activityManagerService) {
6028 mActivityManagerService = activityManagerService;
6029 }
6030
6031 public boolean checkPermission(String permission, int pid, int uid) {
6032 return mActivityManagerService.checkPermission(permission, pid,
6033 uid) == PackageManager.PERMISSION_GRANTED;
6034 }
6035 }
6036
6037 /**
6038 * This can be called with or without the global lock held.
6039 */
6040 int checkComponentPermission(String permission, int pid, int uid,
6041 int reqUid) {
6042 // We might be performing an operation on behalf of an indirect binder
6043 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6044 // client identity accordingly before proceeding.
6045 Identity tlsIdentity = sCallerIdentity.get();
6046 if (tlsIdentity != null) {
6047 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6048 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6049 uid = tlsIdentity.uid;
6050 pid = tlsIdentity.pid;
6051 }
6052
6053 // Root, system server and our own process get to do everything.
6054 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6055 !Process.supportsProcesses()) {
6056 return PackageManager.PERMISSION_GRANTED;
6057 }
6058 // If the target requires a specific UID, always fail for others.
6059 if (reqUid >= 0 && uid != reqUid) {
6060 return PackageManager.PERMISSION_DENIED;
6061 }
6062 if (permission == null) {
6063 return PackageManager.PERMISSION_GRANTED;
6064 }
6065 try {
6066 return ActivityThread.getPackageManager()
6067 .checkUidPermission(permission, uid);
6068 } catch (RemoteException e) {
6069 // Should never happen, but if it does... deny!
6070 Log.e(TAG, "PackageManager is dead?!?", e);
6071 }
6072 return PackageManager.PERMISSION_DENIED;
6073 }
6074
6075 /**
6076 * As the only public entry point for permissions checking, this method
6077 * can enforce the semantic that requesting a check on a null global
6078 * permission is automatically denied. (Internally a null permission
6079 * string is used when calling {@link #checkComponentPermission} in cases
6080 * when only uid-based security is needed.)
6081 *
6082 * This can be called with or without the global lock held.
6083 */
6084 public int checkPermission(String permission, int pid, int uid) {
6085 if (permission == null) {
6086 return PackageManager.PERMISSION_DENIED;
6087 }
6088 return checkComponentPermission(permission, pid, uid, -1);
6089 }
6090
6091 /**
6092 * Binder IPC calls go through the public entry point.
6093 * This can be called with or without the global lock held.
6094 */
6095 int checkCallingPermission(String permission) {
6096 return checkPermission(permission,
6097 Binder.getCallingPid(),
6098 Binder.getCallingUid());
6099 }
6100
6101 /**
6102 * This can be called with or without the global lock held.
6103 */
6104 void enforceCallingPermission(String permission, String func) {
6105 if (checkCallingPermission(permission)
6106 == PackageManager.PERMISSION_GRANTED) {
6107 return;
6108 }
6109
6110 String msg = "Permission Denial: " + func + " from pid="
6111 + Binder.getCallingPid()
6112 + ", uid=" + Binder.getCallingUid()
6113 + " requires " + permission;
6114 Log.w(TAG, msg);
6115 throw new SecurityException(msg);
6116 }
6117
6118 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6119 ProviderInfo pi, int uid, int modeFlags) {
6120 try {
6121 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6122 if ((pi.readPermission != null) &&
6123 (pm.checkUidPermission(pi.readPermission, uid)
6124 != PackageManager.PERMISSION_GRANTED)) {
6125 return false;
6126 }
6127 }
6128 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6129 if ((pi.writePermission != null) &&
6130 (pm.checkUidPermission(pi.writePermission, uid)
6131 != PackageManager.PERMISSION_GRANTED)) {
6132 return false;
6133 }
6134 }
6135 return true;
6136 } catch (RemoteException e) {
6137 return false;
6138 }
6139 }
6140
6141 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6142 int modeFlags) {
6143 // Root gets to do everything.
6144 if (uid == 0 || !Process.supportsProcesses()) {
6145 return true;
6146 }
6147 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6148 if (perms == null) return false;
6149 UriPermission perm = perms.get(uri);
6150 if (perm == null) return false;
6151 return (modeFlags&perm.modeFlags) == modeFlags;
6152 }
6153
6154 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6155 // Another redirected-binder-call permissions check as in
6156 // {@link checkComponentPermission}.
6157 Identity tlsIdentity = sCallerIdentity.get();
6158 if (tlsIdentity != null) {
6159 uid = tlsIdentity.uid;
6160 pid = tlsIdentity.pid;
6161 }
6162
6163 // Our own process gets to do everything.
6164 if (pid == MY_PID) {
6165 return PackageManager.PERMISSION_GRANTED;
6166 }
6167 synchronized(this) {
6168 return checkUriPermissionLocked(uri, uid, modeFlags)
6169 ? PackageManager.PERMISSION_GRANTED
6170 : PackageManager.PERMISSION_DENIED;
6171 }
6172 }
6173
6174 private void grantUriPermissionLocked(int callingUid,
6175 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6176 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6177 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6178 if (modeFlags == 0) {
6179 return;
6180 }
6181
6182 final IPackageManager pm = ActivityThread.getPackageManager();
6183
6184 // If this is not a content: uri, we can't do anything with it.
6185 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6186 return;
6187 }
6188
6189 String name = uri.getAuthority();
6190 ProviderInfo pi = null;
6191 ContentProviderRecord cpr
6192 = (ContentProviderRecord)mProvidersByName.get(name);
6193 if (cpr != null) {
6194 pi = cpr.info;
6195 } else {
6196 try {
6197 pi = pm.resolveContentProvider(name,
6198 PackageManager.GET_URI_PERMISSION_PATTERNS);
6199 } catch (RemoteException ex) {
6200 }
6201 }
6202 if (pi == null) {
6203 Log.w(TAG, "No content provider found for: " + name);
6204 return;
6205 }
6206
6207 int targetUid;
6208 try {
6209 targetUid = pm.getPackageUid(targetPkg);
6210 if (targetUid < 0) {
6211 return;
6212 }
6213 } catch (RemoteException ex) {
6214 return;
6215 }
6216
6217 // First... does the target actually need this permission?
6218 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6219 // No need to grant the target this permission.
6220 return;
6221 }
6222
6223 // Second... maybe someone else has already granted the
6224 // permission?
6225 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6226 // No need to grant the target this permission.
6227 return;
6228 }
6229
6230 // Third... is the provider allowing granting of URI permissions?
6231 if (!pi.grantUriPermissions) {
6232 throw new SecurityException("Provider " + pi.packageName
6233 + "/" + pi.name
6234 + " does not allow granting of Uri permissions (uri "
6235 + uri + ")");
6236 }
6237 if (pi.uriPermissionPatterns != null) {
6238 final int N = pi.uriPermissionPatterns.length;
6239 boolean allowed = false;
6240 for (int i=0; i<N; i++) {
6241 if (pi.uriPermissionPatterns[i] != null
6242 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6243 allowed = true;
6244 break;
6245 }
6246 }
6247 if (!allowed) {
6248 throw new SecurityException("Provider " + pi.packageName
6249 + "/" + pi.name
6250 + " does not allow granting of permission to path of Uri "
6251 + uri);
6252 }
6253 }
6254
6255 // Fourth... does the caller itself have permission to access
6256 // this uri?
6257 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6258 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6259 throw new SecurityException("Uid " + callingUid
6260 + " does not have permission to uri " + uri);
6261 }
6262 }
6263
6264 // Okay! So here we are: the caller has the assumed permission
6265 // to the uri, and the target doesn't. Let's now give this to
6266 // the target.
6267
6268 HashMap<Uri, UriPermission> targetUris
6269 = mGrantedUriPermissions.get(targetUid);
6270 if (targetUris == null) {
6271 targetUris = new HashMap<Uri, UriPermission>();
6272 mGrantedUriPermissions.put(targetUid, targetUris);
6273 }
6274
6275 UriPermission perm = targetUris.get(uri);
6276 if (perm == null) {
6277 perm = new UriPermission(targetUid, uri);
6278 targetUris.put(uri, perm);
6279
6280 }
6281 perm.modeFlags |= modeFlags;
6282 if (activity == null) {
6283 perm.globalModeFlags |= modeFlags;
6284 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6285 perm.readActivities.add(activity);
6286 if (activity.readUriPermissions == null) {
6287 activity.readUriPermissions = new HashSet<UriPermission>();
6288 }
6289 activity.readUriPermissions.add(perm);
6290 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6291 perm.writeActivities.add(activity);
6292 if (activity.writeUriPermissions == null) {
6293 activity.writeUriPermissions = new HashSet<UriPermission>();
6294 }
6295 activity.writeUriPermissions.add(perm);
6296 }
6297 }
6298
6299 private void grantUriPermissionFromIntentLocked(int callingUid,
6300 String targetPkg, Intent intent, HistoryRecord activity) {
6301 if (intent == null) {
6302 return;
6303 }
6304 Uri data = intent.getData();
6305 if (data == null) {
6306 return;
6307 }
6308 grantUriPermissionLocked(callingUid, targetPkg, data,
6309 intent.getFlags(), activity);
6310 }
6311
6312 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6313 Uri uri, int modeFlags) {
6314 synchronized(this) {
6315 final ProcessRecord r = getRecordForAppLocked(caller);
6316 if (r == null) {
6317 throw new SecurityException("Unable to find app for caller "
6318 + caller
6319 + " when granting permission to uri " + uri);
6320 }
6321 if (targetPkg == null) {
6322 Log.w(TAG, "grantUriPermission: null target");
6323 return;
6324 }
6325 if (uri == null) {
6326 Log.w(TAG, "grantUriPermission: null uri");
6327 return;
6328 }
6329
6330 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6331 null);
6332 }
6333 }
6334
6335 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6336 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6337 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6338 HashMap<Uri, UriPermission> perms
6339 = mGrantedUriPermissions.get(perm.uid);
6340 if (perms != null) {
6341 perms.remove(perm.uri);
6342 if (perms.size() == 0) {
6343 mGrantedUriPermissions.remove(perm.uid);
6344 }
6345 }
6346 }
6347 }
6348
6349 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6350 if (activity.readUriPermissions != null) {
6351 for (UriPermission perm : activity.readUriPermissions) {
6352 perm.readActivities.remove(activity);
6353 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6354 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6355 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6356 removeUriPermissionIfNeededLocked(perm);
6357 }
6358 }
6359 }
6360 if (activity.writeUriPermissions != null) {
6361 for (UriPermission perm : activity.writeUriPermissions) {
6362 perm.writeActivities.remove(activity);
6363 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6364 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6365 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6366 removeUriPermissionIfNeededLocked(perm);
6367 }
6368 }
6369 }
6370 }
6371
6372 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6373 int modeFlags) {
6374 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6375 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6376 if (modeFlags == 0) {
6377 return;
6378 }
6379
6380 final IPackageManager pm = ActivityThread.getPackageManager();
6381
6382 final String authority = uri.getAuthority();
6383 ProviderInfo pi = null;
6384 ContentProviderRecord cpr
6385 = (ContentProviderRecord)mProvidersByName.get(authority);
6386 if (cpr != null) {
6387 pi = cpr.info;
6388 } else {
6389 try {
6390 pi = pm.resolveContentProvider(authority,
6391 PackageManager.GET_URI_PERMISSION_PATTERNS);
6392 } catch (RemoteException ex) {
6393 }
6394 }
6395 if (pi == null) {
6396 Log.w(TAG, "No content provider found for: " + authority);
6397 return;
6398 }
6399
6400 // Does the caller have this permission on the URI?
6401 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6402 // Right now, if you are not the original owner of the permission,
6403 // you are not allowed to revoke it.
6404 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6405 throw new SecurityException("Uid " + callingUid
6406 + " does not have permission to uri " + uri);
6407 //}
6408 }
6409
6410 // Go through all of the permissions and remove any that match.
6411 final List<String> SEGMENTS = uri.getPathSegments();
6412 if (SEGMENTS != null) {
6413 final int NS = SEGMENTS.size();
6414 int N = mGrantedUriPermissions.size();
6415 for (int i=0; i<N; i++) {
6416 HashMap<Uri, UriPermission> perms
6417 = mGrantedUriPermissions.valueAt(i);
6418 Iterator<UriPermission> it = perms.values().iterator();
6419 toploop:
6420 while (it.hasNext()) {
6421 UriPermission perm = it.next();
6422 Uri targetUri = perm.uri;
6423 if (!authority.equals(targetUri.getAuthority())) {
6424 continue;
6425 }
6426 List<String> targetSegments = targetUri.getPathSegments();
6427 if (targetSegments == null) {
6428 continue;
6429 }
6430 if (targetSegments.size() < NS) {
6431 continue;
6432 }
6433 for (int j=0; j<NS; j++) {
6434 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6435 continue toploop;
6436 }
6437 }
6438 perm.clearModes(modeFlags);
6439 if (perm.modeFlags == 0) {
6440 it.remove();
6441 }
6442 }
6443 if (perms.size() == 0) {
6444 mGrantedUriPermissions.remove(
6445 mGrantedUriPermissions.keyAt(i));
6446 N--;
6447 i--;
6448 }
6449 }
6450 }
6451 }
6452
6453 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6454 int modeFlags) {
6455 synchronized(this) {
6456 final ProcessRecord r = getRecordForAppLocked(caller);
6457 if (r == null) {
6458 throw new SecurityException("Unable to find app for caller "
6459 + caller
6460 + " when revoking permission to uri " + uri);
6461 }
6462 if (uri == null) {
6463 Log.w(TAG, "revokeUriPermission: null uri");
6464 return;
6465 }
6466
6467 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6468 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6469 if (modeFlags == 0) {
6470 return;
6471 }
6472
6473 final IPackageManager pm = ActivityThread.getPackageManager();
6474
6475 final String authority = uri.getAuthority();
6476 ProviderInfo pi = null;
6477 ContentProviderRecord cpr
6478 = (ContentProviderRecord)mProvidersByName.get(authority);
6479 if (cpr != null) {
6480 pi = cpr.info;
6481 } else {
6482 try {
6483 pi = pm.resolveContentProvider(authority,
6484 PackageManager.GET_URI_PERMISSION_PATTERNS);
6485 } catch (RemoteException ex) {
6486 }
6487 }
6488 if (pi == null) {
6489 Log.w(TAG, "No content provider found for: " + authority);
6490 return;
6491 }
6492
6493 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6494 }
6495 }
6496
6497 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6498 synchronized (this) {
6499 ProcessRecord app =
6500 who != null ? getRecordForAppLocked(who) : null;
6501 if (app == null) return;
6502
6503 Message msg = Message.obtain();
6504 msg.what = WAIT_FOR_DEBUGGER_MSG;
6505 msg.obj = app;
6506 msg.arg1 = waiting ? 1 : 0;
6507 mHandler.sendMessage(msg);
6508 }
6509 }
6510
6511 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6512 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006513 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006514 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006515 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006516 }
6517
6518 // =========================================================
6519 // TASK MANAGEMENT
6520 // =========================================================
6521
6522 public List getTasks(int maxNum, int flags,
6523 IThumbnailReceiver receiver) {
6524 ArrayList list = new ArrayList();
6525
6526 PendingThumbnailsRecord pending = null;
6527 IApplicationThread topThumbnail = null;
6528 HistoryRecord topRecord = null;
6529
6530 synchronized(this) {
6531 if (localLOGV) Log.v(
6532 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6533 + ", receiver=" + receiver);
6534
6535 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6536 != PackageManager.PERMISSION_GRANTED) {
6537 if (receiver != null) {
6538 // If the caller wants to wait for pending thumbnails,
6539 // it ain't gonna get them.
6540 try {
6541 receiver.finished();
6542 } catch (RemoteException ex) {
6543 }
6544 }
6545 String msg = "Permission Denial: getTasks() from pid="
6546 + Binder.getCallingPid()
6547 + ", uid=" + Binder.getCallingUid()
6548 + " requires " + android.Manifest.permission.GET_TASKS;
6549 Log.w(TAG, msg);
6550 throw new SecurityException(msg);
6551 }
6552
6553 int pos = mHistory.size()-1;
6554 HistoryRecord next =
6555 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6556 HistoryRecord top = null;
6557 CharSequence topDescription = null;
6558 TaskRecord curTask = null;
6559 int numActivities = 0;
6560 int numRunning = 0;
6561 while (pos >= 0 && maxNum > 0) {
6562 final HistoryRecord r = next;
6563 pos--;
6564 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6565
6566 // Initialize state for next task if needed.
6567 if (top == null ||
6568 (top.state == ActivityState.INITIALIZING
6569 && top.task == r.task)) {
6570 top = r;
6571 topDescription = r.description;
6572 curTask = r.task;
6573 numActivities = numRunning = 0;
6574 }
6575
6576 // Add 'r' into the current task.
6577 numActivities++;
6578 if (r.app != null && r.app.thread != null) {
6579 numRunning++;
6580 }
6581 if (topDescription == null) {
6582 topDescription = r.description;
6583 }
6584
6585 if (localLOGV) Log.v(
6586 TAG, r.intent.getComponent().flattenToShortString()
6587 + ": task=" + r.task);
6588
6589 // If the next one is a different task, generate a new
6590 // TaskInfo entry for what we have.
6591 if (next == null || next.task != curTask) {
6592 ActivityManager.RunningTaskInfo ci
6593 = new ActivityManager.RunningTaskInfo();
6594 ci.id = curTask.taskId;
6595 ci.baseActivity = r.intent.getComponent();
6596 ci.topActivity = top.intent.getComponent();
6597 ci.thumbnail = top.thumbnail;
6598 ci.description = topDescription;
6599 ci.numActivities = numActivities;
6600 ci.numRunning = numRunning;
6601 //System.out.println(
6602 // "#" + maxNum + ": " + " descr=" + ci.description);
6603 if (ci.thumbnail == null && receiver != null) {
6604 if (localLOGV) Log.v(
6605 TAG, "State=" + top.state + "Idle=" + top.idle
6606 + " app=" + top.app
6607 + " thr=" + (top.app != null ? top.app.thread : null));
6608 if (top.state == ActivityState.RESUMED
6609 || top.state == ActivityState.PAUSING) {
6610 if (top.idle && top.app != null
6611 && top.app.thread != null) {
6612 topRecord = top;
6613 topThumbnail = top.app.thread;
6614 } else {
6615 top.thumbnailNeeded = true;
6616 }
6617 }
6618 if (pending == null) {
6619 pending = new PendingThumbnailsRecord(receiver);
6620 }
6621 pending.pendingRecords.add(top);
6622 }
6623 list.add(ci);
6624 maxNum--;
6625 top = null;
6626 }
6627 }
6628
6629 if (pending != null) {
6630 mPendingThumbnails.add(pending);
6631 }
6632 }
6633
6634 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6635
6636 if (topThumbnail != null) {
6637 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6638 try {
6639 topThumbnail.requestThumbnail(topRecord);
6640 } catch (Exception e) {
6641 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6642 sendPendingThumbnail(null, topRecord, null, null, true);
6643 }
6644 }
6645
6646 if (pending == null && receiver != null) {
6647 // In this case all thumbnails were available and the client
6648 // is being asked to be told when the remaining ones come in...
6649 // which is unusually, since the top-most currently running
6650 // activity should never have a canned thumbnail! Oh well.
6651 try {
6652 receiver.finished();
6653 } catch (RemoteException ex) {
6654 }
6655 }
6656
6657 return list;
6658 }
6659
6660 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6661 int flags) {
6662 synchronized (this) {
6663 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6664 "getRecentTasks()");
6665
6666 final int N = mRecentTasks.size();
6667 ArrayList<ActivityManager.RecentTaskInfo> res
6668 = new ArrayList<ActivityManager.RecentTaskInfo>(
6669 maxNum < N ? maxNum : N);
6670 for (int i=0; i<N && maxNum > 0; i++) {
6671 TaskRecord tr = mRecentTasks.get(i);
6672 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6673 || (tr.intent == null)
6674 || ((tr.intent.getFlags()
6675 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6676 ActivityManager.RecentTaskInfo rti
6677 = new ActivityManager.RecentTaskInfo();
6678 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6679 rti.baseIntent = new Intent(
6680 tr.intent != null ? tr.intent : tr.affinityIntent);
6681 rti.origActivity = tr.origActivity;
6682 res.add(rti);
6683 maxNum--;
6684 }
6685 }
6686 return res;
6687 }
6688 }
6689
6690 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6691 int j;
6692 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6693 TaskRecord jt = startTask;
6694
6695 // First look backwards
6696 for (j=startIndex-1; j>=0; j--) {
6697 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6698 if (r.task != jt) {
6699 jt = r.task;
6700 if (affinity.equals(jt.affinity)) {
6701 return j;
6702 }
6703 }
6704 }
6705
6706 // Now look forwards
6707 final int N = mHistory.size();
6708 jt = startTask;
6709 for (j=startIndex+1; j<N; j++) {
6710 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6711 if (r.task != jt) {
6712 if (affinity.equals(jt.affinity)) {
6713 return j;
6714 }
6715 jt = r.task;
6716 }
6717 }
6718
6719 // Might it be at the top?
6720 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6721 return N-1;
6722 }
6723
6724 return -1;
6725 }
6726
6727 /**
6728 * Perform a reset of the given task, if needed as part of launching it.
6729 * Returns the new HistoryRecord at the top of the task.
6730 */
6731 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6732 HistoryRecord newActivity) {
6733 boolean forceReset = (newActivity.info.flags
6734 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6735 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6736 if ((newActivity.info.flags
6737 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6738 forceReset = true;
6739 }
6740 }
6741
6742 final TaskRecord task = taskTop.task;
6743
6744 // We are going to move through the history list so that we can look
6745 // at each activity 'target' with 'below' either the interesting
6746 // activity immediately below it in the stack or null.
6747 HistoryRecord target = null;
6748 int targetI = 0;
6749 int taskTopI = -1;
6750 int replyChainEnd = -1;
6751 int lastReparentPos = -1;
6752 for (int i=mHistory.size()-1; i>=-1; i--) {
6753 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6754
6755 if (below != null && below.finishing) {
6756 continue;
6757 }
6758 if (target == null) {
6759 target = below;
6760 targetI = i;
6761 // If we were in the middle of a reply chain before this
6762 // task, it doesn't appear like the root of the chain wants
6763 // anything interesting, so drop it.
6764 replyChainEnd = -1;
6765 continue;
6766 }
6767
6768 final int flags = target.info.flags;
6769
6770 final boolean finishOnTaskLaunch =
6771 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6772 final boolean allowTaskReparenting =
6773 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6774
6775 if (target.task == task) {
6776 // We are inside of the task being reset... we'll either
6777 // finish this activity, push it out for another task,
6778 // or leave it as-is. We only do this
6779 // for activities that are not the root of the task (since
6780 // if we finish the root, we may no longer have the task!).
6781 if (taskTopI < 0) {
6782 taskTopI = targetI;
6783 }
6784 if (below != null && below.task == task) {
6785 final boolean clearWhenTaskReset =
6786 (target.intent.getFlags()
6787 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006788 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006789 // If this activity is sending a reply to a previous
6790 // activity, we can't do anything with it now until
6791 // we reach the start of the reply chain.
6792 // XXX note that we are assuming the result is always
6793 // to the previous activity, which is almost always
6794 // the case but we really shouldn't count on.
6795 if (replyChainEnd < 0) {
6796 replyChainEnd = targetI;
6797 }
Ed Heyl73798232009-03-24 21:32:21 -07006798 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006799 && target.taskAffinity != null
6800 && !target.taskAffinity.equals(task.affinity)) {
6801 // If this activity has an affinity for another
6802 // task, then we need to move it out of here. We will
6803 // move it as far out of the way as possible, to the
6804 // bottom of the activity stack. This also keeps it
6805 // correctly ordered with any activities we previously
6806 // moved.
6807 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6808 if (target.taskAffinity != null
6809 && target.taskAffinity.equals(p.task.affinity)) {
6810 // If the activity currently at the bottom has the
6811 // same task affinity as the one we are moving,
6812 // then merge it into the same task.
6813 target.task = p.task;
6814 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6815 + " out to bottom task " + p.task);
6816 } else {
6817 mCurTask++;
6818 if (mCurTask <= 0) {
6819 mCurTask = 1;
6820 }
6821 target.task = new TaskRecord(mCurTask, target.info, null,
6822 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6823 target.task.affinityIntent = target.intent;
6824 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6825 + " out to new task " + target.task);
6826 }
6827 mWindowManager.setAppGroupId(target, task.taskId);
6828 if (replyChainEnd < 0) {
6829 replyChainEnd = targetI;
6830 }
6831 int dstPos = 0;
6832 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6833 p = (HistoryRecord)mHistory.get(srcPos);
6834 if (p.finishing) {
6835 continue;
6836 }
6837 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6838 + " out to target's task " + target.task);
6839 task.numActivities--;
6840 p.task = target.task;
6841 target.task.numActivities++;
6842 mHistory.remove(srcPos);
6843 mHistory.add(dstPos, p);
6844 mWindowManager.moveAppToken(dstPos, p);
6845 mWindowManager.setAppGroupId(p, p.task.taskId);
6846 dstPos++;
6847 if (VALIDATE_TOKENS) {
6848 mWindowManager.validateAppTokens(mHistory);
6849 }
6850 i++;
6851 }
6852 if (taskTop == p) {
6853 taskTop = below;
6854 }
6855 if (taskTopI == replyChainEnd) {
6856 taskTopI = -1;
6857 }
6858 replyChainEnd = -1;
6859 addRecentTask(target.task);
6860 } else if (forceReset || finishOnTaskLaunch
6861 || clearWhenTaskReset) {
6862 // If the activity should just be removed -- either
6863 // because it asks for it, or the task should be
6864 // cleared -- then finish it and anything that is
6865 // part of its reply chain.
6866 if (clearWhenTaskReset) {
6867 // In this case, we want to finish this activity
6868 // and everything above it, so be sneaky and pretend
6869 // like these are all in the reply chain.
6870 replyChainEnd = targetI+1;
6871 while (replyChainEnd < mHistory.size() &&
6872 ((HistoryRecord)mHistory.get(
6873 replyChainEnd)).task == task) {
6874 replyChainEnd++;
6875 }
6876 replyChainEnd--;
6877 } else if (replyChainEnd < 0) {
6878 replyChainEnd = targetI;
6879 }
6880 HistoryRecord p = null;
6881 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6882 p = (HistoryRecord)mHistory.get(srcPos);
6883 if (p.finishing) {
6884 continue;
6885 }
6886 if (finishActivityLocked(p, srcPos,
6887 Activity.RESULT_CANCELED, null, "reset")) {
6888 replyChainEnd--;
6889 srcPos--;
6890 }
6891 }
6892 if (taskTop == p) {
6893 taskTop = below;
6894 }
6895 if (taskTopI == replyChainEnd) {
6896 taskTopI = -1;
6897 }
6898 replyChainEnd = -1;
6899 } else {
6900 // If we were in the middle of a chain, well the
6901 // activity that started it all doesn't want anything
6902 // special, so leave it all as-is.
6903 replyChainEnd = -1;
6904 }
6905 } else {
6906 // Reached the bottom of the task -- any reply chain
6907 // should be left as-is.
6908 replyChainEnd = -1;
6909 }
6910
6911 } else if (target.resultTo != null) {
6912 // If this activity is sending a reply to a previous
6913 // activity, we can't do anything with it now until
6914 // we reach the start of the reply chain.
6915 // XXX note that we are assuming the result is always
6916 // to the previous activity, which is almost always
6917 // the case but we really shouldn't count on.
6918 if (replyChainEnd < 0) {
6919 replyChainEnd = targetI;
6920 }
6921
6922 } else if (taskTopI >= 0 && allowTaskReparenting
6923 && task.affinity != null
6924 && task.affinity.equals(target.taskAffinity)) {
6925 // We are inside of another task... if this activity has
6926 // an affinity for our task, then either remove it if we are
6927 // clearing or move it over to our task. Note that
6928 // we currently punt on the case where we are resetting a
6929 // task that is not at the top but who has activities above
6930 // with an affinity to it... this is really not a normal
6931 // case, and we will need to later pull that task to the front
6932 // and usually at that point we will do the reset and pick
6933 // up those remaining activities. (This only happens if
6934 // someone starts an activity in a new task from an activity
6935 // in a task that is not currently on top.)
6936 if (forceReset || finishOnTaskLaunch) {
6937 if (replyChainEnd < 0) {
6938 replyChainEnd = targetI;
6939 }
6940 HistoryRecord p = null;
6941 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6942 p = (HistoryRecord)mHistory.get(srcPos);
6943 if (p.finishing) {
6944 continue;
6945 }
6946 if (finishActivityLocked(p, srcPos,
6947 Activity.RESULT_CANCELED, null, "reset")) {
6948 taskTopI--;
6949 lastReparentPos--;
6950 replyChainEnd--;
6951 srcPos--;
6952 }
6953 }
6954 replyChainEnd = -1;
6955 } else {
6956 if (replyChainEnd < 0) {
6957 replyChainEnd = targetI;
6958 }
6959 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6960 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6961 if (p.finishing) {
6962 continue;
6963 }
6964 if (lastReparentPos < 0) {
6965 lastReparentPos = taskTopI;
6966 taskTop = p;
6967 } else {
6968 lastReparentPos--;
6969 }
6970 mHistory.remove(srcPos);
6971 p.task.numActivities--;
6972 p.task = task;
6973 mHistory.add(lastReparentPos, p);
6974 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6975 + " in to resetting task " + task);
6976 task.numActivities++;
6977 mWindowManager.moveAppToken(lastReparentPos, p);
6978 mWindowManager.setAppGroupId(p, p.task.taskId);
6979 if (VALIDATE_TOKENS) {
6980 mWindowManager.validateAppTokens(mHistory);
6981 }
6982 }
6983 replyChainEnd = -1;
6984
6985 // Now we've moved it in to place... but what if this is
6986 // a singleTop activity and we have put it on top of another
6987 // instance of the same activity? Then we drop the instance
6988 // below so it remains singleTop.
6989 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6990 for (int j=lastReparentPos-1; j>=0; j--) {
6991 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6992 if (p.finishing) {
6993 continue;
6994 }
6995 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6996 if (finishActivityLocked(p, j,
6997 Activity.RESULT_CANCELED, null, "replace")) {
6998 taskTopI--;
6999 lastReparentPos--;
7000 }
7001 }
7002 }
7003 }
7004 }
7005 }
7006
7007 target = below;
7008 targetI = i;
7009 }
7010
7011 return taskTop;
7012 }
7013
7014 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007015 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007016 */
7017 public void moveTaskToFront(int task) {
7018 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7019 "moveTaskToFront()");
7020
7021 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007022 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7023 Binder.getCallingUid(), "Task to front")) {
7024 return;
7025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007026 final long origId = Binder.clearCallingIdentity();
7027 try {
7028 int N = mRecentTasks.size();
7029 for (int i=0; i<N; i++) {
7030 TaskRecord tr = mRecentTasks.get(i);
7031 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007032 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007033 return;
7034 }
7035 }
7036 for (int i=mHistory.size()-1; i>=0; i--) {
7037 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7038 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007039 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007040 return;
7041 }
7042 }
7043 } finally {
7044 Binder.restoreCallingIdentity(origId);
7045 }
7046 }
7047 }
7048
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007049 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007050 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7051
7052 final int task = tr.taskId;
7053 int top = mHistory.size()-1;
7054
7055 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7056 // nothing to do!
7057 return;
7058 }
7059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007060 ArrayList moved = new ArrayList();
7061
7062 // Applying the affinities may have removed entries from the history,
7063 // so get the size again.
7064 top = mHistory.size()-1;
7065 int pos = top;
7066
7067 // Shift all activities with this task up to the top
7068 // of the stack, keeping them in the same internal order.
7069 while (pos >= 0) {
7070 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7071 if (localLOGV) Log.v(
7072 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7073 boolean first = true;
7074 if (r.task.taskId == task) {
7075 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7076 mHistory.remove(pos);
7077 mHistory.add(top, r);
7078 moved.add(0, r);
7079 top--;
7080 if (first) {
7081 addRecentTask(r.task);
7082 first = false;
7083 }
7084 }
7085 pos--;
7086 }
7087
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007088 if (DEBUG_TRANSITION) Log.v(TAG,
7089 "Prepare to front transition: task=" + tr);
7090 if (reason != null &&
7091 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7092 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7093 HistoryRecord r = topRunningActivityLocked(null);
7094 if (r != null) {
7095 mNoAnimActivities.add(r);
7096 }
7097 } else {
7098 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7099 }
7100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007101 mWindowManager.moveAppTokensToTop(moved);
7102 if (VALIDATE_TOKENS) {
7103 mWindowManager.validateAppTokens(mHistory);
7104 }
7105
7106 finishTaskMove(task);
7107 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7108 }
7109
7110 private final void finishTaskMove(int task) {
7111 resumeTopActivityLocked(null);
7112 }
7113
7114 public void moveTaskToBack(int task) {
7115 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7116 "moveTaskToBack()");
7117
7118 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007119 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7120 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7121 Binder.getCallingUid(), "Task to back")) {
7122 return;
7123 }
7124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007125 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007126 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007127 Binder.restoreCallingIdentity(origId);
7128 }
7129 }
7130
7131 /**
7132 * Moves an activity, and all of the other activities within the same task, to the bottom
7133 * of the history stack. The activity's order within the task is unchanged.
7134 *
7135 * @param token A reference to the activity we wish to move
7136 * @param nonRoot If false then this only works if the activity is the root
7137 * of a task; if true it will work for any activity in a task.
7138 * @return Returns true if the move completed, false if not.
7139 */
7140 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7141 synchronized(this) {
7142 final long origId = Binder.clearCallingIdentity();
7143 int taskId = getTaskForActivityLocked(token, !nonRoot);
7144 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007145 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007146 }
7147 Binder.restoreCallingIdentity(origId);
7148 }
7149 return false;
7150 }
7151
7152 /**
7153 * Worker method for rearranging history stack. Implements the function of moving all
7154 * activities for a specific task (gathering them if disjoint) into a single group at the
7155 * bottom of the stack.
7156 *
7157 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7158 * to premeptively cancel the move.
7159 *
7160 * @param task The taskId to collect and move to the bottom.
7161 * @return Returns true if the move completed, false if not.
7162 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007163 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007164 Log.i(TAG, "moveTaskToBack: " + task);
7165
7166 // If we have a watcher, preflight the move before committing to it. First check
7167 // for *other* available tasks, but if none are available, then try again allowing the
7168 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007169 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007170 HistoryRecord next = topRunningActivityLocked(null, task);
7171 if (next == null) {
7172 next = topRunningActivityLocked(null, 0);
7173 }
7174 if (next != null) {
7175 // ask watcher if this is allowed
7176 boolean moveOK = true;
7177 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007178 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007179 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007180 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007181 }
7182 if (!moveOK) {
7183 return false;
7184 }
7185 }
7186 }
7187
7188 ArrayList moved = new ArrayList();
7189
7190 if (DEBUG_TRANSITION) Log.v(TAG,
7191 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007192
7193 final int N = mHistory.size();
7194 int bottom = 0;
7195 int pos = 0;
7196
7197 // Shift all activities with this task down to the bottom
7198 // of the stack, keeping them in the same internal order.
7199 while (pos < N) {
7200 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7201 if (localLOGV) Log.v(
7202 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7203 if (r.task.taskId == task) {
7204 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7205 mHistory.remove(pos);
7206 mHistory.add(bottom, r);
7207 moved.add(r);
7208 bottom++;
7209 }
7210 pos++;
7211 }
7212
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007213 if (reason != null &&
7214 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7215 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7216 HistoryRecord r = topRunningActivityLocked(null);
7217 if (r != null) {
7218 mNoAnimActivities.add(r);
7219 }
7220 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007221 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007223 mWindowManager.moveAppTokensToBottom(moved);
7224 if (VALIDATE_TOKENS) {
7225 mWindowManager.validateAppTokens(mHistory);
7226 }
7227
7228 finishTaskMove(task);
7229 return true;
7230 }
7231
7232 public void moveTaskBackwards(int task) {
7233 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7234 "moveTaskBackwards()");
7235
7236 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007237 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7238 Binder.getCallingUid(), "Task backwards")) {
7239 return;
7240 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007241 final long origId = Binder.clearCallingIdentity();
7242 moveTaskBackwardsLocked(task);
7243 Binder.restoreCallingIdentity(origId);
7244 }
7245 }
7246
7247 private final void moveTaskBackwardsLocked(int task) {
7248 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7249 }
7250
7251 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7252 synchronized(this) {
7253 return getTaskForActivityLocked(token, onlyRoot);
7254 }
7255 }
7256
7257 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7258 final int N = mHistory.size();
7259 TaskRecord lastTask = null;
7260 for (int i=0; i<N; i++) {
7261 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7262 if (r == token) {
7263 if (!onlyRoot || lastTask != r.task) {
7264 return r.task.taskId;
7265 }
7266 return -1;
7267 }
7268 lastTask = r.task;
7269 }
7270
7271 return -1;
7272 }
7273
7274 /**
7275 * Returns the top activity in any existing task matching the given
7276 * Intent. Returns null if no such task is found.
7277 */
7278 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7279 ComponentName cls = intent.getComponent();
7280 if (info.targetActivity != null) {
7281 cls = new ComponentName(info.packageName, info.targetActivity);
7282 }
7283
7284 TaskRecord cp = null;
7285
7286 final int N = mHistory.size();
7287 for (int i=(N-1); i>=0; i--) {
7288 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7289 if (!r.finishing && r.task != cp
7290 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7291 cp = r.task;
7292 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7293 // + "/aff=" + r.task.affinity + " to new cls="
7294 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7295 if (r.task.affinity != null) {
7296 if (r.task.affinity.equals(info.taskAffinity)) {
7297 //Log.i(TAG, "Found matching affinity!");
7298 return r;
7299 }
7300 } else if (r.task.intent != null
7301 && r.task.intent.getComponent().equals(cls)) {
7302 //Log.i(TAG, "Found matching class!");
7303 //dump();
7304 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7305 return r;
7306 } else if (r.task.affinityIntent != null
7307 && r.task.affinityIntent.getComponent().equals(cls)) {
7308 //Log.i(TAG, "Found matching class!");
7309 //dump();
7310 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7311 return r;
7312 }
7313 }
7314 }
7315
7316 return null;
7317 }
7318
7319 /**
7320 * Returns the first activity (starting from the top of the stack) that
7321 * is the same as the given activity. Returns null if no such activity
7322 * is found.
7323 */
7324 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7325 ComponentName cls = intent.getComponent();
7326 if (info.targetActivity != null) {
7327 cls = new ComponentName(info.packageName, info.targetActivity);
7328 }
7329
7330 final int N = mHistory.size();
7331 for (int i=(N-1); i>=0; i--) {
7332 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7333 if (!r.finishing) {
7334 if (r.intent.getComponent().equals(cls)) {
7335 //Log.i(TAG, "Found matching class!");
7336 //dump();
7337 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7338 return r;
7339 }
7340 }
7341 }
7342
7343 return null;
7344 }
7345
7346 public void finishOtherInstances(IBinder token, ComponentName className) {
7347 synchronized(this) {
7348 final long origId = Binder.clearCallingIdentity();
7349
7350 int N = mHistory.size();
7351 TaskRecord lastTask = null;
7352 for (int i=0; i<N; i++) {
7353 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7354 if (r.realActivity.equals(className)
7355 && r != token && lastTask != r.task) {
7356 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7357 null, "others")) {
7358 i--;
7359 N--;
7360 }
7361 }
7362 lastTask = r.task;
7363 }
7364
7365 Binder.restoreCallingIdentity(origId);
7366 }
7367 }
7368
7369 // =========================================================
7370 // THUMBNAILS
7371 // =========================================================
7372
7373 public void reportThumbnail(IBinder token,
7374 Bitmap thumbnail, CharSequence description) {
7375 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7376 final long origId = Binder.clearCallingIdentity();
7377 sendPendingThumbnail(null, token, thumbnail, description, true);
7378 Binder.restoreCallingIdentity(origId);
7379 }
7380
7381 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7382 Bitmap thumbnail, CharSequence description, boolean always) {
7383 TaskRecord task = null;
7384 ArrayList receivers = null;
7385
7386 //System.out.println("Send pending thumbnail: " + r);
7387
7388 synchronized(this) {
7389 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007390 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007391 if (index < 0) {
7392 return;
7393 }
7394 r = (HistoryRecord)mHistory.get(index);
7395 }
7396 if (thumbnail == null) {
7397 thumbnail = r.thumbnail;
7398 description = r.description;
7399 }
7400 if (thumbnail == null && !always) {
7401 // If there is no thumbnail, and this entry is not actually
7402 // going away, then abort for now and pick up the next
7403 // thumbnail we get.
7404 return;
7405 }
7406 task = r.task;
7407
7408 int N = mPendingThumbnails.size();
7409 int i=0;
7410 while (i<N) {
7411 PendingThumbnailsRecord pr =
7412 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7413 //System.out.println("Looking in " + pr.pendingRecords);
7414 if (pr.pendingRecords.remove(r)) {
7415 if (receivers == null) {
7416 receivers = new ArrayList();
7417 }
7418 receivers.add(pr);
7419 if (pr.pendingRecords.size() == 0) {
7420 pr.finished = true;
7421 mPendingThumbnails.remove(i);
7422 N--;
7423 continue;
7424 }
7425 }
7426 i++;
7427 }
7428 }
7429
7430 if (receivers != null) {
7431 final int N = receivers.size();
7432 for (int i=0; i<N; i++) {
7433 try {
7434 PendingThumbnailsRecord pr =
7435 (PendingThumbnailsRecord)receivers.get(i);
7436 pr.receiver.newThumbnail(
7437 task != null ? task.taskId : -1, thumbnail, description);
7438 if (pr.finished) {
7439 pr.receiver.finished();
7440 }
7441 } catch (Exception e) {
7442 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7443 }
7444 }
7445 }
7446 }
7447
7448 // =========================================================
7449 // CONTENT PROVIDERS
7450 // =========================================================
7451
7452 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7453 List providers = null;
7454 try {
7455 providers = ActivityThread.getPackageManager().
7456 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007457 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007458 } catch (RemoteException ex) {
7459 }
7460 if (providers != null) {
7461 final int N = providers.size();
7462 for (int i=0; i<N; i++) {
7463 ProviderInfo cpi =
7464 (ProviderInfo)providers.get(i);
7465 ContentProviderRecord cpr =
7466 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7467 if (cpr == null) {
7468 cpr = new ContentProviderRecord(cpi, app.info);
7469 mProvidersByClass.put(cpi.name, cpr);
7470 }
7471 app.pubProviders.put(cpi.name, cpr);
7472 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007473 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007474 }
7475 }
7476 return providers;
7477 }
7478
7479 private final String checkContentProviderPermissionLocked(
7480 ProviderInfo cpi, ProcessRecord r, int mode) {
7481 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7482 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7483 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7484 cpi.exported ? -1 : cpi.applicationInfo.uid)
7485 == PackageManager.PERMISSION_GRANTED
7486 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7487 return null;
7488 }
7489 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7490 cpi.exported ? -1 : cpi.applicationInfo.uid)
7491 == PackageManager.PERMISSION_GRANTED) {
7492 return null;
7493 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007494
7495 PathPermission[] pps = cpi.pathPermissions;
7496 if (pps != null) {
7497 int i = pps.length;
7498 while (i > 0) {
7499 i--;
7500 PathPermission pp = pps[i];
7501 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7502 cpi.exported ? -1 : cpi.applicationInfo.uid)
7503 == PackageManager.PERMISSION_GRANTED
7504 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7505 return null;
7506 }
7507 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7508 cpi.exported ? -1 : cpi.applicationInfo.uid)
7509 == PackageManager.PERMISSION_GRANTED) {
7510 return null;
7511 }
7512 }
7513 }
7514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007515 String msg = "Permission Denial: opening provider " + cpi.name
7516 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7517 + ", uid=" + callingUid + ") requires "
7518 + cpi.readPermission + " or " + cpi.writePermission;
7519 Log.w(TAG, msg);
7520 return msg;
7521 }
7522
7523 private final ContentProviderHolder getContentProviderImpl(
7524 IApplicationThread caller, String name) {
7525 ContentProviderRecord cpr;
7526 ProviderInfo cpi = null;
7527
7528 synchronized(this) {
7529 ProcessRecord r = null;
7530 if (caller != null) {
7531 r = getRecordForAppLocked(caller);
7532 if (r == null) {
7533 throw new SecurityException(
7534 "Unable to find app for caller " + caller
7535 + " (pid=" + Binder.getCallingPid()
7536 + ") when getting content provider " + name);
7537 }
7538 }
7539
7540 // First check if this content provider has been published...
7541 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7542 if (cpr != null) {
7543 cpi = cpr.info;
7544 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7545 return new ContentProviderHolder(cpi,
7546 cpi.readPermission != null
7547 ? cpi.readPermission : cpi.writePermission);
7548 }
7549
7550 if (r != null && cpr.canRunHere(r)) {
7551 // This provider has been published or is in the process
7552 // of being published... but it is also allowed to run
7553 // in the caller's process, so don't make a connection
7554 // and just let the caller instantiate its own instance.
7555 if (cpr.provider != null) {
7556 // don't give caller the provider object, it needs
7557 // to make its own.
7558 cpr = new ContentProviderRecord(cpr);
7559 }
7560 return cpr;
7561 }
7562
7563 final long origId = Binder.clearCallingIdentity();
7564
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007565 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007566 // return it right away.
7567 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007568 if (DEBUG_PROVIDER) Log.v(TAG,
7569 "Adding provider requested by "
7570 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007571 + cpr.info.processName);
7572 Integer cnt = r.conProviders.get(cpr);
7573 if (cnt == null) {
7574 r.conProviders.put(cpr, new Integer(1));
7575 } else {
7576 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7577 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007578 cpr.clients.add(r);
7579 } else {
7580 cpr.externals++;
7581 }
7582
7583 if (cpr.app != null) {
7584 updateOomAdjLocked(cpr.app);
7585 }
7586
7587 Binder.restoreCallingIdentity(origId);
7588
7589 } else {
7590 try {
7591 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007592 resolveContentProvider(name,
7593 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007594 } catch (RemoteException ex) {
7595 }
7596 if (cpi == null) {
7597 return null;
7598 }
7599
7600 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7601 return new ContentProviderHolder(cpi,
7602 cpi.readPermission != null
7603 ? cpi.readPermission : cpi.writePermission);
7604 }
7605
7606 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7607 final boolean firstClass = cpr == null;
7608 if (firstClass) {
7609 try {
7610 ApplicationInfo ai =
7611 ActivityThread.getPackageManager().
7612 getApplicationInfo(
7613 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007614 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007615 if (ai == null) {
7616 Log.w(TAG, "No package info for content provider "
7617 + cpi.name);
7618 return null;
7619 }
7620 cpr = new ContentProviderRecord(cpi, ai);
7621 } catch (RemoteException ex) {
7622 // pm is in same process, this will never happen.
7623 }
7624 }
7625
7626 if (r != null && cpr.canRunHere(r)) {
7627 // If this is a multiprocess provider, then just return its
7628 // info and allow the caller to instantiate it. Only do
7629 // this if the provider is the same user as the caller's
7630 // process, or can run as root (so can be in any process).
7631 return cpr;
7632 }
7633
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007634 if (DEBUG_PROVIDER) {
7635 RuntimeException e = new RuntimeException("here");
7636 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7637 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007638 }
7639
7640 // This is single process, and our app is now connecting to it.
7641 // See if we are already in the process of launching this
7642 // provider.
7643 final int N = mLaunchingProviders.size();
7644 int i;
7645 for (i=0; i<N; i++) {
7646 if (mLaunchingProviders.get(i) == cpr) {
7647 break;
7648 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007649 }
7650
7651 // If the provider is not already being launched, then get it
7652 // started.
7653 if (i >= N) {
7654 final long origId = Binder.clearCallingIdentity();
7655 ProcessRecord proc = startProcessLocked(cpi.processName,
7656 cpr.appInfo, false, 0, "content provider",
7657 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007658 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007659 if (proc == null) {
7660 Log.w(TAG, "Unable to launch app "
7661 + cpi.applicationInfo.packageName + "/"
7662 + cpi.applicationInfo.uid + " for provider "
7663 + name + ": process is bad");
7664 return null;
7665 }
7666 cpr.launchingApp = proc;
7667 mLaunchingProviders.add(cpr);
7668 Binder.restoreCallingIdentity(origId);
7669 }
7670
7671 // Make sure the provider is published (the same provider class
7672 // may be published under multiple names).
7673 if (firstClass) {
7674 mProvidersByClass.put(cpi.name, cpr);
7675 }
7676 mProvidersByName.put(name, cpr);
7677
7678 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007679 if (DEBUG_PROVIDER) Log.v(TAG,
7680 "Adding provider requested by "
7681 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007682 + cpr.info.processName);
7683 Integer cnt = r.conProviders.get(cpr);
7684 if (cnt == null) {
7685 r.conProviders.put(cpr, new Integer(1));
7686 } else {
7687 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007689 cpr.clients.add(r);
7690 } else {
7691 cpr.externals++;
7692 }
7693 }
7694 }
7695
7696 // Wait for the provider to be published...
7697 synchronized (cpr) {
7698 while (cpr.provider == null) {
7699 if (cpr.launchingApp == null) {
7700 Log.w(TAG, "Unable to launch app "
7701 + cpi.applicationInfo.packageName + "/"
7702 + cpi.applicationInfo.uid + " for provider "
7703 + name + ": launching app became null");
7704 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7705 cpi.applicationInfo.packageName,
7706 cpi.applicationInfo.uid, name);
7707 return null;
7708 }
7709 try {
7710 cpr.wait();
7711 } catch (InterruptedException ex) {
7712 }
7713 }
7714 }
7715 return cpr;
7716 }
7717
7718 public final ContentProviderHolder getContentProvider(
7719 IApplicationThread caller, String name) {
7720 if (caller == null) {
7721 String msg = "null IApplicationThread when getting content provider "
7722 + name;
7723 Log.w(TAG, msg);
7724 throw new SecurityException(msg);
7725 }
7726
7727 return getContentProviderImpl(caller, name);
7728 }
7729
7730 private ContentProviderHolder getContentProviderExternal(String name) {
7731 return getContentProviderImpl(null, name);
7732 }
7733
7734 /**
7735 * Drop a content provider from a ProcessRecord's bookkeeping
7736 * @param cpr
7737 */
7738 public void removeContentProvider(IApplicationThread caller, String name) {
7739 synchronized (this) {
7740 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7741 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007742 // remove from mProvidersByClass
7743 if (DEBUG_PROVIDER) Log.v(TAG, name +
7744 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007745 return;
7746 }
7747 final ProcessRecord r = getRecordForAppLocked(caller);
7748 if (r == null) {
7749 throw new SecurityException(
7750 "Unable to find app for caller " + caller +
7751 " when removing content provider " + name);
7752 }
7753 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007754 ContentProviderRecord localCpr = (ContentProviderRecord)
7755 mProvidersByClass.get(cpr.info.name);
7756 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7757 + r.info.processName + " from process "
7758 + localCpr.appInfo.processName);
7759 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007760 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007761 Log.w(TAG, "removeContentProvider called on local provider: "
7762 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007763 return;
7764 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007765 Integer cnt = r.conProviders.get(localCpr);
7766 if (cnt == null || cnt.intValue() <= 1) {
7767 localCpr.clients.remove(r);
7768 r.conProviders.remove(localCpr);
7769 } else {
7770 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7771 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007772 }
7773 updateOomAdjLocked();
7774 }
7775 }
7776
7777 private void removeContentProviderExternal(String name) {
7778 synchronized (this) {
7779 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7780 if(cpr == null) {
7781 //remove from mProvidersByClass
7782 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7783 return;
7784 }
7785
7786 //update content provider record entry info
7787 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7788 localCpr.externals--;
7789 if (localCpr.externals < 0) {
7790 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7791 }
7792 updateOomAdjLocked();
7793 }
7794 }
7795
7796 public final void publishContentProviders(IApplicationThread caller,
7797 List<ContentProviderHolder> providers) {
7798 if (providers == null) {
7799 return;
7800 }
7801
7802 synchronized(this) {
7803 final ProcessRecord r = getRecordForAppLocked(caller);
7804 if (r == null) {
7805 throw new SecurityException(
7806 "Unable to find app for caller " + caller
7807 + " (pid=" + Binder.getCallingPid()
7808 + ") when publishing content providers");
7809 }
7810
7811 final long origId = Binder.clearCallingIdentity();
7812
7813 final int N = providers.size();
7814 for (int i=0; i<N; i++) {
7815 ContentProviderHolder src = providers.get(i);
7816 if (src == null || src.info == null || src.provider == null) {
7817 continue;
7818 }
7819 ContentProviderRecord dst =
7820 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7821 if (dst != null) {
7822 mProvidersByClass.put(dst.info.name, dst);
7823 String names[] = dst.info.authority.split(";");
7824 for (int j = 0; j < names.length; j++) {
7825 mProvidersByName.put(names[j], dst);
7826 }
7827
7828 int NL = mLaunchingProviders.size();
7829 int j;
7830 for (j=0; j<NL; j++) {
7831 if (mLaunchingProviders.get(j) == dst) {
7832 mLaunchingProviders.remove(j);
7833 j--;
7834 NL--;
7835 }
7836 }
7837 synchronized (dst) {
7838 dst.provider = src.provider;
7839 dst.app = r;
7840 dst.notifyAll();
7841 }
7842 updateOomAdjLocked(r);
7843 }
7844 }
7845
7846 Binder.restoreCallingIdentity(origId);
7847 }
7848 }
7849
7850 public static final void installSystemProviders() {
7851 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7852 List providers = mSelf.generateApplicationProvidersLocked(app);
7853 mSystemThread.installSystemProviders(providers);
7854 }
7855
7856 // =========================================================
7857 // GLOBAL MANAGEMENT
7858 // =========================================================
7859
7860 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7861 ApplicationInfo info, String customProcess) {
7862 String proc = customProcess != null ? customProcess : info.processName;
7863 BatteryStatsImpl.Uid.Proc ps = null;
7864 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7865 synchronized (stats) {
7866 ps = stats.getProcessStatsLocked(info.uid, proc);
7867 }
7868 return new ProcessRecord(ps, thread, info, proc);
7869 }
7870
7871 final ProcessRecord addAppLocked(ApplicationInfo info) {
7872 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7873
7874 if (app == null) {
7875 app = newProcessRecordLocked(null, info, null);
7876 mProcessNames.put(info.processName, info.uid, app);
7877 updateLRUListLocked(app, true);
7878 }
7879
7880 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7881 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7882 app.persistent = true;
7883 app.maxAdj = CORE_SERVER_ADJ;
7884 }
7885 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7886 mPersistentStartingProcesses.add(app);
7887 startProcessLocked(app, "added application", app.processName);
7888 }
7889
7890 return app;
7891 }
7892
7893 public void unhandledBack() {
7894 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7895 "unhandledBack()");
7896
7897 synchronized(this) {
7898 int count = mHistory.size();
7899 if (Config.LOGD) Log.d(
7900 TAG, "Performing unhandledBack(): stack size = " + count);
7901 if (count > 1) {
7902 final long origId = Binder.clearCallingIdentity();
7903 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7904 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7905 Binder.restoreCallingIdentity(origId);
7906 }
7907 }
7908 }
7909
7910 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7911 String name = uri.getAuthority();
7912 ContentProviderHolder cph = getContentProviderExternal(name);
7913 ParcelFileDescriptor pfd = null;
7914 if (cph != null) {
7915 // We record the binder invoker's uid in thread-local storage before
7916 // going to the content provider to open the file. Later, in the code
7917 // that handles all permissions checks, we look for this uid and use
7918 // that rather than the Activity Manager's own uid. The effect is that
7919 // we do the check against the caller's permissions even though it looks
7920 // to the content provider like the Activity Manager itself is making
7921 // the request.
7922 sCallerIdentity.set(new Identity(
7923 Binder.getCallingPid(), Binder.getCallingUid()));
7924 try {
7925 pfd = cph.provider.openFile(uri, "r");
7926 } catch (FileNotFoundException e) {
7927 // do nothing; pfd will be returned null
7928 } finally {
7929 // Ensure that whatever happens, we clean up the identity state
7930 sCallerIdentity.remove();
7931 }
7932
7933 // We've got the fd now, so we're done with the provider.
7934 removeContentProviderExternal(name);
7935 } else {
7936 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7937 }
7938 return pfd;
7939 }
7940
7941 public void goingToSleep() {
7942 synchronized(this) {
7943 mSleeping = true;
7944 mWindowManager.setEventDispatching(false);
7945
7946 if (mResumedActivity != null) {
7947 pauseIfSleepingLocked();
7948 } else {
7949 Log.w(TAG, "goingToSleep with no resumed activity!");
7950 }
7951 }
7952 }
7953
Dianne Hackborn55280a92009-05-07 15:53:46 -07007954 public boolean shutdown(int timeout) {
7955 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7956 != PackageManager.PERMISSION_GRANTED) {
7957 throw new SecurityException("Requires permission "
7958 + android.Manifest.permission.SHUTDOWN);
7959 }
7960
7961 boolean timedout = false;
7962
7963 synchronized(this) {
7964 mShuttingDown = true;
7965 mWindowManager.setEventDispatching(false);
7966
7967 if (mResumedActivity != null) {
7968 pauseIfSleepingLocked();
7969 final long endTime = System.currentTimeMillis() + timeout;
7970 while (mResumedActivity != null || mPausingActivity != null) {
7971 long delay = endTime - System.currentTimeMillis();
7972 if (delay <= 0) {
7973 Log.w(TAG, "Activity manager shutdown timed out");
7974 timedout = true;
7975 break;
7976 }
7977 try {
7978 this.wait();
7979 } catch (InterruptedException e) {
7980 }
7981 }
7982 }
7983 }
7984
7985 mUsageStatsService.shutdown();
7986 mBatteryStatsService.shutdown();
7987
7988 return timedout;
7989 }
7990
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007991 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007992 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007993 if (!mGoingToSleep.isHeld()) {
7994 mGoingToSleep.acquire();
7995 if (mLaunchingActivity.isHeld()) {
7996 mLaunchingActivity.release();
7997 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7998 }
7999 }
8000
8001 // If we are not currently pausing an activity, get the current
8002 // one to pause. If we are pausing one, we will just let that stuff
8003 // run and release the wake lock when all done.
8004 if (mPausingActivity == null) {
8005 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8006 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8007 startPausingLocked(false, true);
8008 }
8009 }
8010 }
8011
8012 public void wakingUp() {
8013 synchronized(this) {
8014 if (mGoingToSleep.isHeld()) {
8015 mGoingToSleep.release();
8016 }
8017 mWindowManager.setEventDispatching(true);
8018 mSleeping = false;
8019 resumeTopActivityLocked(null);
8020 }
8021 }
8022
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008023 public void stopAppSwitches() {
8024 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8025 != PackageManager.PERMISSION_GRANTED) {
8026 throw new SecurityException("Requires permission "
8027 + android.Manifest.permission.STOP_APP_SWITCHES);
8028 }
8029
8030 synchronized(this) {
8031 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8032 + APP_SWITCH_DELAY_TIME;
8033 mDidAppSwitch = false;
8034 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8035 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8036 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8037 }
8038 }
8039
8040 public void resumeAppSwitches() {
8041 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8042 != PackageManager.PERMISSION_GRANTED) {
8043 throw new SecurityException("Requires permission "
8044 + android.Manifest.permission.STOP_APP_SWITCHES);
8045 }
8046
8047 synchronized(this) {
8048 // Note that we don't execute any pending app switches... we will
8049 // let those wait until either the timeout, or the next start
8050 // activity request.
8051 mAppSwitchesAllowedTime = 0;
8052 }
8053 }
8054
8055 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8056 String name) {
8057 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8058 return true;
8059 }
8060
8061 final int perm = checkComponentPermission(
8062 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8063 callingUid, -1);
8064 if (perm == PackageManager.PERMISSION_GRANTED) {
8065 return true;
8066 }
8067
8068 Log.w(TAG, name + " request from " + callingUid + " stopped");
8069 return false;
8070 }
8071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008072 public void setDebugApp(String packageName, boolean waitForDebugger,
8073 boolean persistent) {
8074 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8075 "setDebugApp()");
8076
8077 // Note that this is not really thread safe if there are multiple
8078 // callers into it at the same time, but that's not a situation we
8079 // care about.
8080 if (persistent) {
8081 final ContentResolver resolver = mContext.getContentResolver();
8082 Settings.System.putString(
8083 resolver, Settings.System.DEBUG_APP,
8084 packageName);
8085 Settings.System.putInt(
8086 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8087 waitForDebugger ? 1 : 0);
8088 }
8089
8090 synchronized (this) {
8091 if (!persistent) {
8092 mOrigDebugApp = mDebugApp;
8093 mOrigWaitForDebugger = mWaitForDebugger;
8094 }
8095 mDebugApp = packageName;
8096 mWaitForDebugger = waitForDebugger;
8097 mDebugTransient = !persistent;
8098 if (packageName != null) {
8099 final long origId = Binder.clearCallingIdentity();
8100 uninstallPackageLocked(packageName, -1, false);
8101 Binder.restoreCallingIdentity(origId);
8102 }
8103 }
8104 }
8105
8106 public void setAlwaysFinish(boolean enabled) {
8107 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8108 "setAlwaysFinish()");
8109
8110 Settings.System.putInt(
8111 mContext.getContentResolver(),
8112 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8113
8114 synchronized (this) {
8115 mAlwaysFinishActivities = enabled;
8116 }
8117 }
8118
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008119 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008120 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008121 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008122 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008123 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008124 }
8125 }
8126
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008127 public void registerActivityWatcher(IActivityWatcher watcher) {
8128 mWatchers.register(watcher);
8129 }
8130
8131 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8132 mWatchers.unregister(watcher);
8133 }
8134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008135 public final void enterSafeMode() {
8136 synchronized(this) {
8137 // It only makes sense to do this before the system is ready
8138 // and started launching other packages.
8139 if (!mSystemReady) {
8140 try {
8141 ActivityThread.getPackageManager().enterSafeMode();
8142 } catch (RemoteException e) {
8143 }
8144
8145 View v = LayoutInflater.from(mContext).inflate(
8146 com.android.internal.R.layout.safe_mode, null);
8147 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8148 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8149 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8150 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8151 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8152 lp.format = v.getBackground().getOpacity();
8153 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8154 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8155 ((WindowManager)mContext.getSystemService(
8156 Context.WINDOW_SERVICE)).addView(v, lp);
8157 }
8158 }
8159 }
8160
8161 public void noteWakeupAlarm(IIntentSender sender) {
8162 if (!(sender instanceof PendingIntentRecord)) {
8163 return;
8164 }
8165 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8166 synchronized (stats) {
8167 if (mBatteryStatsService.isOnBattery()) {
8168 mBatteryStatsService.enforceCallingPermission();
8169 PendingIntentRecord rec = (PendingIntentRecord)sender;
8170 int MY_UID = Binder.getCallingUid();
8171 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8172 BatteryStatsImpl.Uid.Pkg pkg =
8173 stats.getPackageStatsLocked(uid, rec.key.packageName);
8174 pkg.incWakeupsLocked();
8175 }
8176 }
8177 }
8178
8179 public boolean killPidsForMemory(int[] pids) {
8180 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8181 throw new SecurityException("killPidsForMemory only available to the system");
8182 }
8183
8184 // XXX Note: don't acquire main activity lock here, because the window
8185 // manager calls in with its locks held.
8186
8187 boolean killed = false;
8188 synchronized (mPidsSelfLocked) {
8189 int[] types = new int[pids.length];
8190 int worstType = 0;
8191 for (int i=0; i<pids.length; i++) {
8192 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8193 if (proc != null) {
8194 int type = proc.setAdj;
8195 types[i] = type;
8196 if (type > worstType) {
8197 worstType = type;
8198 }
8199 }
8200 }
8201
8202 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8203 // then constrain it so we will kill all hidden procs.
8204 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8205 worstType = HIDDEN_APP_MIN_ADJ;
8206 }
8207 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8208 for (int i=0; i<pids.length; i++) {
8209 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8210 if (proc == null) {
8211 continue;
8212 }
8213 int adj = proc.setAdj;
8214 if (adj >= worstType) {
8215 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8216 + adj + ")");
8217 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8218 proc.processName, adj);
8219 killed = true;
8220 Process.killProcess(pids[i]);
8221 }
8222 }
8223 }
8224 return killed;
8225 }
8226
8227 public void reportPss(IApplicationThread caller, int pss) {
8228 Watchdog.PssRequestor req;
8229 String name;
8230 ProcessRecord callerApp;
8231 synchronized (this) {
8232 if (caller == null) {
8233 return;
8234 }
8235 callerApp = getRecordForAppLocked(caller);
8236 if (callerApp == null) {
8237 return;
8238 }
8239 callerApp.lastPss = pss;
8240 req = callerApp;
8241 name = callerApp.processName;
8242 }
8243 Watchdog.getInstance().reportPss(req, name, pss);
8244 if (!callerApp.persistent) {
8245 removeRequestedPss(callerApp);
8246 }
8247 }
8248
8249 public void requestPss(Runnable completeCallback) {
8250 ArrayList<ProcessRecord> procs;
8251 synchronized (this) {
8252 mRequestPssCallback = completeCallback;
8253 mRequestPssList.clear();
8254 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8255 ProcessRecord proc = mLRUProcesses.get(i);
8256 if (!proc.persistent) {
8257 mRequestPssList.add(proc);
8258 }
8259 }
8260 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8261 }
8262
8263 int oldPri = Process.getThreadPriority(Process.myTid());
8264 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8265 for (int i=procs.size()-1; i>=0; i--) {
8266 ProcessRecord proc = procs.get(i);
8267 proc.lastPss = 0;
8268 proc.requestPss();
8269 }
8270 Process.setThreadPriority(oldPri);
8271 }
8272
8273 void removeRequestedPss(ProcessRecord proc) {
8274 Runnable callback = null;
8275 synchronized (this) {
8276 if (mRequestPssList.remove(proc)) {
8277 if (mRequestPssList.size() == 0) {
8278 callback = mRequestPssCallback;
8279 mRequestPssCallback = null;
8280 }
8281 }
8282 }
8283
8284 if (callback != null) {
8285 callback.run();
8286 }
8287 }
8288
8289 public void collectPss(Watchdog.PssStats stats) {
8290 stats.mEmptyPss = 0;
8291 stats.mEmptyCount = 0;
8292 stats.mBackgroundPss = 0;
8293 stats.mBackgroundCount = 0;
8294 stats.mServicePss = 0;
8295 stats.mServiceCount = 0;
8296 stats.mVisiblePss = 0;
8297 stats.mVisibleCount = 0;
8298 stats.mForegroundPss = 0;
8299 stats.mForegroundCount = 0;
8300 stats.mNoPssCount = 0;
8301 synchronized (this) {
8302 int i;
8303 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8304 ? mProcDeaths.length : stats.mProcDeaths.length;
8305 int aggr = 0;
8306 for (i=0; i<NPD; i++) {
8307 aggr += mProcDeaths[i];
8308 stats.mProcDeaths[i] = aggr;
8309 }
8310 while (i<stats.mProcDeaths.length) {
8311 stats.mProcDeaths[i] = 0;
8312 i++;
8313 }
8314
8315 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8316 ProcessRecord proc = mLRUProcesses.get(i);
8317 if (proc.persistent) {
8318 continue;
8319 }
8320 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8321 if (proc.lastPss == 0) {
8322 stats.mNoPssCount++;
8323 continue;
8324 }
8325 if (proc.setAdj == EMPTY_APP_ADJ) {
8326 stats.mEmptyPss += proc.lastPss;
8327 stats.mEmptyCount++;
8328 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8329 stats.mEmptyPss += proc.lastPss;
8330 stats.mEmptyCount++;
8331 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8332 stats.mBackgroundPss += proc.lastPss;
8333 stats.mBackgroundCount++;
8334 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8335 stats.mVisiblePss += proc.lastPss;
8336 stats.mVisibleCount++;
8337 } else {
8338 stats.mForegroundPss += proc.lastPss;
8339 stats.mForegroundCount++;
8340 }
8341 }
8342 }
8343 }
8344
8345 public final void startRunning(String pkg, String cls, String action,
8346 String data) {
8347 synchronized(this) {
8348 if (mStartRunning) {
8349 return;
8350 }
8351 mStartRunning = true;
8352 mTopComponent = pkg != null && cls != null
8353 ? new ComponentName(pkg, cls) : null;
8354 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8355 mTopData = data;
8356 if (!mSystemReady) {
8357 return;
8358 }
8359 }
8360
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008361 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008362 }
8363
8364 private void retrieveSettings() {
8365 final ContentResolver resolver = mContext.getContentResolver();
8366 String debugApp = Settings.System.getString(
8367 resolver, Settings.System.DEBUG_APP);
8368 boolean waitForDebugger = Settings.System.getInt(
8369 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8370 boolean alwaysFinishActivities = Settings.System.getInt(
8371 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8372
8373 Configuration configuration = new Configuration();
8374 Settings.System.getConfiguration(resolver, configuration);
8375
8376 synchronized (this) {
8377 mDebugApp = mOrigDebugApp = debugApp;
8378 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8379 mAlwaysFinishActivities = alwaysFinishActivities;
8380 // This happens before any activities are started, so we can
8381 // change mConfiguration in-place.
8382 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008383 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008384 }
8385 }
8386
8387 public boolean testIsSystemReady() {
8388 // no need to synchronize(this) just to read & return the value
8389 return mSystemReady;
8390 }
8391
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008392 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008393 // In the simulator, startRunning will never have been called, which
8394 // normally sets a few crucial variables. Do it here instead.
8395 if (!Process.supportsProcesses()) {
8396 mStartRunning = true;
8397 mTopAction = Intent.ACTION_MAIN;
8398 }
8399
8400 synchronized(this) {
8401 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008402 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008403 return;
8404 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008405
8406 // Check to see if there are any update receivers to run.
8407 if (!mDidUpdate) {
8408 if (mWaitingUpdate) {
8409 return;
8410 }
8411 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8412 List<ResolveInfo> ris = null;
8413 try {
8414 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8415 intent, null, 0);
8416 } catch (RemoteException e) {
8417 }
8418 if (ris != null) {
8419 for (int i=ris.size()-1; i>=0; i--) {
8420 if ((ris.get(i).activityInfo.applicationInfo.flags
8421 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8422 ris.remove(i);
8423 }
8424 }
8425 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8426 for (int i=0; i<ris.size(); i++) {
8427 ActivityInfo ai = ris.get(i).activityInfo;
8428 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8429 IIntentReceiver finisher = null;
8430 if (i == 0) {
8431 finisher = new IIntentReceiver.Stub() {
8432 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008433 String data, Bundle extras, boolean ordered,
8434 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008435 throws RemoteException {
8436 synchronized (ActivityManagerService.this) {
8437 mDidUpdate = true;
8438 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008439 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008440 }
8441 };
8442 }
8443 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8444 broadcastIntentLocked(null, null, intent, null, finisher,
8445 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8446 if (i == 0) {
8447 mWaitingUpdate = true;
8448 }
8449 }
8450 }
8451 if (mWaitingUpdate) {
8452 return;
8453 }
8454 mDidUpdate = true;
8455 }
8456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008457 mSystemReady = true;
8458 if (!mStartRunning) {
8459 return;
8460 }
8461 }
8462
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008463 ArrayList<ProcessRecord> procsToKill = null;
8464 synchronized(mPidsSelfLocked) {
8465 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8466 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8467 if (!isAllowedWhileBooting(proc.info)){
8468 if (procsToKill == null) {
8469 procsToKill = new ArrayList<ProcessRecord>();
8470 }
8471 procsToKill.add(proc);
8472 }
8473 }
8474 }
8475
8476 if (procsToKill != null) {
8477 synchronized(this) {
8478 for (int i=procsToKill.size()-1; i>=0; i--) {
8479 ProcessRecord proc = procsToKill.get(i);
8480 Log.i(TAG, "Removing system update proc: " + proc);
8481 removeProcessLocked(proc, true);
8482 }
8483 }
8484 }
8485
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008486 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008487 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8488 SystemClock.uptimeMillis());
8489
8490 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008491 // Make sure we have no pre-ready processes sitting around.
8492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008493 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8494 ResolveInfo ri = mContext.getPackageManager()
8495 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008496 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008497 CharSequence errorMsg = null;
8498 if (ri != null) {
8499 ActivityInfo ai = ri.activityInfo;
8500 ApplicationInfo app = ai.applicationInfo;
8501 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8502 mTopAction = Intent.ACTION_FACTORY_TEST;
8503 mTopData = null;
8504 mTopComponent = new ComponentName(app.packageName,
8505 ai.name);
8506 } else {
8507 errorMsg = mContext.getResources().getText(
8508 com.android.internal.R.string.factorytest_not_system);
8509 }
8510 } else {
8511 errorMsg = mContext.getResources().getText(
8512 com.android.internal.R.string.factorytest_no_action);
8513 }
8514 if (errorMsg != null) {
8515 mTopAction = null;
8516 mTopData = null;
8517 mTopComponent = null;
8518 Message msg = Message.obtain();
8519 msg.what = SHOW_FACTORY_ERROR_MSG;
8520 msg.getData().putCharSequence("msg", errorMsg);
8521 mHandler.sendMessage(msg);
8522 }
8523 }
8524 }
8525
8526 retrieveSettings();
8527
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008528 if (goingCallback != null) goingCallback.run();
8529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008530 synchronized (this) {
8531 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8532 try {
8533 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008534 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008535 if (apps != null) {
8536 int N = apps.size();
8537 int i;
8538 for (i=0; i<N; i++) {
8539 ApplicationInfo info
8540 = (ApplicationInfo)apps.get(i);
8541 if (info != null &&
8542 !info.packageName.equals("android")) {
8543 addAppLocked(info);
8544 }
8545 }
8546 }
8547 } catch (RemoteException ex) {
8548 // pm is in same process, this will never happen.
8549 }
8550 }
8551
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008552 // Start up initial activity.
8553 mBooting = true;
8554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008555 try {
8556 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8557 Message msg = Message.obtain();
8558 msg.what = SHOW_UID_ERROR_MSG;
8559 mHandler.sendMessage(msg);
8560 }
8561 } catch (RemoteException e) {
8562 }
8563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008564 resumeTopActivityLocked(null);
8565 }
8566 }
8567
8568 boolean makeAppCrashingLocked(ProcessRecord app,
8569 String tag, String shortMsg, String longMsg, byte[] crashData) {
8570 app.crashing = true;
8571 app.crashingReport = generateProcessError(app,
8572 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8573 startAppProblemLocked(app);
8574 app.stopFreezingAllLocked();
8575 return handleAppCrashLocked(app);
8576 }
8577
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008578 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008579 // check if error reporting is enabled in Gservices
8580 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8581 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8582 if (enabled == 0) {
8583 return null;
8584 }
8585
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008586 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008587
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008588 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008589 // look for receiver in the installer package
8590 String candidate = pm.getInstallerPackageName(app.info.packageName);
8591 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8592 if (result != null) {
8593 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008594 }
8595
Jacek Surazski82a73df2009-06-17 14:33:18 +02008596 // if the error app is on the system image, look for system apps
8597 // error receiver
8598 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8599 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8600 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8601 if (result != null) {
8602 return result;
8603 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008604 }
8605
Jacek Surazski82a73df2009-06-17 14:33:18 +02008606 // if there is a default receiver, try that
8607 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8608 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008609 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008610 // should not happen
8611 Log.e(TAG, "error talking to PackageManager", e);
8612 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008613 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008614 }
8615
8616 /**
8617 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8618 *
8619 * @param pm PackageManager isntance
8620 * @param errorPackage package which caused the error
8621 * @param receiverPackage candidate package to receive the error
8622 * @return activity component within receiverPackage which handles
8623 * ACTION_APP_ERROR, or null if not found
8624 */
8625 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8626 String receiverPackage) throws RemoteException {
8627 if (receiverPackage == null || receiverPackage.length() == 0) {
8628 return null;
8629 }
8630
8631 // break the loop if it's the error report receiver package that crashed
8632 if (receiverPackage.equals(errorPackage)) {
8633 return null;
8634 }
8635
8636 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8637 intent.setPackage(receiverPackage);
8638 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8639 if (info == null || info.activityInfo == null) {
8640 return null;
8641 }
8642 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008643 }
8644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008645 void makeAppNotRespondingLocked(ProcessRecord app,
8646 String tag, String shortMsg, String longMsg, byte[] crashData) {
8647 app.notResponding = true;
8648 app.notRespondingReport = generateProcessError(app,
8649 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8650 crashData);
8651 startAppProblemLocked(app);
8652 app.stopFreezingAllLocked();
8653 }
8654
8655 /**
8656 * Generate a process error record, suitable for attachment to a ProcessRecord.
8657 *
8658 * @param app The ProcessRecord in which the error occurred.
8659 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8660 * ActivityManager.AppErrorStateInfo
8661 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8662 * @param shortMsg Short message describing the crash.
8663 * @param longMsg Long message describing the crash.
8664 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8665 *
8666 * @return Returns a fully-formed AppErrorStateInfo record.
8667 */
8668 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8669 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8670 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8671
8672 report.condition = condition;
8673 report.processName = app.processName;
8674 report.pid = app.pid;
8675 report.uid = app.info.uid;
8676 report.tag = tag;
8677 report.shortMsg = shortMsg;
8678 report.longMsg = longMsg;
8679 report.crashData = crashData;
8680
8681 return report;
8682 }
8683
8684 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8685 boolean crashed) {
8686 synchronized (this) {
8687 app.crashing = false;
8688 app.crashingReport = null;
8689 app.notResponding = false;
8690 app.notRespondingReport = null;
8691 if (app.anrDialog == fromDialog) {
8692 app.anrDialog = null;
8693 }
8694 if (app.waitDialog == fromDialog) {
8695 app.waitDialog = null;
8696 }
8697 if (app.pid > 0 && app.pid != MY_PID) {
8698 if (crashed) {
8699 handleAppCrashLocked(app);
8700 }
8701 Log.i(ActivityManagerService.TAG, "Killing process "
8702 + app.processName
8703 + " (pid=" + app.pid + ") at user's request");
8704 Process.killProcess(app.pid);
8705 }
8706
8707 }
8708 }
8709
8710 boolean handleAppCrashLocked(ProcessRecord app) {
8711 long now = SystemClock.uptimeMillis();
8712
8713 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8714 app.info.uid);
8715 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8716 // This process loses!
8717 Log.w(TAG, "Process " + app.info.processName
8718 + " has crashed too many times: killing!");
8719 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8720 app.info.processName, app.info.uid);
8721 killServicesLocked(app, false);
8722 for (int i=mHistory.size()-1; i>=0; i--) {
8723 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8724 if (r.app == app) {
8725 if (Config.LOGD) Log.d(
8726 TAG, " Force finishing activity "
8727 + r.intent.getComponent().flattenToShortString());
8728 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8729 }
8730 }
8731 if (!app.persistent) {
8732 // We don't want to start this process again until the user
8733 // explicitly does so... but for persistent process, we really
8734 // need to keep it running. If a persistent process is actually
8735 // repeatedly crashing, then badness for everyone.
8736 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8737 app.info.processName);
8738 mBadProcesses.put(app.info.processName, app.info.uid, now);
8739 app.bad = true;
8740 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8741 app.removed = true;
8742 removeProcessLocked(app, false);
8743 return false;
8744 }
8745 }
8746
8747 // Bump up the crash count of any services currently running in the proc.
8748 if (app.services.size() != 0) {
8749 // Any services running in the application need to be placed
8750 // back in the pending list.
8751 Iterator it = app.services.iterator();
8752 while (it.hasNext()) {
8753 ServiceRecord sr = (ServiceRecord)it.next();
8754 sr.crashCount++;
8755 }
8756 }
8757
8758 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8759 return true;
8760 }
8761
8762 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008763 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008764 skipCurrentReceiverLocked(app);
8765 }
8766
8767 void skipCurrentReceiverLocked(ProcessRecord app) {
8768 boolean reschedule = false;
8769 BroadcastRecord r = app.curReceiver;
8770 if (r != null) {
8771 // The current broadcast is waiting for this app's receiver
8772 // to be finished. Looks like that's not going to happen, so
8773 // let the broadcast continue.
8774 logBroadcastReceiverDiscard(r);
8775 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8776 r.resultExtras, r.resultAbort, true);
8777 reschedule = true;
8778 }
8779 r = mPendingBroadcast;
8780 if (r != null && r.curApp == app) {
8781 if (DEBUG_BROADCAST) Log.v(TAG,
8782 "skip & discard pending app " + r);
8783 logBroadcastReceiverDiscard(r);
8784 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8785 r.resultExtras, r.resultAbort, true);
8786 reschedule = true;
8787 }
8788 if (reschedule) {
8789 scheduleBroadcastsLocked();
8790 }
8791 }
8792
8793 public int handleApplicationError(IBinder app, int flags,
8794 String tag, String shortMsg, String longMsg, byte[] crashData) {
8795 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008796 ProcessRecord r = null;
8797 synchronized (this) {
8798 if (app != null) {
8799 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8800 final int NA = apps.size();
8801 for (int ia=0; ia<NA; ia++) {
8802 ProcessRecord p = apps.valueAt(ia);
8803 if (p.thread != null && p.thread.asBinder() == app) {
8804 r = p;
8805 break;
8806 }
8807 }
8808 }
8809 }
8810
8811 if (r != null) {
8812 // The application has crashed. Send the SIGQUIT to the process so
8813 // that it can dump its state.
8814 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8815 //Log.i(TAG, "Current system threads:");
8816 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8817 }
8818
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008819 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008820 try {
8821 String name = r != null ? r.processName : null;
8822 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008823 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008824 shortMsg, longMsg, crashData)) {
8825 Log.w(TAG, "Force-killing crashed app " + name
8826 + " at watcher's request");
8827 Process.killProcess(pid);
8828 return 0;
8829 }
8830 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008831 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008832 }
8833 }
8834
8835 final long origId = Binder.clearCallingIdentity();
8836
8837 // If this process is running instrumentation, finish it.
8838 if (r != null && r.instrumentationClass != null) {
8839 Log.w(TAG, "Error in app " + r.processName
8840 + " running instrumentation " + r.instrumentationClass + ":");
8841 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8842 if (longMsg != null) Log.w(TAG, " " + longMsg);
8843 Bundle info = new Bundle();
8844 info.putString("shortMsg", shortMsg);
8845 info.putString("longMsg", longMsg);
8846 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8847 Binder.restoreCallingIdentity(origId);
8848 return 0;
8849 }
8850
8851 if (r != null) {
8852 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8853 return 0;
8854 }
8855 } else {
8856 Log.w(TAG, "Some application object " + app + " tag " + tag
8857 + " has crashed, but I don't know who it is.");
8858 Log.w(TAG, "ShortMsg:" + shortMsg);
8859 Log.w(TAG, "LongMsg:" + longMsg);
8860 Binder.restoreCallingIdentity(origId);
8861 return 0;
8862 }
8863
8864 Message msg = Message.obtain();
8865 msg.what = SHOW_ERROR_MSG;
8866 HashMap data = new HashMap();
8867 data.put("result", result);
8868 data.put("app", r);
8869 data.put("flags", flags);
8870 data.put("shortMsg", shortMsg);
8871 data.put("longMsg", longMsg);
8872 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8873 // For system processes, submit crash data to the server.
8874 data.put("crashData", crashData);
8875 }
8876 msg.obj = data;
8877 mHandler.sendMessage(msg);
8878
8879 Binder.restoreCallingIdentity(origId);
8880 }
8881
8882 int res = result.get();
8883
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008884 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008885 synchronized (this) {
8886 if (r != null) {
8887 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8888 SystemClock.uptimeMillis());
8889 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008890 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8891 appErrorIntent = createAppErrorIntentLocked(r);
8892 res = AppErrorDialog.FORCE_QUIT;
8893 }
8894 }
8895
8896 if (appErrorIntent != null) {
8897 try {
8898 mContext.startActivity(appErrorIntent);
8899 } catch (ActivityNotFoundException e) {
8900 Log.w(TAG, "bug report receiver dissappeared", e);
8901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008902 }
8903
8904 return res;
8905 }
8906
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008907 Intent createAppErrorIntentLocked(ProcessRecord r) {
8908 ApplicationErrorReport report = createAppErrorReportLocked(r);
8909 if (report == null) {
8910 return null;
8911 }
8912 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8913 result.setComponent(r.errorReportReceiver);
8914 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8915 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8916 return result;
8917 }
8918
8919 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8920 if (r.errorReportReceiver == null) {
8921 return null;
8922 }
8923
8924 if (!r.crashing && !r.notResponding) {
8925 return null;
8926 }
8927
8928 try {
8929 ApplicationErrorReport report = new ApplicationErrorReport();
8930 report.packageName = r.info.packageName;
8931 report.installerPackageName = r.errorReportReceiver.getPackageName();
8932 report.processName = r.processName;
8933
8934 if (r.crashing) {
8935 report.type = ApplicationErrorReport.TYPE_CRASH;
8936 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8937
8938 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8939 r.crashingReport.crashData);
8940 DataInputStream dataStream = new DataInputStream(byteStream);
8941 CrashData crashData = new CrashData(dataStream);
8942 ThrowableData throwData = crashData.getThrowableData();
8943
8944 report.time = crashData.getTime();
8945 report.crashInfo.stackTrace = throwData.toString();
8946
Jacek Surazskif829a782009-06-11 22:47:02 +02008947 // Extract the source of the exception, useful for report
8948 // clustering. Also extract the "deepest" non-null exception
8949 // message.
8950 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008951 while (throwData.getCause() != null) {
8952 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008953 String msg = throwData.getMessage();
8954 if (msg != null && msg.length() > 0) {
8955 exceptionMessage = msg;
8956 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008957 }
8958 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008959 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008960 report.crashInfo.exceptionClassName = throwData.getType();
8961 report.crashInfo.throwFileName = trace.getFileName();
8962 report.crashInfo.throwClassName = trace.getClassName();
8963 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008964 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008965 } else if (r.notResponding) {
8966 report.type = ApplicationErrorReport.TYPE_ANR;
8967 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8968
8969 report.anrInfo.activity = r.notRespondingReport.tag;
8970 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8971 report.anrInfo.info = r.notRespondingReport.longMsg;
8972 }
8973
8974 return report;
8975 } catch (IOException e) {
8976 // we don't send it
8977 }
8978
8979 return null;
8980 }
8981
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008982 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8983 // assume our apps are happy - lazy create the list
8984 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8985
8986 synchronized (this) {
8987
8988 // iterate across all processes
8989 final int N = mLRUProcesses.size();
8990 for (int i = 0; i < N; i++) {
8991 ProcessRecord app = mLRUProcesses.get(i);
8992 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8993 // This one's in trouble, so we'll generate a report for it
8994 // crashes are higher priority (in case there's a crash *and* an anr)
8995 ActivityManager.ProcessErrorStateInfo report = null;
8996 if (app.crashing) {
8997 report = app.crashingReport;
8998 } else if (app.notResponding) {
8999 report = app.notRespondingReport;
9000 }
9001
9002 if (report != null) {
9003 if (errList == null) {
9004 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9005 }
9006 errList.add(report);
9007 } else {
9008 Log.w(TAG, "Missing app error report, app = " + app.processName +
9009 " crashing = " + app.crashing +
9010 " notResponding = " + app.notResponding);
9011 }
9012 }
9013 }
9014 }
9015
9016 return errList;
9017 }
9018
9019 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9020 // Lazy instantiation of list
9021 List<ActivityManager.RunningAppProcessInfo> runList = null;
9022 synchronized (this) {
9023 // Iterate across all processes
9024 final int N = mLRUProcesses.size();
9025 for (int i = 0; i < N; i++) {
9026 ProcessRecord app = mLRUProcesses.get(i);
9027 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9028 // Generate process state info for running application
9029 ActivityManager.RunningAppProcessInfo currApp =
9030 new ActivityManager.RunningAppProcessInfo(app.processName,
9031 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009032 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009033 int adj = app.curAdj;
9034 if (adj >= CONTENT_PROVIDER_ADJ) {
9035 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9036 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9037 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009038 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9039 } else if (adj >= HOME_APP_ADJ) {
9040 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9041 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009042 } else if (adj >= SECONDARY_SERVER_ADJ) {
9043 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9044 } else if (adj >= VISIBLE_APP_ADJ) {
9045 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9046 } else {
9047 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9048 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009049 currApp.importanceReasonCode = app.adjTypeCode;
9050 if (app.adjSource instanceof ProcessRecord) {
9051 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9052 } else if (app.adjSource instanceof HistoryRecord) {
9053 HistoryRecord r = (HistoryRecord)app.adjSource;
9054 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9055 }
9056 if (app.adjTarget instanceof ComponentName) {
9057 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9058 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009059 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9060 // + " lru=" + currApp.lru);
9061 if (runList == null) {
9062 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9063 }
9064 runList.add(currApp);
9065 }
9066 }
9067 }
9068 return runList;
9069 }
9070
9071 @Override
9072 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9073 synchronized (this) {
9074 if (checkCallingPermission(android.Manifest.permission.DUMP)
9075 != PackageManager.PERMISSION_GRANTED) {
9076 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9077 + Binder.getCallingPid()
9078 + ", uid=" + Binder.getCallingUid()
9079 + " without permission "
9080 + android.Manifest.permission.DUMP);
9081 return;
9082 }
9083 if (args.length != 0 && "service".equals(args[0])) {
9084 dumpService(fd, pw, args);
9085 return;
9086 }
9087 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009088 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009089 pw.println(" ");
9090 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009091 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009092 if (mWaitingVisibleActivities.size() > 0) {
9093 pw.println(" ");
9094 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009095 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009096 }
9097 if (mStoppingActivities.size() > 0) {
9098 pw.println(" ");
9099 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009100 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009101 }
9102 if (mFinishingActivities.size() > 0) {
9103 pw.println(" ");
9104 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009105 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009106 }
9107
9108 pw.println(" ");
9109 pw.println(" mPausingActivity: " + mPausingActivity);
9110 pw.println(" mResumedActivity: " + mResumedActivity);
9111 pw.println(" mFocusedActivity: " + mFocusedActivity);
9112 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9113
9114 if (mRecentTasks.size() > 0) {
9115 pw.println(" ");
9116 pw.println("Recent tasks in Current Activity Manager State:");
9117
9118 final int N = mRecentTasks.size();
9119 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009120 TaskRecord tr = mRecentTasks.get(i);
9121 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9122 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009123 mRecentTasks.get(i).dump(pw, " ");
9124 }
9125 }
9126
9127 pw.println(" ");
9128 pw.println(" mCurTask: " + mCurTask);
9129
9130 pw.println(" ");
9131 pw.println("Processes in Current Activity Manager State:");
9132
9133 boolean needSep = false;
9134 int numPers = 0;
9135
9136 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9137 final int NA = procs.size();
9138 for (int ia=0; ia<NA; ia++) {
9139 if (!needSep) {
9140 pw.println(" All known processes:");
9141 needSep = true;
9142 }
9143 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009144 pw.print(r.persistent ? " *PERS*" : " *APP*");
9145 pw.print(" UID "); pw.print(procs.keyAt(ia));
9146 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009147 r.dump(pw, " ");
9148 if (r.persistent) {
9149 numPers++;
9150 }
9151 }
9152 }
9153
9154 if (mLRUProcesses.size() > 0) {
9155 if (needSep) pw.println(" ");
9156 needSep = true;
9157 pw.println(" Running processes (most recent first):");
9158 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009159 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009160 needSep = true;
9161 }
9162
9163 synchronized (mPidsSelfLocked) {
9164 if (mPidsSelfLocked.size() > 0) {
9165 if (needSep) pw.println(" ");
9166 needSep = true;
9167 pw.println(" PID mappings:");
9168 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009169 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9170 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009171 }
9172 }
9173 }
9174
9175 if (mForegroundProcesses.size() > 0) {
9176 if (needSep) pw.println(" ");
9177 needSep = true;
9178 pw.println(" Foreground Processes:");
9179 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009180 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9181 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009182 }
9183 }
9184
9185 if (mPersistentStartingProcesses.size() > 0) {
9186 if (needSep) pw.println(" ");
9187 needSep = true;
9188 pw.println(" Persisent processes that are starting:");
9189 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009190 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009191 }
9192
9193 if (mStartingProcesses.size() > 0) {
9194 if (needSep) pw.println(" ");
9195 needSep = true;
9196 pw.println(" Processes that are starting:");
9197 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009198 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009199 }
9200
9201 if (mRemovedProcesses.size() > 0) {
9202 if (needSep) pw.println(" ");
9203 needSep = true;
9204 pw.println(" Processes that are being removed:");
9205 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009206 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009207 }
9208
9209 if (mProcessesOnHold.size() > 0) {
9210 if (needSep) pw.println(" ");
9211 needSep = true;
9212 pw.println(" Processes that are on old until the system is ready:");
9213 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009214 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009215 }
9216
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009217 if (mProcessesToGc.size() > 0) {
9218 if (needSep) pw.println(" ");
9219 needSep = true;
9220 pw.println(" Processes that are waiting to GC:");
9221 long now = SystemClock.uptimeMillis();
9222 for (int i=0; i<mProcessesToGc.size(); i++) {
9223 ProcessRecord proc = mProcessesToGc.get(i);
9224 pw.print(" Process "); pw.println(proc);
9225 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9226 pw.print(", last gced=");
9227 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009228 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009229 pw.print(now-proc.lastLowMemory);
9230 pw.println(" ms ago");
9231
9232 }
9233 }
9234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009235 if (mProcessCrashTimes.getMap().size() > 0) {
9236 if (needSep) pw.println(" ");
9237 needSep = true;
9238 pw.println(" Time since processes crashed:");
9239 long now = SystemClock.uptimeMillis();
9240 for (Map.Entry<String, SparseArray<Long>> procs
9241 : mProcessCrashTimes.getMap().entrySet()) {
9242 SparseArray<Long> uids = procs.getValue();
9243 final int N = uids.size();
9244 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009245 pw.print(" Process "); pw.print(procs.getKey());
9246 pw.print(" uid "); pw.print(uids.keyAt(i));
9247 pw.print(": last crashed ");
9248 pw.print((now-uids.valueAt(i)));
9249 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009250 }
9251 }
9252 }
9253
9254 if (mBadProcesses.getMap().size() > 0) {
9255 if (needSep) pw.println(" ");
9256 needSep = true;
9257 pw.println(" Bad processes:");
9258 for (Map.Entry<String, SparseArray<Long>> procs
9259 : mBadProcesses.getMap().entrySet()) {
9260 SparseArray<Long> uids = procs.getValue();
9261 final int N = uids.size();
9262 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009263 pw.print(" Bad process "); pw.print(procs.getKey());
9264 pw.print(" uid "); pw.print(uids.keyAt(i));
9265 pw.print(": crashed at time ");
9266 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009267 }
9268 }
9269 }
9270
9271 pw.println(" ");
9272 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009273 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009274 pw.println(" mConfiguration: " + mConfiguration);
9275 pw.println(" mStartRunning=" + mStartRunning
9276 + " mSystemReady=" + mSystemReady
9277 + " mBooting=" + mBooting
9278 + " mBooted=" + mBooted
9279 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009280 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009281 pw.println(" mGoingToSleep=" + mGoingToSleep);
9282 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9283 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9284 + " mDebugTransient=" + mDebugTransient
9285 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9286 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009287 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009288 }
9289 }
9290
9291 /**
9292 * There are three ways to call this:
9293 * - no service specified: dump all the services
9294 * - a flattened component name that matched an existing service was specified as the
9295 * first arg: dump that one service
9296 * - the first arg isn't the flattened component name of an existing service:
9297 * dump all services whose component contains the first arg as a substring
9298 */
9299 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9300 String[] newArgs;
9301 String componentNameString;
9302 ServiceRecord r;
9303 if (args.length == 1) {
9304 componentNameString = null;
9305 newArgs = EMPTY_STRING_ARRAY;
9306 r = null;
9307 } else {
9308 componentNameString = args[1];
9309 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9310 r = componentName != null ? mServices.get(componentName) : null;
9311 newArgs = new String[args.length - 2];
9312 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9313 }
9314
9315 if (r != null) {
9316 dumpService(fd, pw, r, newArgs);
9317 } else {
9318 for (ServiceRecord r1 : mServices.values()) {
9319 if (componentNameString == null
9320 || r1.name.flattenToString().contains(componentNameString)) {
9321 dumpService(fd, pw, r1, newArgs);
9322 }
9323 }
9324 }
9325 }
9326
9327 /**
9328 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9329 * there is a thread associated with the service.
9330 */
9331 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9332 pw.println(" Service " + r.name.flattenToString());
9333 if (r.app != null && r.app.thread != null) {
9334 try {
9335 // flush anything that is already in the PrintWriter since the thread is going
9336 // to write to the file descriptor directly
9337 pw.flush();
9338 r.app.thread.dumpService(fd, r, args);
9339 pw.print("\n");
9340 } catch (RemoteException e) {
9341 pw.println("got a RemoteException while dumping the service");
9342 }
9343 }
9344 }
9345
9346 void dumpBroadcasts(PrintWriter pw) {
9347 synchronized (this) {
9348 if (checkCallingPermission(android.Manifest.permission.DUMP)
9349 != PackageManager.PERMISSION_GRANTED) {
9350 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9351 + Binder.getCallingPid()
9352 + ", uid=" + Binder.getCallingUid()
9353 + " without permission "
9354 + android.Manifest.permission.DUMP);
9355 return;
9356 }
9357 pw.println("Broadcasts in Current Activity Manager State:");
9358
9359 if (mRegisteredReceivers.size() > 0) {
9360 pw.println(" ");
9361 pw.println(" Registered Receivers:");
9362 Iterator it = mRegisteredReceivers.values().iterator();
9363 while (it.hasNext()) {
9364 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009365 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009366 r.dump(pw, " ");
9367 }
9368 }
9369
9370 pw.println(" ");
9371 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009372 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009373
9374 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9375 || mPendingBroadcast != null) {
9376 if (mParallelBroadcasts.size() > 0) {
9377 pw.println(" ");
9378 pw.println(" Active broadcasts:");
9379 }
9380 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9381 pw.println(" Broadcast #" + i + ":");
9382 mParallelBroadcasts.get(i).dump(pw, " ");
9383 }
9384 if (mOrderedBroadcasts.size() > 0) {
9385 pw.println(" ");
9386 pw.println(" Active serialized broadcasts:");
9387 }
9388 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9389 pw.println(" Serialized Broadcast #" + i + ":");
9390 mOrderedBroadcasts.get(i).dump(pw, " ");
9391 }
9392 pw.println(" ");
9393 pw.println(" Pending broadcast:");
9394 if (mPendingBroadcast != null) {
9395 mPendingBroadcast.dump(pw, " ");
9396 } else {
9397 pw.println(" (null)");
9398 }
9399 }
9400
9401 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009402 pw.println(" Historical broadcasts:");
9403 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9404 BroadcastRecord r = mBroadcastHistory[i];
9405 if (r == null) {
9406 break;
9407 }
9408 pw.println(" Historical Broadcast #" + i + ":");
9409 r.dump(pw, " ");
9410 }
9411
9412 pw.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009413 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9414 if (mStickyBroadcasts != null) {
9415 pw.println(" ");
9416 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009417 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009418 for (Map.Entry<String, ArrayList<Intent>> ent
9419 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009420 pw.print(" * Sticky action "); pw.print(ent.getKey());
9421 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009422 ArrayList<Intent> intents = ent.getValue();
9423 final int N = intents.size();
9424 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009425 sb.setLength(0);
9426 sb.append(" Intent: ");
9427 intents.get(i).toShortString(sb, true, false);
9428 pw.println(sb.toString());
9429 Bundle bundle = intents.get(i).getExtras();
9430 if (bundle != null) {
9431 pw.print(" ");
9432 pw.println(bundle.toString());
9433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009434 }
9435 }
9436 }
9437
9438 pw.println(" ");
9439 pw.println(" mHandler:");
9440 mHandler.dump(new PrintWriterPrinter(pw), " ");
9441 }
9442 }
9443
9444 void dumpServices(PrintWriter pw) {
9445 synchronized (this) {
9446 if (checkCallingPermission(android.Manifest.permission.DUMP)
9447 != PackageManager.PERMISSION_GRANTED) {
9448 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9449 + Binder.getCallingPid()
9450 + ", uid=" + Binder.getCallingUid()
9451 + " without permission "
9452 + android.Manifest.permission.DUMP);
9453 return;
9454 }
9455 pw.println("Services in Current Activity Manager State:");
9456
9457 boolean needSep = false;
9458
9459 if (mServices.size() > 0) {
9460 pw.println(" Active services:");
9461 Iterator<ServiceRecord> it = mServices.values().iterator();
9462 while (it.hasNext()) {
9463 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009464 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009465 r.dump(pw, " ");
9466 }
9467 needSep = true;
9468 }
9469
9470 if (mPendingServices.size() > 0) {
9471 if (needSep) pw.println(" ");
9472 pw.println(" Pending services:");
9473 for (int i=0; i<mPendingServices.size(); i++) {
9474 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009475 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009476 r.dump(pw, " ");
9477 }
9478 needSep = true;
9479 }
9480
9481 if (mRestartingServices.size() > 0) {
9482 if (needSep) pw.println(" ");
9483 pw.println(" Restarting services:");
9484 for (int i=0; i<mRestartingServices.size(); i++) {
9485 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009486 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009487 r.dump(pw, " ");
9488 }
9489 needSep = true;
9490 }
9491
9492 if (mStoppingServices.size() > 0) {
9493 if (needSep) pw.println(" ");
9494 pw.println(" Stopping services:");
9495 for (int i=0; i<mStoppingServices.size(); i++) {
9496 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009497 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009498 r.dump(pw, " ");
9499 }
9500 needSep = true;
9501 }
9502
9503 if (mServiceConnections.size() > 0) {
9504 if (needSep) pw.println(" ");
9505 pw.println(" Connection bindings to services:");
9506 Iterator<ConnectionRecord> it
9507 = mServiceConnections.values().iterator();
9508 while (it.hasNext()) {
9509 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009510 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009511 r.dump(pw, " ");
9512 }
9513 }
9514 }
9515 }
9516
9517 void dumpProviders(PrintWriter pw) {
9518 synchronized (this) {
9519 if (checkCallingPermission(android.Manifest.permission.DUMP)
9520 != PackageManager.PERMISSION_GRANTED) {
9521 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9522 + Binder.getCallingPid()
9523 + ", uid=" + Binder.getCallingUid()
9524 + " without permission "
9525 + android.Manifest.permission.DUMP);
9526 return;
9527 }
9528
9529 pw.println("Content Providers in Current Activity Manager State:");
9530
9531 boolean needSep = false;
9532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009533 if (mProvidersByClass.size() > 0) {
9534 if (needSep) pw.println(" ");
9535 pw.println(" Published content providers (by class):");
9536 Iterator it = mProvidersByClass.entrySet().iterator();
9537 while (it.hasNext()) {
9538 Map.Entry e = (Map.Entry)it.next();
9539 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009540 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009541 r.dump(pw, " ");
9542 }
9543 needSep = true;
9544 }
9545
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009546 if (mProvidersByName.size() > 0) {
9547 pw.println(" ");
9548 pw.println(" Authority to provider mappings:");
9549 Iterator it = mProvidersByName.entrySet().iterator();
9550 while (it.hasNext()) {
9551 Map.Entry e = (Map.Entry)it.next();
9552 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9553 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9554 pw.println(r);
9555 }
9556 needSep = true;
9557 }
9558
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009559 if (mLaunchingProviders.size() > 0) {
9560 if (needSep) pw.println(" ");
9561 pw.println(" Launching content providers:");
9562 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009563 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9564 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009565 }
9566 needSep = true;
9567 }
9568
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009569 if (mGrantedUriPermissions.size() > 0) {
9570 pw.println();
9571 pw.println("Granted Uri Permissions:");
9572 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9573 int uid = mGrantedUriPermissions.keyAt(i);
9574 HashMap<Uri, UriPermission> perms
9575 = mGrantedUriPermissions.valueAt(i);
9576 pw.print(" * UID "); pw.print(uid);
9577 pw.println(" holds:");
9578 for (UriPermission perm : perms.values()) {
9579 pw.print(" "); pw.println(perm);
9580 perm.dump(pw, " ");
9581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009582 }
9583 }
9584 }
9585 }
9586
9587 void dumpSenders(PrintWriter pw) {
9588 synchronized (this) {
9589 if (checkCallingPermission(android.Manifest.permission.DUMP)
9590 != PackageManager.PERMISSION_GRANTED) {
9591 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9592 + Binder.getCallingPid()
9593 + ", uid=" + Binder.getCallingUid()
9594 + " without permission "
9595 + android.Manifest.permission.DUMP);
9596 return;
9597 }
9598
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009599 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009600
9601 if (this.mIntentSenderRecords.size() > 0) {
9602 Iterator<WeakReference<PendingIntentRecord>> it
9603 = mIntentSenderRecords.values().iterator();
9604 while (it.hasNext()) {
9605 WeakReference<PendingIntentRecord> ref = it.next();
9606 PendingIntentRecord rec = ref != null ? ref.get(): null;
9607 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009608 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009609 rec.dump(pw, " ");
9610 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009611 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009612 }
9613 }
9614 }
9615 }
9616 }
9617
9618 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009619 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009620 TaskRecord lastTask = null;
9621 for (int i=list.size()-1; i>=0; i--) {
9622 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009623 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009624 if (lastTask != r.task) {
9625 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009626 pw.print(prefix);
9627 pw.print(full ? "* " : " ");
9628 pw.println(lastTask);
9629 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009630 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009632 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009633 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9634 pw.print(" #"); pw.print(i); pw.print(": ");
9635 pw.println(r);
9636 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009637 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009639 }
9640 }
9641
9642 private static final int dumpProcessList(PrintWriter pw, List list,
9643 String prefix, String normalLabel, String persistentLabel,
9644 boolean inclOomAdj) {
9645 int numPers = 0;
9646 for (int i=list.size()-1; i>=0; i--) {
9647 ProcessRecord r = (ProcessRecord)list.get(i);
9648 if (false) {
9649 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9650 + " #" + i + ":");
9651 r.dump(pw, prefix + " ");
9652 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009653 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009654 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009655 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9656 if (r.adjSource != null || r.adjTarget != null) {
9657 pw.println(prefix + " " + r.adjTarget
9658 + " used by " + r.adjSource);
9659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009660 } else {
9661 pw.println(String.format("%s%s #%2d: %s",
9662 prefix, (r.persistent ? persistentLabel : normalLabel),
9663 i, r.toString()));
9664 }
9665 if (r.persistent) {
9666 numPers++;
9667 }
9668 }
9669 return numPers;
9670 }
9671
9672 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9673 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009674 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009675 long uptime = SystemClock.uptimeMillis();
9676 long realtime = SystemClock.elapsedRealtime();
9677
9678 if (isCheckinRequest) {
9679 // short checkin version
9680 pw.println(uptime + "," + realtime);
9681 pw.flush();
9682 } else {
9683 pw.println("Applications Memory Usage (kB):");
9684 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9685 }
9686 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9687 ProcessRecord r = (ProcessRecord)list.get(i);
9688 if (r.thread != null) {
9689 if (!isCheckinRequest) {
9690 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9691 pw.flush();
9692 }
9693 try {
9694 r.thread.asBinder().dump(fd, args);
9695 } catch (RemoteException e) {
9696 if (!isCheckinRequest) {
9697 pw.println("Got RemoteException!");
9698 pw.flush();
9699 }
9700 }
9701 }
9702 }
9703 }
9704
9705 /**
9706 * Searches array of arguments for the specified string
9707 * @param args array of argument strings
9708 * @param value value to search for
9709 * @return true if the value is contained in the array
9710 */
9711 private static boolean scanArgs(String[] args, String value) {
9712 if (args != null) {
9713 for (String arg : args) {
9714 if (value.equals(arg)) {
9715 return true;
9716 }
9717 }
9718 }
9719 return false;
9720 }
9721
Dianne Hackborn75b03852009-06-12 15:43:26 -07009722 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009723 int count = mHistory.size();
9724
9725 // convert the token to an entry in the history.
9726 HistoryRecord r = null;
9727 int index = -1;
9728 for (int i=count-1; i>=0; i--) {
9729 Object o = mHistory.get(i);
9730 if (o == token) {
9731 r = (HistoryRecord)o;
9732 index = i;
9733 break;
9734 }
9735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009736
9737 return index;
9738 }
9739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009740 private final void killServicesLocked(ProcessRecord app,
9741 boolean allowRestart) {
9742 // Report disconnected services.
9743 if (false) {
9744 // XXX we are letting the client link to the service for
9745 // death notifications.
9746 if (app.services.size() > 0) {
9747 Iterator it = app.services.iterator();
9748 while (it.hasNext()) {
9749 ServiceRecord r = (ServiceRecord)it.next();
9750 if (r.connections.size() > 0) {
9751 Iterator<ConnectionRecord> jt
9752 = r.connections.values().iterator();
9753 while (jt.hasNext()) {
9754 ConnectionRecord c = jt.next();
9755 if (c.binding.client != app) {
9756 try {
9757 //c.conn.connected(r.className, null);
9758 } catch (Exception e) {
9759 // todo: this should be asynchronous!
9760 Log.w(TAG, "Exception thrown disconnected servce "
9761 + r.shortName
9762 + " from app " + app.processName, e);
9763 }
9764 }
9765 }
9766 }
9767 }
9768 }
9769 }
9770
9771 // Clean up any connections this application has to other services.
9772 if (app.connections.size() > 0) {
9773 Iterator<ConnectionRecord> it = app.connections.iterator();
9774 while (it.hasNext()) {
9775 ConnectionRecord r = it.next();
9776 removeConnectionLocked(r, app, null);
9777 }
9778 }
9779 app.connections.clear();
9780
9781 if (app.services.size() != 0) {
9782 // Any services running in the application need to be placed
9783 // back in the pending list.
9784 Iterator it = app.services.iterator();
9785 while (it.hasNext()) {
9786 ServiceRecord sr = (ServiceRecord)it.next();
9787 synchronized (sr.stats.getBatteryStats()) {
9788 sr.stats.stopLaunchedLocked();
9789 }
9790 sr.app = null;
9791 sr.executeNesting = 0;
9792 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009793
9794 boolean hasClients = sr.bindings.size() > 0;
9795 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009796 Iterator<IntentBindRecord> bindings
9797 = sr.bindings.values().iterator();
9798 while (bindings.hasNext()) {
9799 IntentBindRecord b = bindings.next();
9800 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9801 + ": shouldUnbind=" + b.hasBound);
9802 b.binder = null;
9803 b.requested = b.received = b.hasBound = false;
9804 }
9805 }
9806
9807 if (sr.crashCount >= 2) {
9808 Log.w(TAG, "Service crashed " + sr.crashCount
9809 + " times, stopping: " + sr);
9810 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9811 sr.crashCount, sr.shortName, app.pid);
9812 bringDownServiceLocked(sr, true);
9813 } else if (!allowRestart) {
9814 bringDownServiceLocked(sr, true);
9815 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009816 boolean canceled = scheduleServiceRestartLocked(sr, true);
9817
9818 // Should the service remain running? Note that in the
9819 // extreme case of so many attempts to deliver a command
9820 // that it failed, that we also will stop it here.
9821 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9822 if (sr.pendingStarts.size() == 0) {
9823 sr.startRequested = false;
9824 if (!hasClients) {
9825 // Whoops, no reason to restart!
9826 bringDownServiceLocked(sr, true);
9827 }
9828 }
9829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009830 }
9831 }
9832
9833 if (!allowRestart) {
9834 app.services.clear();
9835 }
9836 }
9837
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009838 // Make sure we have no more records on the stopping list.
9839 int i = mStoppingServices.size();
9840 while (i > 0) {
9841 i--;
9842 ServiceRecord sr = mStoppingServices.get(i);
9843 if (sr.app == app) {
9844 mStoppingServices.remove(i);
9845 }
9846 }
9847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009848 app.executingServices.clear();
9849 }
9850
9851 private final void removeDyingProviderLocked(ProcessRecord proc,
9852 ContentProviderRecord cpr) {
9853 synchronized (cpr) {
9854 cpr.launchingApp = null;
9855 cpr.notifyAll();
9856 }
9857
9858 mProvidersByClass.remove(cpr.info.name);
9859 String names[] = cpr.info.authority.split(";");
9860 for (int j = 0; j < names.length; j++) {
9861 mProvidersByName.remove(names[j]);
9862 }
9863
9864 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9865 while (cit.hasNext()) {
9866 ProcessRecord capp = cit.next();
9867 if (!capp.persistent && capp.thread != null
9868 && capp.pid != 0
9869 && capp.pid != MY_PID) {
9870 Log.i(TAG, "Killing app " + capp.processName
9871 + " (pid " + capp.pid
9872 + ") because provider " + cpr.info.name
9873 + " is in dying process " + proc.processName);
9874 Process.killProcess(capp.pid);
9875 }
9876 }
9877
9878 mLaunchingProviders.remove(cpr);
9879 }
9880
9881 /**
9882 * Main code for cleaning up a process when it has gone away. This is
9883 * called both as a result of the process dying, or directly when stopping
9884 * a process when running in single process mode.
9885 */
9886 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9887 boolean restarting, int index) {
9888 if (index >= 0) {
9889 mLRUProcesses.remove(index);
9890 }
9891
Dianne Hackborn36124872009-10-08 16:22:03 -07009892 mProcessesToGc.remove(app);
9893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009894 // Dismiss any open dialogs.
9895 if (app.crashDialog != null) {
9896 app.crashDialog.dismiss();
9897 app.crashDialog = null;
9898 }
9899 if (app.anrDialog != null) {
9900 app.anrDialog.dismiss();
9901 app.anrDialog = null;
9902 }
9903 if (app.waitDialog != null) {
9904 app.waitDialog.dismiss();
9905 app.waitDialog = null;
9906 }
9907
9908 app.crashing = false;
9909 app.notResponding = false;
9910
9911 app.resetPackageList();
9912 app.thread = null;
9913 app.forcingToForeground = null;
9914 app.foregroundServices = false;
9915
9916 killServicesLocked(app, true);
9917
9918 boolean restart = false;
9919
9920 int NL = mLaunchingProviders.size();
9921
9922 // Remove published content providers.
9923 if (!app.pubProviders.isEmpty()) {
9924 Iterator it = app.pubProviders.values().iterator();
9925 while (it.hasNext()) {
9926 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9927 cpr.provider = null;
9928 cpr.app = null;
9929
9930 // See if someone is waiting for this provider... in which
9931 // case we don't remove it, but just let it restart.
9932 int i = 0;
9933 if (!app.bad) {
9934 for (; i<NL; i++) {
9935 if (mLaunchingProviders.get(i) == cpr) {
9936 restart = true;
9937 break;
9938 }
9939 }
9940 } else {
9941 i = NL;
9942 }
9943
9944 if (i >= NL) {
9945 removeDyingProviderLocked(app, cpr);
9946 NL = mLaunchingProviders.size();
9947 }
9948 }
9949 app.pubProviders.clear();
9950 }
9951
9952 // Look through the content providers we are waiting to have launched,
9953 // and if any run in this process then either schedule a restart of
9954 // the process or kill the client waiting for it if this process has
9955 // gone bad.
9956 for (int i=0; i<NL; i++) {
9957 ContentProviderRecord cpr = (ContentProviderRecord)
9958 mLaunchingProviders.get(i);
9959 if (cpr.launchingApp == app) {
9960 if (!app.bad) {
9961 restart = true;
9962 } else {
9963 removeDyingProviderLocked(app, cpr);
9964 NL = mLaunchingProviders.size();
9965 }
9966 }
9967 }
9968
9969 // Unregister from connected content providers.
9970 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07009971 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009972 while (it.hasNext()) {
9973 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9974 cpr.clients.remove(app);
9975 }
9976 app.conProviders.clear();
9977 }
9978
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009979 // At this point there may be remaining entries in mLaunchingProviders
9980 // where we were the only one waiting, so they are no longer of use.
9981 // Look for these and clean up if found.
9982 // XXX Commented out for now. Trying to figure out a way to reproduce
9983 // the actual situation to identify what is actually going on.
9984 if (false) {
9985 for (int i=0; i<NL; i++) {
9986 ContentProviderRecord cpr = (ContentProviderRecord)
9987 mLaunchingProviders.get(i);
9988 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9989 synchronized (cpr) {
9990 cpr.launchingApp = null;
9991 cpr.notifyAll();
9992 }
9993 }
9994 }
9995 }
9996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009997 skipCurrentReceiverLocked(app);
9998
9999 // Unregister any receivers.
10000 if (app.receivers.size() > 0) {
10001 Iterator<ReceiverList> it = app.receivers.iterator();
10002 while (it.hasNext()) {
10003 removeReceiverLocked(it.next());
10004 }
10005 app.receivers.clear();
10006 }
10007
Christopher Tate181fafa2009-05-14 11:12:14 -070010008 // If the app is undergoing backup, tell the backup manager about it
10009 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10010 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10011 try {
10012 IBackupManager bm = IBackupManager.Stub.asInterface(
10013 ServiceManager.getService(Context.BACKUP_SERVICE));
10014 bm.agentDisconnected(app.info.packageName);
10015 } catch (RemoteException e) {
10016 // can't happen; backup manager is local
10017 }
10018 }
10019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010020 // If the caller is restarting this app, then leave it in its
10021 // current lists and let the caller take care of it.
10022 if (restarting) {
10023 return;
10024 }
10025
10026 if (!app.persistent) {
10027 if (DEBUG_PROCESSES) Log.v(TAG,
10028 "Removing non-persistent process during cleanup: " + app);
10029 mProcessNames.remove(app.processName, app.info.uid);
10030 } else if (!app.removed) {
10031 // This app is persistent, so we need to keep its record around.
10032 // If it is not already on the pending app list, add it there
10033 // and start a new process for it.
10034 app.thread = null;
10035 app.forcingToForeground = null;
10036 app.foregroundServices = false;
10037 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10038 mPersistentStartingProcesses.add(app);
10039 restart = true;
10040 }
10041 }
10042 mProcessesOnHold.remove(app);
10043
The Android Open Source Project4df24232009-03-05 14:34:35 -080010044 if (app == mHomeProcess) {
10045 mHomeProcess = null;
10046 }
10047
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010048 if (restart) {
10049 // We have components that still need to be running in the
10050 // process, so re-launch it.
10051 mProcessNames.put(app.processName, app.info.uid, app);
10052 startProcessLocked(app, "restart", app.processName);
10053 } else if (app.pid > 0 && app.pid != MY_PID) {
10054 // Goodbye!
10055 synchronized (mPidsSelfLocked) {
10056 mPidsSelfLocked.remove(app.pid);
10057 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10058 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010059 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010060 }
10061 }
10062
10063 // =========================================================
10064 // SERVICES
10065 // =========================================================
10066
10067 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10068 ActivityManager.RunningServiceInfo info =
10069 new ActivityManager.RunningServiceInfo();
10070 info.service = r.name;
10071 if (r.app != null) {
10072 info.pid = r.app.pid;
10073 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010074 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010075 info.process = r.processName;
10076 info.foreground = r.isForeground;
10077 info.activeSince = r.createTime;
10078 info.started = r.startRequested;
10079 info.clientCount = r.connections.size();
10080 info.crashCount = r.crashCount;
10081 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010082 if (r.isForeground) {
10083 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10084 }
10085 if (r.startRequested) {
10086 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10087 }
10088 if (r.app != null && r.app.pid == Process.myPid()) {
10089 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10090 }
10091 if (r.app != null && r.app.persistent) {
10092 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10093 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010094 for (ConnectionRecord conn : r.connections.values()) {
10095 if (conn.clientLabel != 0) {
10096 info.clientPackage = conn.binding.client.info.packageName;
10097 info.clientLabel = conn.clientLabel;
10098 break;
10099 }
10100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010101 return info;
10102 }
10103
10104 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10105 int flags) {
10106 synchronized (this) {
10107 ArrayList<ActivityManager.RunningServiceInfo> res
10108 = new ArrayList<ActivityManager.RunningServiceInfo>();
10109
10110 if (mServices.size() > 0) {
10111 Iterator<ServiceRecord> it = mServices.values().iterator();
10112 while (it.hasNext() && res.size() < maxNum) {
10113 res.add(makeRunningServiceInfoLocked(it.next()));
10114 }
10115 }
10116
10117 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10118 ServiceRecord r = mRestartingServices.get(i);
10119 ActivityManager.RunningServiceInfo info =
10120 makeRunningServiceInfoLocked(r);
10121 info.restarting = r.nextRestartTime;
10122 res.add(info);
10123 }
10124
10125 return res;
10126 }
10127 }
10128
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010129 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10130 synchronized (this) {
10131 ServiceRecord r = mServices.get(name);
10132 if (r != null) {
10133 for (ConnectionRecord conn : r.connections.values()) {
10134 if (conn.clientIntent != null) {
10135 return conn.clientIntent;
10136 }
10137 }
10138 }
10139 }
10140 return null;
10141 }
10142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010143 private final ServiceRecord findServiceLocked(ComponentName name,
10144 IBinder token) {
10145 ServiceRecord r = mServices.get(name);
10146 return r == token ? r : null;
10147 }
10148
10149 private final class ServiceLookupResult {
10150 final ServiceRecord record;
10151 final String permission;
10152
10153 ServiceLookupResult(ServiceRecord _record, String _permission) {
10154 record = _record;
10155 permission = _permission;
10156 }
10157 };
10158
10159 private ServiceLookupResult findServiceLocked(Intent service,
10160 String resolvedType) {
10161 ServiceRecord r = null;
10162 if (service.getComponent() != null) {
10163 r = mServices.get(service.getComponent());
10164 }
10165 if (r == null) {
10166 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10167 r = mServicesByIntent.get(filter);
10168 }
10169
10170 if (r == null) {
10171 try {
10172 ResolveInfo rInfo =
10173 ActivityThread.getPackageManager().resolveService(
10174 service, resolvedType, 0);
10175 ServiceInfo sInfo =
10176 rInfo != null ? rInfo.serviceInfo : null;
10177 if (sInfo == null) {
10178 return null;
10179 }
10180
10181 ComponentName name = new ComponentName(
10182 sInfo.applicationInfo.packageName, sInfo.name);
10183 r = mServices.get(name);
10184 } catch (RemoteException ex) {
10185 // pm is in same process, this will never happen.
10186 }
10187 }
10188 if (r != null) {
10189 int callingPid = Binder.getCallingPid();
10190 int callingUid = Binder.getCallingUid();
10191 if (checkComponentPermission(r.permission,
10192 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10193 != PackageManager.PERMISSION_GRANTED) {
10194 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10195 + " from pid=" + callingPid
10196 + ", uid=" + callingUid
10197 + " requires " + r.permission);
10198 return new ServiceLookupResult(null, r.permission);
10199 }
10200 return new ServiceLookupResult(r, null);
10201 }
10202 return null;
10203 }
10204
10205 private class ServiceRestarter implements Runnable {
10206 private ServiceRecord mService;
10207
10208 void setService(ServiceRecord service) {
10209 mService = service;
10210 }
10211
10212 public void run() {
10213 synchronized(ActivityManagerService.this) {
10214 performServiceRestartLocked(mService);
10215 }
10216 }
10217 }
10218
10219 private ServiceLookupResult retrieveServiceLocked(Intent service,
10220 String resolvedType, int callingPid, int callingUid) {
10221 ServiceRecord r = null;
10222 if (service.getComponent() != null) {
10223 r = mServices.get(service.getComponent());
10224 }
10225 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10226 r = mServicesByIntent.get(filter);
10227 if (r == null) {
10228 try {
10229 ResolveInfo rInfo =
10230 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010231 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010232 ServiceInfo sInfo =
10233 rInfo != null ? rInfo.serviceInfo : null;
10234 if (sInfo == null) {
10235 Log.w(TAG, "Unable to start service " + service +
10236 ": not found");
10237 return null;
10238 }
10239
10240 ComponentName name = new ComponentName(
10241 sInfo.applicationInfo.packageName, sInfo.name);
10242 r = mServices.get(name);
10243 if (r == null) {
10244 filter = new Intent.FilterComparison(service.cloneFilter());
10245 ServiceRestarter res = new ServiceRestarter();
10246 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10247 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10248 synchronized (stats) {
10249 ss = stats.getServiceStatsLocked(
10250 sInfo.applicationInfo.uid, sInfo.packageName,
10251 sInfo.name);
10252 }
10253 r = new ServiceRecord(ss, name, filter, sInfo, res);
10254 res.setService(r);
10255 mServices.put(name, r);
10256 mServicesByIntent.put(filter, r);
10257
10258 // Make sure this component isn't in the pending list.
10259 int N = mPendingServices.size();
10260 for (int i=0; i<N; i++) {
10261 ServiceRecord pr = mPendingServices.get(i);
10262 if (pr.name.equals(name)) {
10263 mPendingServices.remove(i);
10264 i--;
10265 N--;
10266 }
10267 }
10268 }
10269 } catch (RemoteException ex) {
10270 // pm is in same process, this will never happen.
10271 }
10272 }
10273 if (r != null) {
10274 if (checkComponentPermission(r.permission,
10275 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10276 != PackageManager.PERMISSION_GRANTED) {
10277 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10278 + " from pid=" + Binder.getCallingPid()
10279 + ", uid=" + Binder.getCallingUid()
10280 + " requires " + r.permission);
10281 return new ServiceLookupResult(null, r.permission);
10282 }
10283 return new ServiceLookupResult(r, null);
10284 }
10285 return null;
10286 }
10287
10288 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10289 long now = SystemClock.uptimeMillis();
10290 if (r.executeNesting == 0 && r.app != null) {
10291 if (r.app.executingServices.size() == 0) {
10292 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10293 msg.obj = r.app;
10294 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10295 }
10296 r.app.executingServices.add(r);
10297 }
10298 r.executeNesting++;
10299 r.executingStart = now;
10300 }
10301
10302 private final void sendServiceArgsLocked(ServiceRecord r,
10303 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010304 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010305 if (N == 0) {
10306 return;
10307 }
10308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010309 int i = 0;
10310 while (i < N) {
10311 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010312 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010313 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010314 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010315 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010316 // If somehow we got a dummy start at the front, then
10317 // just drop it here.
10318 i++;
10319 continue;
10320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010321 bumpServiceExecutingLocked(r);
10322 if (!oomAdjusted) {
10323 oomAdjusted = true;
10324 updateOomAdjLocked(r.app);
10325 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010326 int flags = 0;
10327 if (si.deliveryCount > 0) {
10328 flags |= Service.START_FLAG_RETRY;
10329 }
10330 if (si.doneExecutingCount > 0) {
10331 flags |= Service.START_FLAG_REDELIVERY;
10332 }
10333 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10334 si.deliveredTime = SystemClock.uptimeMillis();
10335 r.deliveredStarts.add(si);
10336 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010337 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010338 } catch (RemoteException e) {
10339 // Remote process gone... we'll let the normal cleanup take
10340 // care of this.
10341 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010342 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010343 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010344 break;
10345 }
10346 }
10347 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010348 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010349 } else {
10350 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010351 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010352 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010353 }
10354 }
10355 }
10356
10357 private final boolean requestServiceBindingLocked(ServiceRecord r,
10358 IntentBindRecord i, boolean rebind) {
10359 if (r.app == null || r.app.thread == null) {
10360 // If service is not currently running, can't yet bind.
10361 return false;
10362 }
10363 if ((!i.requested || rebind) && i.apps.size() > 0) {
10364 try {
10365 bumpServiceExecutingLocked(r);
10366 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10367 + ": shouldUnbind=" + i.hasBound);
10368 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10369 if (!rebind) {
10370 i.requested = true;
10371 }
10372 i.hasBound = true;
10373 i.doRebind = false;
10374 } catch (RemoteException e) {
10375 return false;
10376 }
10377 }
10378 return true;
10379 }
10380
10381 private final void requestServiceBindingsLocked(ServiceRecord r) {
10382 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10383 while (bindings.hasNext()) {
10384 IntentBindRecord i = bindings.next();
10385 if (!requestServiceBindingLocked(r, i, false)) {
10386 break;
10387 }
10388 }
10389 }
10390
10391 private final void realStartServiceLocked(ServiceRecord r,
10392 ProcessRecord app) throws RemoteException {
10393 if (app.thread == null) {
10394 throw new RemoteException();
10395 }
10396
10397 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010398 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010399
10400 app.services.add(r);
10401 bumpServiceExecutingLocked(r);
10402 updateLRUListLocked(app, true);
10403
10404 boolean created = false;
10405 try {
10406 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10407 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010408 mStringBuilder.setLength(0);
10409 r.intent.getIntent().toShortString(mStringBuilder, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010410 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10411 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010412 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010413 synchronized (r.stats.getBatteryStats()) {
10414 r.stats.startLaunchedLocked();
10415 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010416 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010417 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010418 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010419 created = true;
10420 } finally {
10421 if (!created) {
10422 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010423 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010424 }
10425 }
10426
10427 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010428
10429 // If the service is in the started state, and there are no
10430 // pending arguments, then fake up one so its onStartCommand() will
10431 // be called.
10432 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10433 r.lastStartId++;
10434 if (r.lastStartId < 1) {
10435 r.lastStartId = 1;
10436 }
10437 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10438 }
10439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010440 sendServiceArgsLocked(r, true);
10441 }
10442
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010443 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10444 boolean allowCancel) {
10445 boolean canceled = false;
10446
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010447 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010448 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010449 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010450
10451 // Any delivered but not yet finished starts should be put back
10452 // on the pending list.
10453 final int N = r.deliveredStarts.size();
10454 if (N > 0) {
10455 for (int i=N-1; i>=0; i--) {
10456 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10457 if (si.intent == null) {
10458 // We'll generate this again if needed.
10459 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10460 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10461 r.pendingStarts.add(0, si);
10462 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10463 dur *= 2;
10464 if (minDuration < dur) minDuration = dur;
10465 if (resetTime < dur) resetTime = dur;
10466 } else {
10467 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10468 + r.name);
10469 canceled = true;
10470 }
10471 }
10472 r.deliveredStarts.clear();
10473 }
10474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010475 r.totalRestartCount++;
10476 if (r.restartDelay == 0) {
10477 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010478 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010479 } else {
10480 // If it has been a "reasonably long time" since the service
10481 // was started, then reset our restart duration back to
10482 // the beginning, so we don't infinitely increase the duration
10483 // on a service that just occasionally gets killed (which is
10484 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010485 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010486 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010487 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010488 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010489 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010490 if (r.restartDelay < minDuration) {
10491 r.restartDelay = minDuration;
10492 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010493 }
10494 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010495
10496 r.nextRestartTime = now + r.restartDelay;
10497
10498 // Make sure that we don't end up restarting a bunch of services
10499 // all at the same time.
10500 boolean repeat;
10501 do {
10502 repeat = false;
10503 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10504 ServiceRecord r2 = mRestartingServices.get(i);
10505 if (r2 != r && r.nextRestartTime
10506 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10507 && r.nextRestartTime
10508 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10509 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10510 r.restartDelay = r.nextRestartTime - now;
10511 repeat = true;
10512 break;
10513 }
10514 }
10515 } while (repeat);
10516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010517 if (!mRestartingServices.contains(r)) {
10518 mRestartingServices.add(r);
10519 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010520
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010521 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010523 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010524 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010525 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10526 Log.w(TAG, "Scheduling restart of crashed service "
10527 + r.shortName + " in " + r.restartDelay + "ms");
10528 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10529 r.shortName, r.restartDelay);
10530
10531 Message msg = Message.obtain();
10532 msg.what = SERVICE_ERROR_MSG;
10533 msg.obj = r;
10534 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010535
10536 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010537 }
10538
10539 final void performServiceRestartLocked(ServiceRecord r) {
10540 if (!mRestartingServices.contains(r)) {
10541 return;
10542 }
10543 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10544 }
10545
10546 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10547 if (r.restartDelay == 0) {
10548 return false;
10549 }
10550 r.resetRestartCounter();
10551 mRestartingServices.remove(r);
10552 mHandler.removeCallbacks(r.restarter);
10553 return true;
10554 }
10555
10556 private final boolean bringUpServiceLocked(ServiceRecord r,
10557 int intentFlags, boolean whileRestarting) {
10558 //Log.i(TAG, "Bring up service:");
10559 //r.dump(" ");
10560
Dianne Hackborn36124872009-10-08 16:22:03 -070010561 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010562 sendServiceArgsLocked(r, false);
10563 return true;
10564 }
10565
10566 if (!whileRestarting && r.restartDelay > 0) {
10567 // If waiting for a restart, then do nothing.
10568 return true;
10569 }
10570
10571 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10572 + " " + r.intent);
10573
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010574 // We are now bringing the service up, so no longer in the
10575 // restarting state.
10576 mRestartingServices.remove(r);
10577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010578 final String appName = r.processName;
10579 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10580 if (app != null && app.thread != null) {
10581 try {
10582 realStartServiceLocked(r, app);
10583 return true;
10584 } catch (RemoteException e) {
10585 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10586 }
10587
10588 // If a dead object exception was thrown -- fall through to
10589 // restart the application.
10590 }
10591
Dianne Hackborn36124872009-10-08 16:22:03 -070010592 // Not running -- get it started, and enqueue this service record
10593 // to be executed when the app comes up.
10594 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10595 "service", r.name, false) == null) {
10596 Log.w(TAG, "Unable to launch app "
10597 + r.appInfo.packageName + "/"
10598 + r.appInfo.uid + " for service "
10599 + r.intent.getIntent() + ": process is bad");
10600 bringDownServiceLocked(r, true);
10601 return false;
10602 }
10603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010604 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010605 mPendingServices.add(r);
10606 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010608 return true;
10609 }
10610
10611 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10612 //Log.i(TAG, "Bring down service:");
10613 //r.dump(" ");
10614
10615 // Does it still need to run?
10616 if (!force && r.startRequested) {
10617 return;
10618 }
10619 if (r.connections.size() > 0) {
10620 if (!force) {
10621 // XXX should probably keep a count of the number of auto-create
10622 // connections directly in the service.
10623 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10624 while (it.hasNext()) {
10625 ConnectionRecord cr = it.next();
10626 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10627 return;
10628 }
10629 }
10630 }
10631
10632 // Report to all of the connections that the service is no longer
10633 // available.
10634 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10635 while (it.hasNext()) {
10636 ConnectionRecord c = it.next();
10637 try {
10638 // todo: shouldn't be a synchronous call!
10639 c.conn.connected(r.name, null);
10640 } catch (Exception e) {
10641 Log.w(TAG, "Failure disconnecting service " + r.name +
10642 " to connection " + c.conn.asBinder() +
10643 " (in " + c.binding.client.processName + ")", e);
10644 }
10645 }
10646 }
10647
10648 // Tell the service that it has been unbound.
10649 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10650 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10651 while (it.hasNext()) {
10652 IntentBindRecord ibr = it.next();
10653 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10654 + ": hasBound=" + ibr.hasBound);
10655 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10656 try {
10657 bumpServiceExecutingLocked(r);
10658 updateOomAdjLocked(r.app);
10659 ibr.hasBound = false;
10660 r.app.thread.scheduleUnbindService(r,
10661 ibr.intent.getIntent());
10662 } catch (Exception e) {
10663 Log.w(TAG, "Exception when unbinding service "
10664 + r.shortName, e);
10665 serviceDoneExecutingLocked(r, true);
10666 }
10667 }
10668 }
10669 }
10670
10671 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10672 + " " + r.intent);
10673 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10674 System.identityHashCode(r), r.shortName,
10675 (r.app != null) ? r.app.pid : -1);
10676
10677 mServices.remove(r.name);
10678 mServicesByIntent.remove(r.intent);
10679 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10680 r.totalRestartCount = 0;
10681 unscheduleServiceRestartLocked(r);
10682
10683 // Also make sure it is not on the pending list.
10684 int N = mPendingServices.size();
10685 for (int i=0; i<N; i++) {
10686 if (mPendingServices.get(i) == r) {
10687 mPendingServices.remove(i);
10688 if (DEBUG_SERVICE) Log.v(
10689 TAG, "Removed pending service: " + r.shortName);
10690 i--;
10691 N--;
10692 }
10693 }
10694
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010695 r.cancelNotification();
10696 r.isForeground = false;
10697 r.foregroundId = 0;
10698 r.foregroundNoti = null;
10699
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010700 // Clear start entries.
10701 r.deliveredStarts.clear();
10702 r.pendingStarts.clear();
10703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010704 if (r.app != null) {
10705 synchronized (r.stats.getBatteryStats()) {
10706 r.stats.stopLaunchedLocked();
10707 }
10708 r.app.services.remove(r);
10709 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010710 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010711 if (DEBUG_SERVICE) Log.v(TAG,
10712 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010713 bumpServiceExecutingLocked(r);
10714 mStoppingServices.add(r);
10715 updateOomAdjLocked(r.app);
10716 r.app.thread.scheduleStopService(r);
10717 } catch (Exception e) {
10718 Log.w(TAG, "Exception when stopping service "
10719 + r.shortName, e);
10720 serviceDoneExecutingLocked(r, true);
10721 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010722 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010723 } else {
10724 if (DEBUG_SERVICE) Log.v(
10725 TAG, "Removed service that has no process: " + r.shortName);
10726 }
10727 } else {
10728 if (DEBUG_SERVICE) Log.v(
10729 TAG, "Removed service that is not running: " + r.shortName);
10730 }
10731 }
10732
10733 ComponentName startServiceLocked(IApplicationThread caller,
10734 Intent service, String resolvedType,
10735 int callingPid, int callingUid) {
10736 synchronized(this) {
10737 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10738 + " type=" + resolvedType + " args=" + service.getExtras());
10739
10740 if (caller != null) {
10741 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10742 if (callerApp == null) {
10743 throw new SecurityException(
10744 "Unable to find app for caller " + caller
10745 + " (pid=" + Binder.getCallingPid()
10746 + ") when starting service " + service);
10747 }
10748 }
10749
10750 ServiceLookupResult res =
10751 retrieveServiceLocked(service, resolvedType,
10752 callingPid, callingUid);
10753 if (res == null) {
10754 return null;
10755 }
10756 if (res.record == null) {
10757 return new ComponentName("!", res.permission != null
10758 ? res.permission : "private to package");
10759 }
10760 ServiceRecord r = res.record;
10761 if (unscheduleServiceRestartLocked(r)) {
10762 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10763 + r.shortName);
10764 }
10765 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010766 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010767 r.lastStartId++;
10768 if (r.lastStartId < 1) {
10769 r.lastStartId = 1;
10770 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010771 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010772 r.lastActivity = SystemClock.uptimeMillis();
10773 synchronized (r.stats.getBatteryStats()) {
10774 r.stats.startRunningLocked();
10775 }
10776 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10777 return new ComponentName("!", "Service process is bad");
10778 }
10779 return r.name;
10780 }
10781 }
10782
10783 public ComponentName startService(IApplicationThread caller, Intent service,
10784 String resolvedType) {
10785 // Refuse possible leaked file descriptors
10786 if (service != null && service.hasFileDescriptors() == true) {
10787 throw new IllegalArgumentException("File descriptors passed in Intent");
10788 }
10789
10790 synchronized(this) {
10791 final int callingPid = Binder.getCallingPid();
10792 final int callingUid = Binder.getCallingUid();
10793 final long origId = Binder.clearCallingIdentity();
10794 ComponentName res = startServiceLocked(caller, service,
10795 resolvedType, callingPid, callingUid);
10796 Binder.restoreCallingIdentity(origId);
10797 return res;
10798 }
10799 }
10800
10801 ComponentName startServiceInPackage(int uid,
10802 Intent service, String resolvedType) {
10803 synchronized(this) {
10804 final long origId = Binder.clearCallingIdentity();
10805 ComponentName res = startServiceLocked(null, service,
10806 resolvedType, -1, uid);
10807 Binder.restoreCallingIdentity(origId);
10808 return res;
10809 }
10810 }
10811
10812 public int stopService(IApplicationThread caller, Intent service,
10813 String resolvedType) {
10814 // Refuse possible leaked file descriptors
10815 if (service != null && service.hasFileDescriptors() == true) {
10816 throw new IllegalArgumentException("File descriptors passed in Intent");
10817 }
10818
10819 synchronized(this) {
10820 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10821 + " type=" + resolvedType);
10822
10823 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10824 if (caller != null && callerApp == null) {
10825 throw new SecurityException(
10826 "Unable to find app for caller " + caller
10827 + " (pid=" + Binder.getCallingPid()
10828 + ") when stopping service " + service);
10829 }
10830
10831 // If this service is active, make sure it is stopped.
10832 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10833 if (r != null) {
10834 if (r.record != null) {
10835 synchronized (r.record.stats.getBatteryStats()) {
10836 r.record.stats.stopRunningLocked();
10837 }
10838 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010839 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010840 final long origId = Binder.clearCallingIdentity();
10841 bringDownServiceLocked(r.record, false);
10842 Binder.restoreCallingIdentity(origId);
10843 return 1;
10844 }
10845 return -1;
10846 }
10847 }
10848
10849 return 0;
10850 }
10851
10852 public IBinder peekService(Intent service, String resolvedType) {
10853 // Refuse possible leaked file descriptors
10854 if (service != null && service.hasFileDescriptors() == true) {
10855 throw new IllegalArgumentException("File descriptors passed in Intent");
10856 }
10857
10858 IBinder ret = null;
10859
10860 synchronized(this) {
10861 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10862
10863 if (r != null) {
10864 // r.record is null if findServiceLocked() failed the caller permission check
10865 if (r.record == null) {
10866 throw new SecurityException(
10867 "Permission Denial: Accessing service " + r.record.name
10868 + " from pid=" + Binder.getCallingPid()
10869 + ", uid=" + Binder.getCallingUid()
10870 + " requires " + r.permission);
10871 }
10872 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10873 if (ib != null) {
10874 ret = ib.binder;
10875 }
10876 }
10877 }
10878
10879 return ret;
10880 }
10881
10882 public boolean stopServiceToken(ComponentName className, IBinder token,
10883 int startId) {
10884 synchronized(this) {
10885 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10886 + " " + token + " startId=" + startId);
10887 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010888 if (r != null) {
10889 if (startId >= 0) {
10890 // Asked to only stop if done with all work. Note that
10891 // to avoid leaks, we will take this as dropping all
10892 // start items up to and including this one.
10893 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10894 if (si != null) {
10895 while (r.deliveredStarts.size() > 0) {
10896 if (r.deliveredStarts.remove(0) == si) {
10897 break;
10898 }
10899 }
10900 }
10901
10902 if (r.lastStartId != startId) {
10903 return false;
10904 }
10905
10906 if (r.deliveredStarts.size() > 0) {
10907 Log.w(TAG, "stopServiceToken startId " + startId
10908 + " is last, but have " + r.deliveredStarts.size()
10909 + " remaining args");
10910 }
10911 }
10912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010913 synchronized (r.stats.getBatteryStats()) {
10914 r.stats.stopRunningLocked();
10915 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010916 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010917 }
10918 final long origId = Binder.clearCallingIdentity();
10919 bringDownServiceLocked(r, false);
10920 Binder.restoreCallingIdentity(origId);
10921 return true;
10922 }
10923 }
10924 return false;
10925 }
10926
10927 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010928 int id, Notification notification, boolean removeNotification) {
10929 final long origId = Binder.clearCallingIdentity();
10930 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010931 synchronized(this) {
10932 ServiceRecord r = findServiceLocked(className, token);
10933 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010934 if (id != 0) {
10935 if (notification == null) {
10936 throw new IllegalArgumentException("null notification");
10937 }
10938 if (r.foregroundId != id) {
10939 r.cancelNotification();
10940 r.foregroundId = id;
10941 }
10942 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10943 r.foregroundNoti = notification;
10944 r.isForeground = true;
10945 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010946 if (r.app != null) {
10947 updateServiceForegroundLocked(r.app, true);
10948 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010949 } else {
10950 if (r.isForeground) {
10951 r.isForeground = false;
10952 if (r.app != null) {
10953 updateServiceForegroundLocked(r.app, true);
10954 }
10955 }
10956 if (removeNotification) {
10957 r.cancelNotification();
10958 r.foregroundId = 0;
10959 r.foregroundNoti = null;
10960 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010961 }
10962 }
10963 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010964 } finally {
10965 Binder.restoreCallingIdentity(origId);
10966 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010967 }
10968
10969 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10970 boolean anyForeground = false;
10971 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10972 if (sr.isForeground) {
10973 anyForeground = true;
10974 break;
10975 }
10976 }
10977 if (anyForeground != proc.foregroundServices) {
10978 proc.foregroundServices = anyForeground;
10979 if (oomAdj) {
10980 updateOomAdjLocked();
10981 }
10982 }
10983 }
10984
10985 public int bindService(IApplicationThread caller, IBinder token,
10986 Intent service, String resolvedType,
10987 IServiceConnection connection, int flags) {
10988 // Refuse possible leaked file descriptors
10989 if (service != null && service.hasFileDescriptors() == true) {
10990 throw new IllegalArgumentException("File descriptors passed in Intent");
10991 }
10992
10993 synchronized(this) {
10994 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10995 + " type=" + resolvedType + " conn=" + connection.asBinder()
10996 + " flags=0x" + Integer.toHexString(flags));
10997 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10998 if (callerApp == null) {
10999 throw new SecurityException(
11000 "Unable to find app for caller " + caller
11001 + " (pid=" + Binder.getCallingPid()
11002 + ") when binding service " + service);
11003 }
11004
11005 HistoryRecord activity = null;
11006 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011007 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011008 if (aindex < 0) {
11009 Log.w(TAG, "Binding with unknown activity: " + token);
11010 return 0;
11011 }
11012 activity = (HistoryRecord)mHistory.get(aindex);
11013 }
11014
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011015 int clientLabel = 0;
11016 PendingIntent clientIntent = null;
11017
11018 if (callerApp.info.uid == Process.SYSTEM_UID) {
11019 // Hacky kind of thing -- allow system stuff to tell us
11020 // what they are, so we can report this elsewhere for
11021 // others to know why certain services are running.
11022 try {
11023 clientIntent = (PendingIntent)service.getParcelableExtra(
11024 Intent.EXTRA_CLIENT_INTENT);
11025 } catch (RuntimeException e) {
11026 }
11027 if (clientIntent != null) {
11028 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11029 if (clientLabel != 0) {
11030 // There are no useful extras in the intent, trash them.
11031 // System code calling with this stuff just needs to know
11032 // this will happen.
11033 service = service.cloneFilter();
11034 }
11035 }
11036 }
11037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011038 ServiceLookupResult res =
11039 retrieveServiceLocked(service, resolvedType,
11040 Binder.getCallingPid(), Binder.getCallingUid());
11041 if (res == null) {
11042 return 0;
11043 }
11044 if (res.record == null) {
11045 return -1;
11046 }
11047 ServiceRecord s = res.record;
11048
11049 final long origId = Binder.clearCallingIdentity();
11050
11051 if (unscheduleServiceRestartLocked(s)) {
11052 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11053 + s.shortName);
11054 }
11055
11056 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11057 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011058 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011059
11060 IBinder binder = connection.asBinder();
11061 s.connections.put(binder, c);
11062 b.connections.add(c);
11063 if (activity != null) {
11064 if (activity.connections == null) {
11065 activity.connections = new HashSet<ConnectionRecord>();
11066 }
11067 activity.connections.add(c);
11068 }
11069 b.client.connections.add(c);
11070 mServiceConnections.put(binder, c);
11071
11072 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11073 s.lastActivity = SystemClock.uptimeMillis();
11074 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11075 return 0;
11076 }
11077 }
11078
11079 if (s.app != null) {
11080 // This could have made the service more important.
11081 updateOomAdjLocked(s.app);
11082 }
11083
11084 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11085 + ": received=" + b.intent.received
11086 + " apps=" + b.intent.apps.size()
11087 + " doRebind=" + b.intent.doRebind);
11088
11089 if (s.app != null && b.intent.received) {
11090 // Service is already running, so we can immediately
11091 // publish the connection.
11092 try {
11093 c.conn.connected(s.name, b.intent.binder);
11094 } catch (Exception e) {
11095 Log.w(TAG, "Failure sending service " + s.shortName
11096 + " to connection " + c.conn.asBinder()
11097 + " (in " + c.binding.client.processName + ")", e);
11098 }
11099
11100 // If this is the first app connected back to this binding,
11101 // and the service had previously asked to be told when
11102 // rebound, then do so.
11103 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11104 requestServiceBindingLocked(s, b.intent, true);
11105 }
11106 } else if (!b.intent.requested) {
11107 requestServiceBindingLocked(s, b.intent, false);
11108 }
11109
11110 Binder.restoreCallingIdentity(origId);
11111 }
11112
11113 return 1;
11114 }
11115
11116 private void removeConnectionLocked(
11117 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11118 IBinder binder = c.conn.asBinder();
11119 AppBindRecord b = c.binding;
11120 ServiceRecord s = b.service;
11121 s.connections.remove(binder);
11122 b.connections.remove(c);
11123 if (c.activity != null && c.activity != skipAct) {
11124 if (c.activity.connections != null) {
11125 c.activity.connections.remove(c);
11126 }
11127 }
11128 if (b.client != skipApp) {
11129 b.client.connections.remove(c);
11130 }
11131 mServiceConnections.remove(binder);
11132
11133 if (b.connections.size() == 0) {
11134 b.intent.apps.remove(b.client);
11135 }
11136
11137 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11138 + ": shouldUnbind=" + b.intent.hasBound);
11139 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11140 && b.intent.hasBound) {
11141 try {
11142 bumpServiceExecutingLocked(s);
11143 updateOomAdjLocked(s.app);
11144 b.intent.hasBound = false;
11145 // Assume the client doesn't want to know about a rebind;
11146 // we will deal with that later if it asks for one.
11147 b.intent.doRebind = false;
11148 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11149 } catch (Exception e) {
11150 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11151 serviceDoneExecutingLocked(s, true);
11152 }
11153 }
11154
11155 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11156 bringDownServiceLocked(s, false);
11157 }
11158 }
11159
11160 public boolean unbindService(IServiceConnection connection) {
11161 synchronized (this) {
11162 IBinder binder = connection.asBinder();
11163 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11164 ConnectionRecord r = mServiceConnections.get(binder);
11165 if (r == null) {
11166 Log.w(TAG, "Unbind failed: could not find connection for "
11167 + connection.asBinder());
11168 return false;
11169 }
11170
11171 final long origId = Binder.clearCallingIdentity();
11172
11173 removeConnectionLocked(r, null, null);
11174
11175 if (r.binding.service.app != null) {
11176 // This could have made the service less important.
11177 updateOomAdjLocked(r.binding.service.app);
11178 }
11179
11180 Binder.restoreCallingIdentity(origId);
11181 }
11182
11183 return true;
11184 }
11185
11186 public void publishService(IBinder token, Intent intent, IBinder service) {
11187 // Refuse possible leaked file descriptors
11188 if (intent != null && intent.hasFileDescriptors() == true) {
11189 throw new IllegalArgumentException("File descriptors passed in Intent");
11190 }
11191
11192 synchronized(this) {
11193 if (!(token instanceof ServiceRecord)) {
11194 throw new IllegalArgumentException("Invalid service token");
11195 }
11196 ServiceRecord r = (ServiceRecord)token;
11197
11198 final long origId = Binder.clearCallingIdentity();
11199
11200 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11201 + " " + intent + ": " + service);
11202 if (r != null) {
11203 Intent.FilterComparison filter
11204 = new Intent.FilterComparison(intent);
11205 IntentBindRecord b = r.bindings.get(filter);
11206 if (b != null && !b.received) {
11207 b.binder = service;
11208 b.requested = true;
11209 b.received = true;
11210 if (r.connections.size() > 0) {
11211 Iterator<ConnectionRecord> it
11212 = r.connections.values().iterator();
11213 while (it.hasNext()) {
11214 ConnectionRecord c = it.next();
11215 if (!filter.equals(c.binding.intent.intent)) {
11216 if (DEBUG_SERVICE) Log.v(
11217 TAG, "Not publishing to: " + c);
11218 if (DEBUG_SERVICE) Log.v(
11219 TAG, "Bound intent: " + c.binding.intent.intent);
11220 if (DEBUG_SERVICE) Log.v(
11221 TAG, "Published intent: " + intent);
11222 continue;
11223 }
11224 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11225 try {
11226 c.conn.connected(r.name, service);
11227 } catch (Exception e) {
11228 Log.w(TAG, "Failure sending service " + r.name +
11229 " to connection " + c.conn.asBinder() +
11230 " (in " + c.binding.client.processName + ")", e);
11231 }
11232 }
11233 }
11234 }
11235
11236 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11237
11238 Binder.restoreCallingIdentity(origId);
11239 }
11240 }
11241 }
11242
11243 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11244 // Refuse possible leaked file descriptors
11245 if (intent != null && intent.hasFileDescriptors() == true) {
11246 throw new IllegalArgumentException("File descriptors passed in Intent");
11247 }
11248
11249 synchronized(this) {
11250 if (!(token instanceof ServiceRecord)) {
11251 throw new IllegalArgumentException("Invalid service token");
11252 }
11253 ServiceRecord r = (ServiceRecord)token;
11254
11255 final long origId = Binder.clearCallingIdentity();
11256
11257 if (r != null) {
11258 Intent.FilterComparison filter
11259 = new Intent.FilterComparison(intent);
11260 IntentBindRecord b = r.bindings.get(filter);
11261 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11262 + " at " + b + ": apps="
11263 + (b != null ? b.apps.size() : 0));
11264 if (b != null) {
11265 if (b.apps.size() > 0) {
11266 // Applications have already bound since the last
11267 // unbind, so just rebind right here.
11268 requestServiceBindingLocked(r, b, true);
11269 } else {
11270 // Note to tell the service the next time there is
11271 // a new client.
11272 b.doRebind = true;
11273 }
11274 }
11275
11276 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11277
11278 Binder.restoreCallingIdentity(origId);
11279 }
11280 }
11281 }
11282
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011283 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011284 synchronized(this) {
11285 if (!(token instanceof ServiceRecord)) {
11286 throw new IllegalArgumentException("Invalid service token");
11287 }
11288 ServiceRecord r = (ServiceRecord)token;
11289 boolean inStopping = mStoppingServices.contains(token);
11290 if (r != null) {
11291 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11292 + ": nesting=" + r.executeNesting
11293 + ", inStopping=" + inStopping);
11294 if (r != token) {
11295 Log.w(TAG, "Done executing service " + r.name
11296 + " with incorrect token: given " + token
11297 + ", expected " + r);
11298 return;
11299 }
11300
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011301 if (type == 1) {
11302 // This is a call from a service start... take care of
11303 // book-keeping.
11304 r.callStart = true;
11305 switch (res) {
11306 case Service.START_STICKY_COMPATIBILITY:
11307 case Service.START_STICKY: {
11308 // We are done with the associated start arguments.
11309 r.findDeliveredStart(startId, true);
11310 // Don't stop if killed.
11311 r.stopIfKilled = false;
11312 break;
11313 }
11314 case Service.START_NOT_STICKY: {
11315 // We are done with the associated start arguments.
11316 r.findDeliveredStart(startId, true);
11317 if (r.lastStartId == startId) {
11318 // There is no more work, and this service
11319 // doesn't want to hang around if killed.
11320 r.stopIfKilled = true;
11321 }
11322 break;
11323 }
11324 case Service.START_REDELIVER_INTENT: {
11325 // We'll keep this item until they explicitly
11326 // call stop for it, but keep track of the fact
11327 // that it was delivered.
11328 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11329 if (si != null) {
11330 si.deliveryCount = 0;
11331 si.doneExecutingCount++;
11332 // Don't stop if killed.
11333 r.stopIfKilled = true;
11334 }
11335 break;
11336 }
11337 default:
11338 throw new IllegalArgumentException(
11339 "Unknown service start result: " + res);
11340 }
11341 if (res == Service.START_STICKY_COMPATIBILITY) {
11342 r.callStart = false;
11343 }
11344 }
11345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011346 final long origId = Binder.clearCallingIdentity();
11347 serviceDoneExecutingLocked(r, inStopping);
11348 Binder.restoreCallingIdentity(origId);
11349 } else {
11350 Log.w(TAG, "Done executing unknown service " + r.name
11351 + " with token " + token);
11352 }
11353 }
11354 }
11355
11356 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11357 r.executeNesting--;
11358 if (r.executeNesting <= 0 && r.app != null) {
11359 r.app.executingServices.remove(r);
11360 if (r.app.executingServices.size() == 0) {
11361 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11362 }
11363 if (inStopping) {
11364 mStoppingServices.remove(r);
11365 }
11366 updateOomAdjLocked(r.app);
11367 }
11368 }
11369
11370 void serviceTimeout(ProcessRecord proc) {
11371 synchronized(this) {
11372 if (proc.executingServices.size() == 0 || proc.thread == null) {
11373 return;
11374 }
11375 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11376 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11377 ServiceRecord timeout = null;
11378 long nextTime = 0;
11379 while (it.hasNext()) {
11380 ServiceRecord sr = it.next();
11381 if (sr.executingStart < maxTime) {
11382 timeout = sr;
11383 break;
11384 }
11385 if (sr.executingStart > nextTime) {
11386 nextTime = sr.executingStart;
11387 }
11388 }
11389 if (timeout != null && mLRUProcesses.contains(proc)) {
11390 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011391 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011392 + timeout.name);
11393 } else {
11394 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11395 msg.obj = proc;
11396 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11397 }
11398 }
11399 }
11400
11401 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011402 // BACKUP AND RESTORE
11403 // =========================================================
11404
11405 // Cause the target app to be launched if necessary and its backup agent
11406 // instantiated. The backup agent will invoke backupAgentCreated() on the
11407 // activity manager to announce its creation.
11408 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11409 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11410 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11411
11412 synchronized(this) {
11413 // !!! TODO: currently no check here that we're already bound
11414 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11415 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11416 synchronized (stats) {
11417 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11418 }
11419
11420 BackupRecord r = new BackupRecord(ss, app, backupMode);
11421 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11422 // startProcessLocked() returns existing proc's record if it's already running
11423 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011424 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011425 if (proc == null) {
11426 Log.e(TAG, "Unable to start backup agent process " + r);
11427 return false;
11428 }
11429
11430 r.app = proc;
11431 mBackupTarget = r;
11432 mBackupAppName = app.packageName;
11433
Christopher Tate6fa95972009-06-05 18:43:55 -070011434 // Try not to kill the process during backup
11435 updateOomAdjLocked(proc);
11436
Christopher Tate181fafa2009-05-14 11:12:14 -070011437 // If the process is already attached, schedule the creation of the backup agent now.
11438 // If it is not yet live, this will be done when it attaches to the framework.
11439 if (proc.thread != null) {
11440 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11441 try {
11442 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11443 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011444 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011445 }
11446 } else {
11447 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11448 }
11449 // Invariants: at this point, the target app process exists and the application
11450 // is either already running or in the process of coming up. mBackupTarget and
11451 // mBackupAppName describe the app, so that when it binds back to the AM we
11452 // know that it's scheduled for a backup-agent operation.
11453 }
11454
11455 return true;
11456 }
11457
11458 // A backup agent has just come up
11459 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11460 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11461 + " = " + agent);
11462
11463 synchronized(this) {
11464 if (!agentPackageName.equals(mBackupAppName)) {
11465 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11466 return;
11467 }
11468
Christopher Tate043dadc2009-06-02 16:11:00 -070011469 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011470 try {
11471 IBackupManager bm = IBackupManager.Stub.asInterface(
11472 ServiceManager.getService(Context.BACKUP_SERVICE));
11473 bm.agentConnected(agentPackageName, agent);
11474 } catch (RemoteException e) {
11475 // can't happen; the backup manager service is local
11476 } catch (Exception e) {
11477 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11478 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011479 } finally {
11480 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011481 }
11482 }
11483 }
11484
11485 // done with this agent
11486 public void unbindBackupAgent(ApplicationInfo appInfo) {
11487 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011488 if (appInfo == null) {
11489 Log.w(TAG, "unbind backup agent for null app");
11490 return;
11491 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011492
11493 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011494 if (mBackupAppName == null) {
11495 Log.w(TAG, "Unbinding backup agent with no active backup");
11496 return;
11497 }
11498
Christopher Tate181fafa2009-05-14 11:12:14 -070011499 if (!mBackupAppName.equals(appInfo.packageName)) {
11500 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11501 return;
11502 }
11503
Christopher Tate6fa95972009-06-05 18:43:55 -070011504 ProcessRecord proc = mBackupTarget.app;
11505 mBackupTarget = null;
11506 mBackupAppName = null;
11507
11508 // Not backing this app up any more; reset its OOM adjustment
11509 updateOomAdjLocked(proc);
11510
Christopher Tatec7b31e32009-06-10 15:49:30 -070011511 // If the app crashed during backup, 'thread' will be null here
11512 if (proc.thread != null) {
11513 try {
11514 proc.thread.scheduleDestroyBackupAgent(appInfo);
11515 } catch (Exception e) {
11516 Log.e(TAG, "Exception when unbinding backup agent:");
11517 e.printStackTrace();
11518 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011519 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011520 }
11521 }
11522 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011523 // BROADCASTS
11524 // =========================================================
11525
11526 private final List getStickies(String action, IntentFilter filter,
11527 List cur) {
11528 final ContentResolver resolver = mContext.getContentResolver();
11529 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11530 if (list == null) {
11531 return cur;
11532 }
11533 int N = list.size();
11534 for (int i=0; i<N; i++) {
11535 Intent intent = list.get(i);
11536 if (filter.match(resolver, intent, true, TAG) >= 0) {
11537 if (cur == null) {
11538 cur = new ArrayList<Intent>();
11539 }
11540 cur.add(intent);
11541 }
11542 }
11543 return cur;
11544 }
11545
11546 private final void scheduleBroadcastsLocked() {
11547 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11548 + mBroadcastsScheduled);
11549
11550 if (mBroadcastsScheduled) {
11551 return;
11552 }
11553 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11554 mBroadcastsScheduled = true;
11555 }
11556
11557 public Intent registerReceiver(IApplicationThread caller,
11558 IIntentReceiver receiver, IntentFilter filter, String permission) {
11559 synchronized(this) {
11560 ProcessRecord callerApp = null;
11561 if (caller != null) {
11562 callerApp = getRecordForAppLocked(caller);
11563 if (callerApp == null) {
11564 throw new SecurityException(
11565 "Unable to find app for caller " + caller
11566 + " (pid=" + Binder.getCallingPid()
11567 + ") when registering receiver " + receiver);
11568 }
11569 }
11570
11571 List allSticky = null;
11572
11573 // Look for any matching sticky broadcasts...
11574 Iterator actions = filter.actionsIterator();
11575 if (actions != null) {
11576 while (actions.hasNext()) {
11577 String action = (String)actions.next();
11578 allSticky = getStickies(action, filter, allSticky);
11579 }
11580 } else {
11581 allSticky = getStickies(null, filter, allSticky);
11582 }
11583
11584 // The first sticky in the list is returned directly back to
11585 // the client.
11586 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11587
11588 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11589 + ": " + sticky);
11590
11591 if (receiver == null) {
11592 return sticky;
11593 }
11594
11595 ReceiverList rl
11596 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11597 if (rl == null) {
11598 rl = new ReceiverList(this, callerApp,
11599 Binder.getCallingPid(),
11600 Binder.getCallingUid(), receiver);
11601 if (rl.app != null) {
11602 rl.app.receivers.add(rl);
11603 } else {
11604 try {
11605 receiver.asBinder().linkToDeath(rl, 0);
11606 } catch (RemoteException e) {
11607 return sticky;
11608 }
11609 rl.linkedToDeath = true;
11610 }
11611 mRegisteredReceivers.put(receiver.asBinder(), rl);
11612 }
11613 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11614 rl.add(bf);
11615 if (!bf.debugCheck()) {
11616 Log.w(TAG, "==> For Dynamic broadast");
11617 }
11618 mReceiverResolver.addFilter(bf);
11619
11620 // Enqueue broadcasts for all existing stickies that match
11621 // this filter.
11622 if (allSticky != null) {
11623 ArrayList receivers = new ArrayList();
11624 receivers.add(bf);
11625
11626 int N = allSticky.size();
11627 for (int i=0; i<N; i++) {
11628 Intent intent = (Intent)allSticky.get(i);
11629 BroadcastRecord r = new BroadcastRecord(intent, null,
11630 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011631 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011632 if (mParallelBroadcasts.size() == 0) {
11633 scheduleBroadcastsLocked();
11634 }
11635 mParallelBroadcasts.add(r);
11636 }
11637 }
11638
11639 return sticky;
11640 }
11641 }
11642
11643 public void unregisterReceiver(IIntentReceiver receiver) {
11644 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11645
11646 boolean doNext = false;
11647
11648 synchronized(this) {
11649 ReceiverList rl
11650 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11651 if (rl != null) {
11652 if (rl.curBroadcast != null) {
11653 BroadcastRecord r = rl.curBroadcast;
11654 doNext = finishReceiverLocked(
11655 receiver.asBinder(), r.resultCode, r.resultData,
11656 r.resultExtras, r.resultAbort, true);
11657 }
11658
11659 if (rl.app != null) {
11660 rl.app.receivers.remove(rl);
11661 }
11662 removeReceiverLocked(rl);
11663 if (rl.linkedToDeath) {
11664 rl.linkedToDeath = false;
11665 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11666 }
11667 }
11668 }
11669
11670 if (!doNext) {
11671 return;
11672 }
11673
11674 final long origId = Binder.clearCallingIdentity();
11675 processNextBroadcast(false);
11676 trimApplications();
11677 Binder.restoreCallingIdentity(origId);
11678 }
11679
11680 void removeReceiverLocked(ReceiverList rl) {
11681 mRegisteredReceivers.remove(rl.receiver.asBinder());
11682 int N = rl.size();
11683 for (int i=0; i<N; i++) {
11684 mReceiverResolver.removeFilter(rl.get(i));
11685 }
11686 }
11687
11688 private final int broadcastIntentLocked(ProcessRecord callerApp,
11689 String callerPackage, Intent intent, String resolvedType,
11690 IIntentReceiver resultTo, int resultCode, String resultData,
11691 Bundle map, String requiredPermission,
11692 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11693 intent = new Intent(intent);
11694
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011695 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011696 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11697 + " ordered=" + ordered);
11698 if ((resultTo != null) && !ordered) {
11699 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11700 }
11701
11702 // Handle special intents: if this broadcast is from the package
11703 // manager about a package being removed, we need to remove all of
11704 // its activities from the history stack.
11705 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11706 intent.getAction());
11707 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11708 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11709 || uidRemoved) {
11710 if (checkComponentPermission(
11711 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11712 callingPid, callingUid, -1)
11713 == PackageManager.PERMISSION_GRANTED) {
11714 if (uidRemoved) {
11715 final Bundle intentExtras = intent.getExtras();
11716 final int uid = intentExtras != null
11717 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11718 if (uid >= 0) {
11719 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11720 synchronized (bs) {
11721 bs.removeUidStatsLocked(uid);
11722 }
11723 }
11724 } else {
11725 Uri data = intent.getData();
11726 String ssp;
11727 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11728 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11729 uninstallPackageLocked(ssp,
11730 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011731 AttributeCache ac = AttributeCache.instance();
11732 if (ac != null) {
11733 ac.removePackage(ssp);
11734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011735 }
11736 }
11737 }
11738 } else {
11739 String msg = "Permission Denial: " + intent.getAction()
11740 + " broadcast from " + callerPackage + " (pid=" + callingPid
11741 + ", uid=" + callingUid + ")"
11742 + " requires "
11743 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11744 Log.w(TAG, msg);
11745 throw new SecurityException(msg);
11746 }
11747 }
11748
11749 /*
11750 * If this is the time zone changed action, queue up a message that will reset the timezone
11751 * of all currently running processes. This message will get queued up before the broadcast
11752 * happens.
11753 */
11754 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11755 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11756 }
11757
Dianne Hackborn854060af2009-07-09 18:14:31 -070011758 /*
11759 * Prevent non-system code (defined here to be non-persistent
11760 * processes) from sending protected broadcasts.
11761 */
11762 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11763 || callingUid == Process.SHELL_UID || callingUid == 0) {
11764 // Always okay.
11765 } else if (callerApp == null || !callerApp.persistent) {
11766 try {
11767 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11768 intent.getAction())) {
11769 String msg = "Permission Denial: not allowed to send broadcast "
11770 + intent.getAction() + " from pid="
11771 + callingPid + ", uid=" + callingUid;
11772 Log.w(TAG, msg);
11773 throw new SecurityException(msg);
11774 }
11775 } catch (RemoteException e) {
11776 Log.w(TAG, "Remote exception", e);
11777 return BROADCAST_SUCCESS;
11778 }
11779 }
11780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011781 // Add to the sticky list if requested.
11782 if (sticky) {
11783 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11784 callingPid, callingUid)
11785 != PackageManager.PERMISSION_GRANTED) {
11786 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11787 + callingPid + ", uid=" + callingUid
11788 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11789 Log.w(TAG, msg);
11790 throw new SecurityException(msg);
11791 }
11792 if (requiredPermission != null) {
11793 Log.w(TAG, "Can't broadcast sticky intent " + intent
11794 + " and enforce permission " + requiredPermission);
11795 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11796 }
11797 if (intent.getComponent() != null) {
11798 throw new SecurityException(
11799 "Sticky broadcasts can't target a specific component");
11800 }
11801 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11802 if (list == null) {
11803 list = new ArrayList<Intent>();
11804 mStickyBroadcasts.put(intent.getAction(), list);
11805 }
11806 int N = list.size();
11807 int i;
11808 for (i=0; i<N; i++) {
11809 if (intent.filterEquals(list.get(i))) {
11810 // This sticky already exists, replace it.
11811 list.set(i, new Intent(intent));
11812 break;
11813 }
11814 }
11815 if (i >= N) {
11816 list.add(new Intent(intent));
11817 }
11818 }
11819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011820 // Figure out who all will receive this broadcast.
11821 List receivers = null;
11822 List<BroadcastFilter> registeredReceivers = null;
11823 try {
11824 if (intent.getComponent() != null) {
11825 // Broadcast is going to one specific receiver class...
11826 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011827 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011828 if (ai != null) {
11829 receivers = new ArrayList();
11830 ResolveInfo ri = new ResolveInfo();
11831 ri.activityInfo = ai;
11832 receivers.add(ri);
11833 }
11834 } else {
11835 // Need to resolve the intent to interested receivers...
11836 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11837 == 0) {
11838 receivers =
11839 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011840 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011841 }
Mihai Preda074edef2009-05-18 17:13:31 +020011842 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011843 }
11844 } catch (RemoteException ex) {
11845 // pm is in same process, this will never happen.
11846 }
11847
11848 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11849 if (!ordered && NR > 0) {
11850 // If we are not serializing this broadcast, then send the
11851 // registered receivers separately so they don't wait for the
11852 // components to be launched.
11853 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11854 callerPackage, callingPid, callingUid, requiredPermission,
11855 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011856 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011857 if (DEBUG_BROADCAST) Log.v(
11858 TAG, "Enqueueing parallel broadcast " + r
11859 + ": prev had " + mParallelBroadcasts.size());
11860 mParallelBroadcasts.add(r);
11861 scheduleBroadcastsLocked();
11862 registeredReceivers = null;
11863 NR = 0;
11864 }
11865
11866 // Merge into one list.
11867 int ir = 0;
11868 if (receivers != null) {
11869 // A special case for PACKAGE_ADDED: do not allow the package
11870 // being added to see this broadcast. This prevents them from
11871 // using this as a back door to get run as soon as they are
11872 // installed. Maybe in the future we want to have a special install
11873 // broadcast or such for apps, but we'd like to deliberately make
11874 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011875 boolean skip = false;
11876 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011877 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011878 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11879 skip = true;
11880 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11881 skip = true;
11882 }
11883 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011884 ? intent.getData().getSchemeSpecificPart()
11885 : null;
11886 if (skipPackage != null && receivers != null) {
11887 int NT = receivers.size();
11888 for (int it=0; it<NT; it++) {
11889 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11890 if (curt.activityInfo.packageName.equals(skipPackage)) {
11891 receivers.remove(it);
11892 it--;
11893 NT--;
11894 }
11895 }
11896 }
11897
11898 int NT = receivers != null ? receivers.size() : 0;
11899 int it = 0;
11900 ResolveInfo curt = null;
11901 BroadcastFilter curr = null;
11902 while (it < NT && ir < NR) {
11903 if (curt == null) {
11904 curt = (ResolveInfo)receivers.get(it);
11905 }
11906 if (curr == null) {
11907 curr = registeredReceivers.get(ir);
11908 }
11909 if (curr.getPriority() >= curt.priority) {
11910 // Insert this broadcast record into the final list.
11911 receivers.add(it, curr);
11912 ir++;
11913 curr = null;
11914 it++;
11915 NT++;
11916 } else {
11917 // Skip to the next ResolveInfo in the final list.
11918 it++;
11919 curt = null;
11920 }
11921 }
11922 }
11923 while (ir < NR) {
11924 if (receivers == null) {
11925 receivers = new ArrayList();
11926 }
11927 receivers.add(registeredReceivers.get(ir));
11928 ir++;
11929 }
11930
11931 if ((receivers != null && receivers.size() > 0)
11932 || resultTo != null) {
11933 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11934 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011935 receivers, resultTo, resultCode, resultData, map, ordered,
11936 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011937 if (DEBUG_BROADCAST) Log.v(
11938 TAG, "Enqueueing ordered broadcast " + r
11939 + ": prev had " + mOrderedBroadcasts.size());
11940 if (DEBUG_BROADCAST) {
11941 int seq = r.intent.getIntExtra("seq", -1);
11942 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11943 }
11944 mOrderedBroadcasts.add(r);
11945 scheduleBroadcastsLocked();
11946 }
11947
11948 return BROADCAST_SUCCESS;
11949 }
11950
11951 public final int broadcastIntent(IApplicationThread caller,
11952 Intent intent, String resolvedType, IIntentReceiver resultTo,
11953 int resultCode, String resultData, Bundle map,
11954 String requiredPermission, boolean serialized, boolean sticky) {
11955 // Refuse possible leaked file descriptors
11956 if (intent != null && intent.hasFileDescriptors() == true) {
11957 throw new IllegalArgumentException("File descriptors passed in Intent");
11958 }
11959
11960 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011961 int flags = intent.getFlags();
11962
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011963 if (!mSystemReady) {
11964 // if the caller really truly claims to know what they're doing, go
11965 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011966 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11967 intent = new Intent(intent);
11968 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11969 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11970 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11971 + " before boot completion");
11972 throw new IllegalStateException("Cannot broadcast before boot completed");
11973 }
11974 }
11975
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011976 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11977 throw new IllegalArgumentException(
11978 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11979 }
11980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011981 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11982 final int callingPid = Binder.getCallingPid();
11983 final int callingUid = Binder.getCallingUid();
11984 final long origId = Binder.clearCallingIdentity();
11985 int res = broadcastIntentLocked(callerApp,
11986 callerApp != null ? callerApp.info.packageName : null,
11987 intent, resolvedType, resultTo,
11988 resultCode, resultData, map, requiredPermission, serialized,
11989 sticky, callingPid, callingUid);
11990 Binder.restoreCallingIdentity(origId);
11991 return res;
11992 }
11993 }
11994
11995 int broadcastIntentInPackage(String packageName, int uid,
11996 Intent intent, String resolvedType, IIntentReceiver resultTo,
11997 int resultCode, String resultData, Bundle map,
11998 String requiredPermission, boolean serialized, boolean sticky) {
11999 synchronized(this) {
12000 final long origId = Binder.clearCallingIdentity();
12001 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12002 resultTo, resultCode, resultData, map, requiredPermission,
12003 serialized, sticky, -1, uid);
12004 Binder.restoreCallingIdentity(origId);
12005 return res;
12006 }
12007 }
12008
12009 public final void unbroadcastIntent(IApplicationThread caller,
12010 Intent intent) {
12011 // Refuse possible leaked file descriptors
12012 if (intent != null && intent.hasFileDescriptors() == true) {
12013 throw new IllegalArgumentException("File descriptors passed in Intent");
12014 }
12015
12016 synchronized(this) {
12017 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12018 != PackageManager.PERMISSION_GRANTED) {
12019 String msg = "Permission Denial: unbroadcastIntent() from pid="
12020 + Binder.getCallingPid()
12021 + ", uid=" + Binder.getCallingUid()
12022 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12023 Log.w(TAG, msg);
12024 throw new SecurityException(msg);
12025 }
12026 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12027 if (list != null) {
12028 int N = list.size();
12029 int i;
12030 for (i=0; i<N; i++) {
12031 if (intent.filterEquals(list.get(i))) {
12032 list.remove(i);
12033 break;
12034 }
12035 }
12036 }
12037 }
12038 }
12039
12040 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12041 String resultData, Bundle resultExtras, boolean resultAbort,
12042 boolean explicit) {
12043 if (mOrderedBroadcasts.size() == 0) {
12044 if (explicit) {
12045 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12046 }
12047 return false;
12048 }
12049 BroadcastRecord r = mOrderedBroadcasts.get(0);
12050 if (r.receiver == null) {
12051 if (explicit) {
12052 Log.w(TAG, "finishReceiver called but none active");
12053 }
12054 return false;
12055 }
12056 if (r.receiver != receiver) {
12057 Log.w(TAG, "finishReceiver called but active receiver is different");
12058 return false;
12059 }
12060 int state = r.state;
12061 r.state = r.IDLE;
12062 if (state == r.IDLE) {
12063 if (explicit) {
12064 Log.w(TAG, "finishReceiver called but state is IDLE");
12065 }
12066 }
12067 r.receiver = null;
12068 r.intent.setComponent(null);
12069 if (r.curApp != null) {
12070 r.curApp.curReceiver = null;
12071 }
12072 if (r.curFilter != null) {
12073 r.curFilter.receiverList.curBroadcast = null;
12074 }
12075 r.curFilter = null;
12076 r.curApp = null;
12077 r.curComponent = null;
12078 r.curReceiver = null;
12079 mPendingBroadcast = null;
12080
12081 r.resultCode = resultCode;
12082 r.resultData = resultData;
12083 r.resultExtras = resultExtras;
12084 r.resultAbort = resultAbort;
12085
12086 // We will process the next receiver right now if this is finishing
12087 // an app receiver (which is always asynchronous) or after we have
12088 // come back from calling a receiver.
12089 return state == BroadcastRecord.APP_RECEIVE
12090 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12091 }
12092
12093 public void finishReceiver(IBinder who, int resultCode, String resultData,
12094 Bundle resultExtras, boolean resultAbort) {
12095 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12096
12097 // Refuse possible leaked file descriptors
12098 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12099 throw new IllegalArgumentException("File descriptors passed in Bundle");
12100 }
12101
12102 boolean doNext;
12103
12104 final long origId = Binder.clearCallingIdentity();
12105
12106 synchronized(this) {
12107 doNext = finishReceiverLocked(
12108 who, resultCode, resultData, resultExtras, resultAbort, true);
12109 }
12110
12111 if (doNext) {
12112 processNextBroadcast(false);
12113 }
12114 trimApplications();
12115
12116 Binder.restoreCallingIdentity(origId);
12117 }
12118
12119 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12120 if (r.nextReceiver > 0) {
12121 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12122 if (curReceiver instanceof BroadcastFilter) {
12123 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12124 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12125 System.identityHashCode(r),
12126 r.intent.getAction(),
12127 r.nextReceiver - 1,
12128 System.identityHashCode(bf));
12129 } else {
12130 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12131 System.identityHashCode(r),
12132 r.intent.getAction(),
12133 r.nextReceiver - 1,
12134 ((ResolveInfo)curReceiver).toString());
12135 }
12136 } else {
12137 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12138 + r);
12139 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12140 System.identityHashCode(r),
12141 r.intent.getAction(),
12142 r.nextReceiver,
12143 "NONE");
12144 }
12145 }
12146
12147 private final void broadcastTimeout() {
12148 synchronized (this) {
12149 if (mOrderedBroadcasts.size() == 0) {
12150 return;
12151 }
12152 long now = SystemClock.uptimeMillis();
12153 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012154 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012155 if (DEBUG_BROADCAST) Log.v(TAG,
12156 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012157 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012158 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012159 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012160 return;
12161 }
12162
12163 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012164 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012165 r.anrCount++;
12166
12167 // Current receiver has passed its expiration date.
12168 if (r.nextReceiver <= 0) {
12169 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12170 return;
12171 }
12172
12173 ProcessRecord app = null;
12174
12175 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12176 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12177 logBroadcastReceiverDiscard(r);
12178 if (curReceiver instanceof BroadcastFilter) {
12179 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12180 if (bf.receiverList.pid != 0
12181 && bf.receiverList.pid != MY_PID) {
12182 synchronized (this.mPidsSelfLocked) {
12183 app = this.mPidsSelfLocked.get(
12184 bf.receiverList.pid);
12185 }
12186 }
12187 } else {
12188 app = r.curApp;
12189 }
12190
12191 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012192 appNotRespondingLocked(app, null, null,
12193 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012194 }
12195
12196 if (mPendingBroadcast == r) {
12197 mPendingBroadcast = null;
12198 }
12199
12200 // Move on to the next receiver.
12201 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12202 r.resultExtras, r.resultAbort, true);
12203 scheduleBroadcastsLocked();
12204 }
12205 }
12206
12207 private final void processCurBroadcastLocked(BroadcastRecord r,
12208 ProcessRecord app) throws RemoteException {
12209 if (app.thread == null) {
12210 throw new RemoteException();
12211 }
12212 r.receiver = app.thread.asBinder();
12213 r.curApp = app;
12214 app.curReceiver = r;
12215 updateLRUListLocked(app, true);
12216
12217 // Tell the application to launch this receiver.
12218 r.intent.setComponent(r.curComponent);
12219
12220 boolean started = false;
12221 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012222 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012223 "Delivering to component " + r.curComponent
12224 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012225 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012226 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12227 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12228 started = true;
12229 } finally {
12230 if (!started) {
12231 r.receiver = null;
12232 r.curApp = null;
12233 app.curReceiver = null;
12234 }
12235 }
12236
12237 }
12238
12239 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012240 Intent intent, int resultCode, String data, Bundle extras,
12241 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012242 if (app != null && app.thread != null) {
12243 // If we have an app thread, do the call through that so it is
12244 // correctly ordered with other one-way calls.
12245 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012246 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012247 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012248 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012249 }
12250 }
12251
12252 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12253 BroadcastFilter filter, boolean ordered) {
12254 boolean skip = false;
12255 if (filter.requiredPermission != null) {
12256 int perm = checkComponentPermission(filter.requiredPermission,
12257 r.callingPid, r.callingUid, -1);
12258 if (perm != PackageManager.PERMISSION_GRANTED) {
12259 Log.w(TAG, "Permission Denial: broadcasting "
12260 + r.intent.toString()
12261 + " from " + r.callerPackage + " (pid="
12262 + r.callingPid + ", uid=" + r.callingUid + ")"
12263 + " requires " + filter.requiredPermission
12264 + " due to registered receiver " + filter);
12265 skip = true;
12266 }
12267 }
12268 if (r.requiredPermission != null) {
12269 int perm = checkComponentPermission(r.requiredPermission,
12270 filter.receiverList.pid, filter.receiverList.uid, -1);
12271 if (perm != PackageManager.PERMISSION_GRANTED) {
12272 Log.w(TAG, "Permission Denial: receiving "
12273 + r.intent.toString()
12274 + " to " + filter.receiverList.app
12275 + " (pid=" + filter.receiverList.pid
12276 + ", uid=" + filter.receiverList.uid + ")"
12277 + " requires " + r.requiredPermission
12278 + " due to sender " + r.callerPackage
12279 + " (uid " + r.callingUid + ")");
12280 skip = true;
12281 }
12282 }
12283
12284 if (!skip) {
12285 // If this is not being sent as an ordered broadcast, then we
12286 // don't want to touch the fields that keep track of the current
12287 // state of ordered broadcasts.
12288 if (ordered) {
12289 r.receiver = filter.receiverList.receiver.asBinder();
12290 r.curFilter = filter;
12291 filter.receiverList.curBroadcast = r;
12292 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012293 if (filter.receiverList.app != null) {
12294 // Bump hosting application to no longer be in background
12295 // scheduling class. Note that we can't do that if there
12296 // isn't an app... but we can only be in that case for
12297 // things that directly call the IActivityManager API, which
12298 // are already core system stuff so don't matter for this.
12299 r.curApp = filter.receiverList.app;
12300 filter.receiverList.app.curReceiver = r;
12301 updateOomAdjLocked();
12302 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012303 }
12304 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012305 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012306 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012307 Log.i(TAG, "Delivering to " + filter.receiverList.app
12308 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012309 }
12310 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12311 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012312 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012313 if (ordered) {
12314 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12315 }
12316 } catch (RemoteException e) {
12317 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12318 if (ordered) {
12319 r.receiver = null;
12320 r.curFilter = null;
12321 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012322 if (filter.receiverList.app != null) {
12323 filter.receiverList.app.curReceiver = null;
12324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012325 }
12326 }
12327 }
12328 }
12329
Dianne Hackborn12527f92009-11-11 17:39:50 -080012330 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12331 if (r.callingUid < 0) {
12332 // This was from a registerReceiver() call; ignore it.
12333 return;
12334 }
12335 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12336 MAX_BROADCAST_HISTORY-1);
12337 r.finishTime = SystemClock.uptimeMillis();
12338 mBroadcastHistory[0] = r;
12339 }
12340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012341 private final void processNextBroadcast(boolean fromMsg) {
12342 synchronized(this) {
12343 BroadcastRecord r;
12344
12345 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12346 + mParallelBroadcasts.size() + " broadcasts, "
12347 + mOrderedBroadcasts.size() + " serialized broadcasts");
12348
12349 updateCpuStats();
12350
12351 if (fromMsg) {
12352 mBroadcastsScheduled = false;
12353 }
12354
12355 // First, deliver any non-serialized broadcasts right away.
12356 while (mParallelBroadcasts.size() > 0) {
12357 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012358 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012359 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012360 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12361 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012362 for (int i=0; i<N; i++) {
12363 Object target = r.receivers.get(i);
12364 if (DEBUG_BROADCAST) Log.v(TAG,
12365 "Delivering non-serialized to registered "
12366 + target + ": " + r);
12367 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12368 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012369 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012370 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12371 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012372 }
12373
12374 // Now take care of the next serialized one...
12375
12376 // If we are waiting for a process to come up to handle the next
12377 // broadcast, then do nothing at this point. Just in case, we
12378 // check that the process we're waiting for still exists.
12379 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012380 if (DEBUG_BROADCAST_LIGHT) {
12381 Log.v(TAG, "processNextBroadcast: waiting for "
12382 + mPendingBroadcast.curApp);
12383 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012384
12385 boolean isDead;
12386 synchronized (mPidsSelfLocked) {
12387 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12388 }
12389 if (!isDead) {
12390 // It's still alive, so keep waiting
12391 return;
12392 } else {
12393 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12394 + " died before responding to broadcast");
12395 mPendingBroadcast = null;
12396 }
12397 }
12398
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012399 boolean looped = false;
12400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012401 do {
12402 if (mOrderedBroadcasts.size() == 0) {
12403 // No more broadcasts pending, so all done!
12404 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012405 if (looped) {
12406 // If we had finished the last ordered broadcast, then
12407 // make sure all processes have correct oom and sched
12408 // adjustments.
12409 updateOomAdjLocked();
12410 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012411 return;
12412 }
12413 r = mOrderedBroadcasts.get(0);
12414 boolean forceReceive = false;
12415
12416 // Ensure that even if something goes awry with the timeout
12417 // detection, we catch "hung" broadcasts here, discard them,
12418 // and continue to make progress.
12419 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12420 long now = SystemClock.uptimeMillis();
12421 if (r.dispatchTime > 0) {
12422 if ((numReceivers > 0) &&
12423 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12424 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12425 + " now=" + now
12426 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012427 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012428 + " intent=" + r.intent
12429 + " numReceivers=" + numReceivers
12430 + " nextReceiver=" + r.nextReceiver
12431 + " state=" + r.state);
12432 broadcastTimeout(); // forcibly finish this broadcast
12433 forceReceive = true;
12434 r.state = BroadcastRecord.IDLE;
12435 }
12436 }
12437
12438 if (r.state != BroadcastRecord.IDLE) {
12439 if (DEBUG_BROADCAST) Log.d(TAG,
12440 "processNextBroadcast() called when not idle (state="
12441 + r.state + ")");
12442 return;
12443 }
12444
12445 if (r.receivers == null || r.nextReceiver >= numReceivers
12446 || r.resultAbort || forceReceive) {
12447 // No more receivers for this broadcast! Send the final
12448 // result if requested...
12449 if (r.resultTo != null) {
12450 try {
12451 if (DEBUG_BROADCAST) {
12452 int seq = r.intent.getIntExtra("seq", -1);
12453 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12454 + " seq=" + seq + " app=" + r.callerApp);
12455 }
12456 performReceive(r.callerApp, r.resultTo,
12457 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012458 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012459 } catch (RemoteException e) {
12460 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12461 }
12462 }
12463
12464 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12465 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12466
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012467 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12468 + r);
12469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012470 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012471 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012472 mOrderedBroadcasts.remove(0);
12473 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012474 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012475 continue;
12476 }
12477 } while (r == null);
12478
12479 // Get the next receiver...
12480 int recIdx = r.nextReceiver++;
12481
12482 // Keep track of when this receiver started, and make sure there
12483 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012484 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012485 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012486 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012487
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012488 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12489 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012490 if (DEBUG_BROADCAST) Log.v(TAG,
12491 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012492 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012493 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012494 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012495 }
12496
12497 Object nextReceiver = r.receivers.get(recIdx);
12498 if (nextReceiver instanceof BroadcastFilter) {
12499 // Simple case: this is a registered receiver who gets
12500 // a direct call.
12501 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12502 if (DEBUG_BROADCAST) Log.v(TAG,
12503 "Delivering serialized to registered "
12504 + filter + ": " + r);
12505 deliverToRegisteredReceiver(r, filter, r.ordered);
12506 if (r.receiver == null || !r.ordered) {
12507 // The receiver has already finished, so schedule to
12508 // process the next one.
12509 r.state = BroadcastRecord.IDLE;
12510 scheduleBroadcastsLocked();
12511 }
12512 return;
12513 }
12514
12515 // Hard case: need to instantiate the receiver, possibly
12516 // starting its application process to host it.
12517
12518 ResolveInfo info =
12519 (ResolveInfo)nextReceiver;
12520
12521 boolean skip = false;
12522 int perm = checkComponentPermission(info.activityInfo.permission,
12523 r.callingPid, r.callingUid,
12524 info.activityInfo.exported
12525 ? -1 : info.activityInfo.applicationInfo.uid);
12526 if (perm != PackageManager.PERMISSION_GRANTED) {
12527 Log.w(TAG, "Permission Denial: broadcasting "
12528 + r.intent.toString()
12529 + " from " + r.callerPackage + " (pid=" + r.callingPid
12530 + ", uid=" + r.callingUid + ")"
12531 + " requires " + info.activityInfo.permission
12532 + " due to receiver " + info.activityInfo.packageName
12533 + "/" + info.activityInfo.name);
12534 skip = true;
12535 }
12536 if (r.callingUid != Process.SYSTEM_UID &&
12537 r.requiredPermission != null) {
12538 try {
12539 perm = ActivityThread.getPackageManager().
12540 checkPermission(r.requiredPermission,
12541 info.activityInfo.applicationInfo.packageName);
12542 } catch (RemoteException e) {
12543 perm = PackageManager.PERMISSION_DENIED;
12544 }
12545 if (perm != PackageManager.PERMISSION_GRANTED) {
12546 Log.w(TAG, "Permission Denial: receiving "
12547 + r.intent + " to "
12548 + info.activityInfo.applicationInfo.packageName
12549 + " requires " + r.requiredPermission
12550 + " due to sender " + r.callerPackage
12551 + " (uid " + r.callingUid + ")");
12552 skip = true;
12553 }
12554 }
12555 if (r.curApp != null && r.curApp.crashing) {
12556 // If the target process is crashing, just skip it.
12557 skip = true;
12558 }
12559
12560 if (skip) {
12561 r.receiver = null;
12562 r.curFilter = null;
12563 r.state = BroadcastRecord.IDLE;
12564 scheduleBroadcastsLocked();
12565 return;
12566 }
12567
12568 r.state = BroadcastRecord.APP_RECEIVE;
12569 String targetProcess = info.activityInfo.processName;
12570 r.curComponent = new ComponentName(
12571 info.activityInfo.applicationInfo.packageName,
12572 info.activityInfo.name);
12573 r.curReceiver = info.activityInfo;
12574
12575 // Is this receiver's application already running?
12576 ProcessRecord app = getProcessRecordLocked(targetProcess,
12577 info.activityInfo.applicationInfo.uid);
12578 if (app != null && app.thread != null) {
12579 try {
12580 processCurBroadcastLocked(r, app);
12581 return;
12582 } catch (RemoteException e) {
12583 Log.w(TAG, "Exception when sending broadcast to "
12584 + r.curComponent, e);
12585 }
12586
12587 // If a dead object exception was thrown -- fall through to
12588 // restart the application.
12589 }
12590
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012591 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012592 if ((r.curApp=startProcessLocked(targetProcess,
12593 info.activityInfo.applicationInfo, true,
12594 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012595 "broadcast", r.curComponent,
12596 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12597 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012598 // Ah, this recipient is unavailable. Finish it if necessary,
12599 // and mark the broadcast record as ready for the next.
12600 Log.w(TAG, "Unable to launch app "
12601 + info.activityInfo.applicationInfo.packageName + "/"
12602 + info.activityInfo.applicationInfo.uid + " for broadcast "
12603 + r.intent + ": process is bad");
12604 logBroadcastReceiverDiscard(r);
12605 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12606 r.resultExtras, r.resultAbort, true);
12607 scheduleBroadcastsLocked();
12608 r.state = BroadcastRecord.IDLE;
12609 return;
12610 }
12611
12612 mPendingBroadcast = r;
12613 }
12614 }
12615
12616 // =========================================================
12617 // INSTRUMENTATION
12618 // =========================================================
12619
12620 public boolean startInstrumentation(ComponentName className,
12621 String profileFile, int flags, Bundle arguments,
12622 IInstrumentationWatcher watcher) {
12623 // Refuse possible leaked file descriptors
12624 if (arguments != null && arguments.hasFileDescriptors()) {
12625 throw new IllegalArgumentException("File descriptors passed in Bundle");
12626 }
12627
12628 synchronized(this) {
12629 InstrumentationInfo ii = null;
12630 ApplicationInfo ai = null;
12631 try {
12632 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012633 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012634 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012635 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012636 } catch (PackageManager.NameNotFoundException e) {
12637 }
12638 if (ii == null) {
12639 reportStartInstrumentationFailure(watcher, className,
12640 "Unable to find instrumentation info for: " + className);
12641 return false;
12642 }
12643 if (ai == null) {
12644 reportStartInstrumentationFailure(watcher, className,
12645 "Unable to find instrumentation target package: " + ii.targetPackage);
12646 return false;
12647 }
12648
12649 int match = mContext.getPackageManager().checkSignatures(
12650 ii.targetPackage, ii.packageName);
12651 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12652 String msg = "Permission Denial: starting instrumentation "
12653 + className + " from pid="
12654 + Binder.getCallingPid()
12655 + ", uid=" + Binder.getCallingPid()
12656 + " not allowed because package " + ii.packageName
12657 + " does not have a signature matching the target "
12658 + ii.targetPackage;
12659 reportStartInstrumentationFailure(watcher, className, msg);
12660 throw new SecurityException(msg);
12661 }
12662
12663 final long origId = Binder.clearCallingIdentity();
12664 uninstallPackageLocked(ii.targetPackage, -1, true);
12665 ProcessRecord app = addAppLocked(ai);
12666 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012667 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012668 app.instrumentationProfileFile = profileFile;
12669 app.instrumentationArguments = arguments;
12670 app.instrumentationWatcher = watcher;
12671 app.instrumentationResultClass = className;
12672 Binder.restoreCallingIdentity(origId);
12673 }
12674
12675 return true;
12676 }
12677
12678 /**
12679 * Report errors that occur while attempting to start Instrumentation. Always writes the
12680 * error to the logs, but if somebody is watching, send the report there too. This enables
12681 * the "am" command to report errors with more information.
12682 *
12683 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12684 * @param cn The component name of the instrumentation.
12685 * @param report The error report.
12686 */
12687 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12688 ComponentName cn, String report) {
12689 Log.w(TAG, report);
12690 try {
12691 if (watcher != null) {
12692 Bundle results = new Bundle();
12693 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12694 results.putString("Error", report);
12695 watcher.instrumentationStatus(cn, -1, results);
12696 }
12697 } catch (RemoteException e) {
12698 Log.w(TAG, e);
12699 }
12700 }
12701
12702 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12703 if (app.instrumentationWatcher != null) {
12704 try {
12705 // NOTE: IInstrumentationWatcher *must* be oneway here
12706 app.instrumentationWatcher.instrumentationFinished(
12707 app.instrumentationClass,
12708 resultCode,
12709 results);
12710 } catch (RemoteException e) {
12711 }
12712 }
12713 app.instrumentationWatcher = null;
12714 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012715 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012716 app.instrumentationProfileFile = null;
12717 app.instrumentationArguments = null;
12718
12719 uninstallPackageLocked(app.processName, -1, false);
12720 }
12721
12722 public void finishInstrumentation(IApplicationThread target,
12723 int resultCode, Bundle results) {
12724 // Refuse possible leaked file descriptors
12725 if (results != null && results.hasFileDescriptors()) {
12726 throw new IllegalArgumentException("File descriptors passed in Intent");
12727 }
12728
12729 synchronized(this) {
12730 ProcessRecord app = getRecordForAppLocked(target);
12731 if (app == null) {
12732 Log.w(TAG, "finishInstrumentation: no app for " + target);
12733 return;
12734 }
12735 final long origId = Binder.clearCallingIdentity();
12736 finishInstrumentationLocked(app, resultCode, results);
12737 Binder.restoreCallingIdentity(origId);
12738 }
12739 }
12740
12741 // =========================================================
12742 // CONFIGURATION
12743 // =========================================================
12744
12745 public ConfigurationInfo getDeviceConfigurationInfo() {
12746 ConfigurationInfo config = new ConfigurationInfo();
12747 synchronized (this) {
12748 config.reqTouchScreen = mConfiguration.touchscreen;
12749 config.reqKeyboardType = mConfiguration.keyboard;
12750 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012751 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12752 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012753 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12754 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012755 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12756 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012757 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12758 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012759 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012760 }
12761 return config;
12762 }
12763
12764 public Configuration getConfiguration() {
12765 Configuration ci;
12766 synchronized(this) {
12767 ci = new Configuration(mConfiguration);
12768 }
12769 return ci;
12770 }
12771
12772 public void updateConfiguration(Configuration values) {
12773 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12774 "updateConfiguration()");
12775
12776 synchronized(this) {
12777 if (values == null && mWindowManager != null) {
12778 // sentinel: fetch the current configuration from the window manager
12779 values = mWindowManager.computeNewConfiguration();
12780 }
12781
12782 final long origId = Binder.clearCallingIdentity();
12783 updateConfigurationLocked(values, null);
12784 Binder.restoreCallingIdentity(origId);
12785 }
12786 }
12787
12788 /**
12789 * Do either or both things: (1) change the current configuration, and (2)
12790 * make sure the given activity is running with the (now) current
12791 * configuration. Returns true if the activity has been left running, or
12792 * false if <var>starting</var> is being destroyed to match the new
12793 * configuration.
12794 */
12795 public boolean updateConfigurationLocked(Configuration values,
12796 HistoryRecord starting) {
12797 int changes = 0;
12798
12799 boolean kept = true;
12800
12801 if (values != null) {
12802 Configuration newConfig = new Configuration(mConfiguration);
12803 changes = newConfig.updateFrom(values);
12804 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012805 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012806 Log.i(TAG, "Updating configuration to: " + values);
12807 }
12808
12809 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12810
12811 if (values.locale != null) {
12812 saveLocaleLocked(values.locale,
12813 !values.locale.equals(mConfiguration.locale),
12814 values.userSetLocale);
12815 }
12816
12817 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012818 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012819
12820 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12821 msg.obj = new Configuration(mConfiguration);
12822 mHandler.sendMessage(msg);
12823
12824 final int N = mLRUProcesses.size();
12825 for (int i=0; i<N; i++) {
12826 ProcessRecord app = mLRUProcesses.get(i);
12827 try {
12828 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012829 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12830 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012831 app.thread.scheduleConfigurationChanged(mConfiguration);
12832 }
12833 } catch (Exception e) {
12834 }
12835 }
12836 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12837 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12838 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012839
12840 AttributeCache ac = AttributeCache.instance();
12841 if (ac != null) {
12842 ac.updateConfiguration(mConfiguration);
12843 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012844 }
12845 }
12846
12847 if (changes != 0 && starting == null) {
12848 // If the configuration changed, and the caller is not already
12849 // in the process of starting an activity, then find the top
12850 // activity to check if its configuration needs to change.
12851 starting = topRunningActivityLocked(null);
12852 }
12853
12854 if (starting != null) {
12855 kept = ensureActivityConfigurationLocked(starting, changes);
12856 if (kept) {
12857 // If this didn't result in the starting activity being
12858 // destroyed, then we need to make sure at this point that all
12859 // other activities are made visible.
12860 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12861 + ", ensuring others are correct.");
12862 ensureActivitiesVisibleLocked(starting, changes);
12863 }
12864 }
12865
12866 return kept;
12867 }
12868
12869 private final boolean relaunchActivityLocked(HistoryRecord r,
12870 int changes, boolean andResume) {
12871 List<ResultInfo> results = null;
12872 List<Intent> newIntents = null;
12873 if (andResume) {
12874 results = r.results;
12875 newIntents = r.newIntents;
12876 }
12877 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12878 + " with results=" + results + " newIntents=" + newIntents
12879 + " andResume=" + andResume);
12880 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12881 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12882 r.task.taskId, r.shortComponentName);
12883
12884 r.startFreezingScreenLocked(r.app, 0);
12885
12886 try {
12887 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12888 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12889 changes, !andResume);
12890 // Note: don't need to call pauseIfSleepingLocked() here, because
12891 // the caller will only pass in 'andResume' if this activity is
12892 // currently resumed, which implies we aren't sleeping.
12893 } catch (RemoteException e) {
12894 return false;
12895 }
12896
12897 if (andResume) {
12898 r.results = null;
12899 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012900 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012901 }
12902
12903 return true;
12904 }
12905
12906 /**
12907 * Make sure the given activity matches the current configuration. Returns
12908 * false if the activity had to be destroyed. Returns true if the
12909 * configuration is the same, or the activity will remain running as-is
12910 * for whatever reason. Ensures the HistoryRecord is updated with the
12911 * correct configuration and all other bookkeeping is handled.
12912 */
12913 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12914 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012915 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12916 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012917
12918 // Short circuit: if the two configurations are the exact same
12919 // object (the common case), then there is nothing to do.
12920 Configuration newConfig = mConfiguration;
12921 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012922 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12923 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012924 return true;
12925 }
12926
12927 // We don't worry about activities that are finishing.
12928 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012929 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012930 "Configuration doesn't matter in finishing " + r);
12931 r.stopFreezingScreenLocked(false);
12932 return true;
12933 }
12934
12935 // Okay we now are going to make this activity have the new config.
12936 // But then we need to figure out how it needs to deal with that.
12937 Configuration oldConfig = r.configuration;
12938 r.configuration = newConfig;
12939
12940 // If the activity isn't currently running, just leave the new
12941 // configuration and it will pick that up next time it starts.
12942 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012943 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012944 "Configuration doesn't matter not running " + r);
12945 r.stopFreezingScreenLocked(false);
12946 return true;
12947 }
12948
12949 // If the activity isn't persistent, there is a chance we will
12950 // need to restart it.
12951 if (!r.persistent) {
12952
12953 // Figure out what has changed between the two configurations.
12954 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012955 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
12956 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012957 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012958 + Integer.toHexString(r.info.configChanges)
12959 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012960 }
12961 if ((changes&(~r.info.configChanges)) != 0) {
12962 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12963 r.configChangeFlags |= changes;
12964 r.startFreezingScreenLocked(r.app, globalChanges);
12965 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012966 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12967 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012968 destroyActivityLocked(r, true);
12969 } else if (r.state == ActivityState.PAUSING) {
12970 // A little annoying: we are waiting for this activity to
12971 // finish pausing. Let's not do anything now, but just
12972 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012973 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12974 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012975 r.configDestroy = true;
12976 return true;
12977 } else if (r.state == ActivityState.RESUMED) {
12978 // Try to optimize this case: the configuration is changing
12979 // and we need to restart the top, resumed activity.
12980 // Instead of doing the normal handshaking, just say
12981 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012982 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12983 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012984 relaunchActivityLocked(r, r.configChangeFlags, true);
12985 r.configChangeFlags = 0;
12986 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012987 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12988 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012989 relaunchActivityLocked(r, r.configChangeFlags, false);
12990 r.configChangeFlags = 0;
12991 }
12992
12993 // All done... tell the caller we weren't able to keep this
12994 // activity around.
12995 return false;
12996 }
12997 }
12998
12999 // Default case: the activity can handle this new configuration, so
13000 // hand it over. Note that we don't need to give it the new
13001 // configuration, since we always send configuration changes to all
13002 // process when they happen so it can just use whatever configuration
13003 // it last got.
13004 if (r.app != null && r.app.thread != null) {
13005 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013006 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013007 r.app.thread.scheduleActivityConfigurationChanged(r);
13008 } catch (RemoteException e) {
13009 // If process died, whatever.
13010 }
13011 }
13012 r.stopFreezingScreenLocked(false);
13013
13014 return true;
13015 }
13016
13017 /**
13018 * Save the locale. You must be inside a synchronized (this) block.
13019 */
13020 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13021 if(isDiff) {
13022 SystemProperties.set("user.language", l.getLanguage());
13023 SystemProperties.set("user.region", l.getCountry());
13024 }
13025
13026 if(isPersist) {
13027 SystemProperties.set("persist.sys.language", l.getLanguage());
13028 SystemProperties.set("persist.sys.country", l.getCountry());
13029 SystemProperties.set("persist.sys.localevar", l.getVariant());
13030 }
13031 }
13032
13033 // =========================================================
13034 // LIFETIME MANAGEMENT
13035 // =========================================================
13036
13037 private final int computeOomAdjLocked(
13038 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13039 if (mAdjSeq == app.adjSeq) {
13040 // This adjustment has already been computed.
13041 return app.curAdj;
13042 }
13043
13044 if (app.thread == null) {
13045 app.adjSeq = mAdjSeq;
13046 return (app.curAdj=EMPTY_APP_ADJ);
13047 }
13048
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013049 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13050 // The max adjustment doesn't allow this app to be anything
13051 // below foreground, so it is not worth doing work for it.
13052 app.adjType = "fixed";
13053 app.adjSeq = mAdjSeq;
13054 app.curRawAdj = app.maxAdj;
13055 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13056 return (app.curAdj=app.maxAdj);
13057 }
13058
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013059 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013060 app.adjSource = null;
13061 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013062
The Android Open Source Project4df24232009-03-05 14:34:35 -080013063 // Determine the importance of the process, starting with most
13064 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013065 int adj;
13066 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013067 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013068 // The last app on the list is the foreground app.
13069 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013070 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013071 } else if (app.instrumentationClass != null) {
13072 // Don't want to kill running instrumentation.
13073 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013074 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013075 } else if (app.persistentActivities > 0) {
13076 // Special persistent activities... shouldn't be used these days.
13077 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013078 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013079 } else if (app.curReceiver != null ||
13080 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13081 // An app that is currently receiving a broadcast also
13082 // counts as being in the foreground.
13083 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013084 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013085 } else if (app.executingServices.size() > 0) {
13086 // An app that is currently executing a service callback also
13087 // counts as being in the foreground.
13088 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013089 app.adjType = "exec-service";
13090 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013091 // The user is aware of this app, so make it visible.
13092 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013093 app.adjType = "foreground-service";
13094 } else if (app.forcingToForeground != null) {
13095 // The user is aware of this app, so make it visible.
13096 adj = VISIBLE_APP_ADJ;
13097 app.adjType = "force-foreground";
13098 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013099 } else if (app == mHomeProcess) {
13100 // This process is hosting what we currently consider to be the
13101 // home app, so we don't want to let it go into the background.
13102 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013103 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013104 } else if ((N=app.activities.size()) != 0) {
13105 // This app is in the background with paused activities.
13106 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013107 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013108 for (int j=0; j<N; j++) {
13109 if (((HistoryRecord)app.activities.get(j)).visible) {
13110 // This app has a visible activity!
13111 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013112 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013113 break;
13114 }
13115 }
13116 } else {
13117 // A very not-needed process.
13118 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013119 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013120 }
13121
The Android Open Source Project4df24232009-03-05 14:34:35 -080013122 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013123 // there are applications dependent on our services or providers, but
13124 // this gives us a baseline and makes sure we don't get into an
13125 // infinite recursion.
13126 app.adjSeq = mAdjSeq;
13127 app.curRawAdj = adj;
13128 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13129
Christopher Tate6fa95972009-06-05 18:43:55 -070013130 if (mBackupTarget != null && app == mBackupTarget.app) {
13131 // If possible we want to avoid killing apps while they're being backed up
13132 if (adj > BACKUP_APP_ADJ) {
13133 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13134 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013135 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013136 }
13137 }
13138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013139 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013140 final long now = SystemClock.uptimeMillis();
13141 // This process is more important if the top activity is
13142 // bound to the service.
13143 Iterator jt = app.services.iterator();
13144 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13145 ServiceRecord s = (ServiceRecord)jt.next();
13146 if (s.startRequested) {
13147 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13148 // This service has seen some activity within
13149 // recent memory, so we will keep its process ahead
13150 // of the background processes.
13151 if (adj > SECONDARY_SERVER_ADJ) {
13152 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013153 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013154 }
13155 }
13156 }
13157 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13158 Iterator<ConnectionRecord> kt
13159 = s.connections.values().iterator();
13160 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13161 // XXX should compute this based on the max of
13162 // all connected clients.
13163 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013164 if (cr.binding.client == app) {
13165 // Binding to ourself is not interesting.
13166 continue;
13167 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013168 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13169 ProcessRecord client = cr.binding.client;
13170 int myHiddenAdj = hiddenAdj;
13171 if (myHiddenAdj > client.hiddenAdj) {
13172 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13173 myHiddenAdj = client.hiddenAdj;
13174 } else {
13175 myHiddenAdj = VISIBLE_APP_ADJ;
13176 }
13177 }
13178 int clientAdj = computeOomAdjLocked(
13179 client, myHiddenAdj, TOP_APP);
13180 if (adj > clientAdj) {
13181 adj = clientAdj > VISIBLE_APP_ADJ
13182 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013183 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013184 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13185 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013186 app.adjSource = cr.binding.client;
13187 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013188 }
13189 }
13190 HistoryRecord a = cr.activity;
13191 //if (a != null) {
13192 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13193 //}
13194 if (a != null && adj > FOREGROUND_APP_ADJ &&
13195 (a.state == ActivityState.RESUMED
13196 || a.state == ActivityState.PAUSING)) {
13197 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013198 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013199 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13200 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013201 app.adjSource = a;
13202 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013203 }
13204 }
13205 }
13206 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013207
13208 // Finally, f this process has active services running in it, we
13209 // would like to avoid killing it unless it would prevent the current
13210 // application from running. By default we put the process in
13211 // with the rest of the background processes; as we scan through
13212 // its services we may bump it up from there.
13213 if (adj > hiddenAdj) {
13214 adj = hiddenAdj;
13215 app.adjType = "bg-services";
13216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013217 }
13218
13219 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013220 Iterator jt = app.pubProviders.values().iterator();
13221 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13222 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13223 if (cpr.clients.size() != 0) {
13224 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13225 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13226 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013227 if (client == app) {
13228 // Being our own client is not interesting.
13229 continue;
13230 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013231 int myHiddenAdj = hiddenAdj;
13232 if (myHiddenAdj > client.hiddenAdj) {
13233 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13234 myHiddenAdj = client.hiddenAdj;
13235 } else {
13236 myHiddenAdj = FOREGROUND_APP_ADJ;
13237 }
13238 }
13239 int clientAdj = computeOomAdjLocked(
13240 client, myHiddenAdj, TOP_APP);
13241 if (adj > clientAdj) {
13242 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013243 ? clientAdj : FOREGROUND_APP_ADJ;
13244 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013245 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13246 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013247 app.adjSource = client;
13248 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013249 }
13250 }
13251 }
13252 // If the provider has external (non-framework) process
13253 // dependencies, ensure that its adjustment is at least
13254 // FOREGROUND_APP_ADJ.
13255 if (cpr.externals != 0) {
13256 if (adj > FOREGROUND_APP_ADJ) {
13257 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013258 app.adjType = "provider";
13259 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013260 }
13261 }
13262 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013263
13264 // Finally, if this process has published any content providers,
13265 // then its adjustment makes it at least as important as any of the
13266 // processes using those providers, and no less important than
13267 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13268 if (adj > CONTENT_PROVIDER_ADJ) {
13269 adj = CONTENT_PROVIDER_ADJ;
13270 app.adjType = "pub-providers";
13271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013272 }
13273
13274 app.curRawAdj = adj;
13275
13276 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13277 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13278 if (adj > app.maxAdj) {
13279 adj = app.maxAdj;
13280 }
13281
13282 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013283 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013284 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13285 : Process.THREAD_GROUP_DEFAULT;
13286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013287 return adj;
13288 }
13289
13290 /**
13291 * Ask a given process to GC right now.
13292 */
13293 final void performAppGcLocked(ProcessRecord app) {
13294 try {
13295 app.lastRequestedGc = SystemClock.uptimeMillis();
13296 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013297 if (app.reportLowMemory) {
13298 app.reportLowMemory = false;
13299 app.thread.scheduleLowMemory();
13300 } else {
13301 app.thread.processInBackground();
13302 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013303 }
13304 } catch (Exception e) {
13305 // whatever.
13306 }
13307 }
13308
13309 /**
13310 * Returns true if things are idle enough to perform GCs.
13311 */
13312 private final boolean canGcNow() {
13313 return mParallelBroadcasts.size() == 0
13314 && mOrderedBroadcasts.size() == 0
13315 && (mSleeping || (mResumedActivity != null &&
13316 mResumedActivity.idle));
13317 }
13318
13319 /**
13320 * Perform GCs on all processes that are waiting for it, but only
13321 * if things are idle.
13322 */
13323 final void performAppGcsLocked() {
13324 final int N = mProcessesToGc.size();
13325 if (N <= 0) {
13326 return;
13327 }
13328 if (canGcNow()) {
13329 while (mProcessesToGc.size() > 0) {
13330 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013331 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13332 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13333 <= SystemClock.uptimeMillis()) {
13334 // To avoid spamming the system, we will GC processes one
13335 // at a time, waiting a few seconds between each.
13336 performAppGcLocked(proc);
13337 scheduleAppGcsLocked();
13338 return;
13339 } else {
13340 // It hasn't been long enough since we last GCed this
13341 // process... put it in the list to wait for its time.
13342 addProcessToGcListLocked(proc);
13343 break;
13344 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013345 }
13346 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013347
13348 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013349 }
13350 }
13351
13352 /**
13353 * If all looks good, perform GCs on all processes waiting for them.
13354 */
13355 final void performAppGcsIfAppropriateLocked() {
13356 if (canGcNow()) {
13357 performAppGcsLocked();
13358 return;
13359 }
13360 // Still not idle, wait some more.
13361 scheduleAppGcsLocked();
13362 }
13363
13364 /**
13365 * Schedule the execution of all pending app GCs.
13366 */
13367 final void scheduleAppGcsLocked() {
13368 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013369
13370 if (mProcessesToGc.size() > 0) {
13371 // Schedule a GC for the time to the next process.
13372 ProcessRecord proc = mProcessesToGc.get(0);
13373 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13374
13375 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13376 long now = SystemClock.uptimeMillis();
13377 if (when < (now+GC_TIMEOUT)) {
13378 when = now + GC_TIMEOUT;
13379 }
13380 mHandler.sendMessageAtTime(msg, when);
13381 }
13382 }
13383
13384 /**
13385 * Add a process to the array of processes waiting to be GCed. Keeps the
13386 * list in sorted order by the last GC time. The process can't already be
13387 * on the list.
13388 */
13389 final void addProcessToGcListLocked(ProcessRecord proc) {
13390 boolean added = false;
13391 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13392 if (mProcessesToGc.get(i).lastRequestedGc <
13393 proc.lastRequestedGc) {
13394 added = true;
13395 mProcessesToGc.add(i+1, proc);
13396 break;
13397 }
13398 }
13399 if (!added) {
13400 mProcessesToGc.add(0, proc);
13401 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013402 }
13403
13404 /**
13405 * Set up to ask a process to GC itself. This will either do it
13406 * immediately, or put it on the list of processes to gc the next
13407 * time things are idle.
13408 */
13409 final void scheduleAppGcLocked(ProcessRecord app) {
13410 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013411 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013412 return;
13413 }
13414 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013415 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013416 scheduleAppGcsLocked();
13417 }
13418 }
13419
13420 private final boolean updateOomAdjLocked(
13421 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13422 app.hiddenAdj = hiddenAdj;
13423
13424 if (app.thread == null) {
13425 return true;
13426 }
13427
13428 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013430 if (app.pid != 0 && app.pid != MY_PID) {
13431 if (app.curRawAdj != app.setRawAdj) {
13432 if (app.curRawAdj > FOREGROUND_APP_ADJ
13433 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13434 // If this app is transitioning from foreground to
13435 // non-foreground, have it do a gc.
13436 scheduleAppGcLocked(app);
13437 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13438 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13439 // Likewise do a gc when an app is moving in to the
13440 // background (such as a service stopping).
13441 scheduleAppGcLocked(app);
13442 }
13443 app.setRawAdj = app.curRawAdj;
13444 }
13445 if (adj != app.setAdj) {
13446 if (Process.setOomAdj(app.pid, adj)) {
13447 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13448 TAG, "Set app " + app.processName +
13449 " oom adj to " + adj);
13450 app.setAdj = adj;
13451 } else {
13452 return false;
13453 }
13454 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013455 if (app.setSchedGroup != app.curSchedGroup) {
13456 app.setSchedGroup = app.curSchedGroup;
13457 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13458 "Setting process group of " + app.processName
13459 + " to " + app.curSchedGroup);
13460 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013461 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013462 try {
13463 Process.setProcessGroup(app.pid, app.curSchedGroup);
13464 } catch (Exception e) {
13465 Log.w(TAG, "Failed setting process group of " + app.pid
13466 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013467 e.printStackTrace();
13468 } finally {
13469 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013470 }
13471 }
13472 if (false) {
13473 if (app.thread != null) {
13474 try {
13475 app.thread.setSchedulingGroup(app.curSchedGroup);
13476 } catch (RemoteException e) {
13477 }
13478 }
13479 }
13480 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013481 }
13482
13483 return true;
13484 }
13485
13486 private final HistoryRecord resumedAppLocked() {
13487 HistoryRecord resumedActivity = mResumedActivity;
13488 if (resumedActivity == null || resumedActivity.app == null) {
13489 resumedActivity = mPausingActivity;
13490 if (resumedActivity == null || resumedActivity.app == null) {
13491 resumedActivity = topRunningActivityLocked(null);
13492 }
13493 }
13494 return resumedActivity;
13495 }
13496
13497 private final boolean updateOomAdjLocked(ProcessRecord app) {
13498 final HistoryRecord TOP_ACT = resumedAppLocked();
13499 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13500 int curAdj = app.curAdj;
13501 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13502 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13503
13504 mAdjSeq++;
13505
13506 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13507 if (res) {
13508 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13509 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13510 if (nowHidden != wasHidden) {
13511 // Changed to/from hidden state, so apps after it in the LRU
13512 // list may also be changed.
13513 updateOomAdjLocked();
13514 }
13515 }
13516 return res;
13517 }
13518
13519 private final boolean updateOomAdjLocked() {
13520 boolean didOomAdj = true;
13521 final HistoryRecord TOP_ACT = resumedAppLocked();
13522 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13523
13524 if (false) {
13525 RuntimeException e = new RuntimeException();
13526 e.fillInStackTrace();
13527 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13528 }
13529
13530 mAdjSeq++;
13531
13532 // First try updating the OOM adjustment for each of the
13533 // application processes based on their current state.
13534 int i = mLRUProcesses.size();
13535 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13536 while (i > 0) {
13537 i--;
13538 ProcessRecord app = mLRUProcesses.get(i);
13539 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13540 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13541 && app.curAdj == curHiddenAdj) {
13542 curHiddenAdj++;
13543 }
13544 } else {
13545 didOomAdj = false;
13546 }
13547 }
13548
13549 // todo: for now pretend like OOM ADJ didn't work, because things
13550 // aren't behaving as expected on Linux -- it's not killing processes.
13551 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13552 }
13553
13554 private final void trimApplications() {
13555 synchronized (this) {
13556 int i;
13557
13558 // First remove any unused application processes whose package
13559 // has been removed.
13560 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13561 final ProcessRecord app = mRemovedProcesses.get(i);
13562 if (app.activities.size() == 0
13563 && app.curReceiver == null && app.services.size() == 0) {
13564 Log.i(
13565 TAG, "Exiting empty application process "
13566 + app.processName + " ("
13567 + (app.thread != null ? app.thread.asBinder() : null)
13568 + ")\n");
13569 if (app.pid > 0 && app.pid != MY_PID) {
13570 Process.killProcess(app.pid);
13571 } else {
13572 try {
13573 app.thread.scheduleExit();
13574 } catch (Exception e) {
13575 // Ignore exceptions.
13576 }
13577 }
13578 cleanUpApplicationRecordLocked(app, false, -1);
13579 mRemovedProcesses.remove(i);
13580
13581 if (app.persistent) {
13582 if (app.persistent) {
13583 addAppLocked(app.info);
13584 }
13585 }
13586 }
13587 }
13588
13589 // Now try updating the OOM adjustment for each of the
13590 // application processes based on their current state.
13591 // If the setOomAdj() API is not supported, then go with our
13592 // back-up plan...
13593 if (!updateOomAdjLocked()) {
13594
13595 // Count how many processes are running services.
13596 int numServiceProcs = 0;
13597 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13598 final ProcessRecord app = mLRUProcesses.get(i);
13599
13600 if (app.persistent || app.services.size() != 0
13601 || app.curReceiver != null
13602 || app.persistentActivities > 0) {
13603 // Don't count processes holding services against our
13604 // maximum process count.
13605 if (localLOGV) Log.v(
13606 TAG, "Not trimming app " + app + " with services: "
13607 + app.services);
13608 numServiceProcs++;
13609 }
13610 }
13611
13612 int curMaxProcs = mProcessLimit;
13613 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13614 if (mAlwaysFinishActivities) {
13615 curMaxProcs = 1;
13616 }
13617 curMaxProcs += numServiceProcs;
13618
13619 // Quit as many processes as we can to get down to the desired
13620 // process count. First remove any processes that no longer
13621 // have activites running in them.
13622 for ( i=0;
13623 i<mLRUProcesses.size()
13624 && mLRUProcesses.size() > curMaxProcs;
13625 i++) {
13626 final ProcessRecord app = mLRUProcesses.get(i);
13627 // Quit an application only if it is not currently
13628 // running any activities.
13629 if (!app.persistent && app.activities.size() == 0
13630 && app.curReceiver == null && app.services.size() == 0) {
13631 Log.i(
13632 TAG, "Exiting empty application process "
13633 + app.processName + " ("
13634 + (app.thread != null ? app.thread.asBinder() : null)
13635 + ")\n");
13636 if (app.pid > 0 && app.pid != MY_PID) {
13637 Process.killProcess(app.pid);
13638 } else {
13639 try {
13640 app.thread.scheduleExit();
13641 } catch (Exception e) {
13642 // Ignore exceptions.
13643 }
13644 }
13645 // todo: For now we assume the application is not buggy
13646 // or evil, and will quit as a result of our request.
13647 // Eventually we need to drive this off of the death
13648 // notification, and kill the process if it takes too long.
13649 cleanUpApplicationRecordLocked(app, false, i);
13650 i--;
13651 }
13652 }
13653
13654 // If we still have too many processes, now from the least
13655 // recently used process we start finishing activities.
13656 if (Config.LOGV) Log.v(
13657 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13658 " of " + curMaxProcs + " processes");
13659 for ( i=0;
13660 i<mLRUProcesses.size()
13661 && mLRUProcesses.size() > curMaxProcs;
13662 i++) {
13663 final ProcessRecord app = mLRUProcesses.get(i);
13664 // Quit the application only if we have a state saved for
13665 // all of its activities.
13666 boolean canQuit = !app.persistent && app.curReceiver == null
13667 && app.services.size() == 0
13668 && app.persistentActivities == 0;
13669 int NUMA = app.activities.size();
13670 int j;
13671 if (Config.LOGV) Log.v(
13672 TAG, "Looking to quit " + app.processName);
13673 for (j=0; j<NUMA && canQuit; j++) {
13674 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13675 if (Config.LOGV) Log.v(
13676 TAG, " " + r.intent.getComponent().flattenToShortString()
13677 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13678 canQuit = (r.haveState || !r.stateNotNeeded)
13679 && !r.visible && r.stopped;
13680 }
13681 if (canQuit) {
13682 // Finish all of the activities, and then the app itself.
13683 for (j=0; j<NUMA; j++) {
13684 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13685 if (!r.finishing) {
13686 destroyActivityLocked(r, false);
13687 }
13688 r.resultTo = null;
13689 }
13690 Log.i(TAG, "Exiting application process "
13691 + app.processName + " ("
13692 + (app.thread != null ? app.thread.asBinder() : null)
13693 + ")\n");
13694 if (app.pid > 0 && app.pid != MY_PID) {
13695 Process.killProcess(app.pid);
13696 } else {
13697 try {
13698 app.thread.scheduleExit();
13699 } catch (Exception e) {
13700 // Ignore exceptions.
13701 }
13702 }
13703 // todo: For now we assume the application is not buggy
13704 // or evil, and will quit as a result of our request.
13705 // Eventually we need to drive this off of the death
13706 // notification, and kill the process if it takes too long.
13707 cleanUpApplicationRecordLocked(app, false, i);
13708 i--;
13709 //dump();
13710 }
13711 }
13712
13713 }
13714
13715 int curMaxActivities = MAX_ACTIVITIES;
13716 if (mAlwaysFinishActivities) {
13717 curMaxActivities = 1;
13718 }
13719
13720 // Finally, if there are too many activities now running, try to
13721 // finish as many as we can to get back down to the limit.
13722 for ( i=0;
13723 i<mLRUActivities.size()
13724 && mLRUActivities.size() > curMaxActivities;
13725 i++) {
13726 final HistoryRecord r
13727 = (HistoryRecord)mLRUActivities.get(i);
13728
13729 // We can finish this one if we have its icicle saved and
13730 // it is not persistent.
13731 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13732 && r.stopped && !r.persistent && !r.finishing) {
13733 final int origSize = mLRUActivities.size();
13734 destroyActivityLocked(r, true);
13735
13736 // This will remove it from the LRU list, so keep
13737 // our index at the same value. Note that this check to
13738 // see if the size changes is just paranoia -- if
13739 // something unexpected happens, we don't want to end up
13740 // in an infinite loop.
13741 if (origSize > mLRUActivities.size()) {
13742 i--;
13743 }
13744 }
13745 }
13746 }
13747 }
13748
13749 /** This method sends the specified signal to each of the persistent apps */
13750 public void signalPersistentProcesses(int sig) throws RemoteException {
13751 if (sig != Process.SIGNAL_USR1) {
13752 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13753 }
13754
13755 synchronized (this) {
13756 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13757 != PackageManager.PERMISSION_GRANTED) {
13758 throw new SecurityException("Requires permission "
13759 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13760 }
13761
13762 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13763 ProcessRecord r = mLRUProcesses.get(i);
13764 if (r.thread != null && r.persistent) {
13765 Process.sendSignal(r.pid, sig);
13766 }
13767 }
13768 }
13769 }
13770
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013771 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013772 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013773
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013774 try {
13775 synchronized (this) {
13776 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13777 // its own permission.
13778 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13779 != PackageManager.PERMISSION_GRANTED) {
13780 throw new SecurityException("Requires permission "
13781 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013782 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013783
13784 if (start && fd == null) {
13785 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013786 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013787
13788 ProcessRecord proc = null;
13789 try {
13790 int pid = Integer.parseInt(process);
13791 synchronized (mPidsSelfLocked) {
13792 proc = mPidsSelfLocked.get(pid);
13793 }
13794 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013795 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013796
13797 if (proc == null) {
13798 HashMap<String, SparseArray<ProcessRecord>> all
13799 = mProcessNames.getMap();
13800 SparseArray<ProcessRecord> procs = all.get(process);
13801 if (procs != null && procs.size() > 0) {
13802 proc = procs.valueAt(0);
13803 }
13804 }
13805
13806 if (proc == null || proc.thread == null) {
13807 throw new IllegalArgumentException("Unknown process: " + process);
13808 }
13809
13810 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13811 if (isSecure) {
13812 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13813 throw new SecurityException("Process not debuggable: " + proc);
13814 }
13815 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013816
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013817 proc.thread.profilerControl(start, path, fd);
13818 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013819 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013820 }
13821 } catch (RemoteException e) {
13822 throw new IllegalStateException("Process disappeared");
13823 } finally {
13824 if (fd != null) {
13825 try {
13826 fd.close();
13827 } catch (IOException e) {
13828 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013829 }
13830 }
13831 }
13832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013833 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13834 public void monitor() {
13835 synchronized (this) { }
13836 }
13837}