blob: 1359f663d1b837d8b6177c15fb41cd2a118a317b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070055import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.server.data.CrashData;
92import android.server.data.StackTraceElementData;
93import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.text.TextUtils;
95import android.util.Config;
96import android.util.EventLog;
97import android.util.Log;
98import android.util.PrintWriterPrinter;
99import android.util.SparseArray;
100import android.view.Gravity;
101import android.view.LayoutInflater;
102import android.view.View;
103import android.view.WindowManager;
104import android.view.WindowManagerPolicy;
105
106import dalvik.system.Zygote;
107
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.ByteArrayInputStream;
109import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200114import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.PrintWriter;
116import java.lang.IllegalStateException;
117import java.lang.ref.WeakReference;
118import java.util.ArrayList;
119import java.util.HashMap;
120import java.util.HashSet;
121import java.util.Iterator;
122import java.util.List;
123import java.util.Locale;
124import java.util.Map;
125
126public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
127 static final String TAG = "ActivityManager";
128 static final boolean DEBUG = false;
129 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
130 static final boolean DEBUG_SWITCH = localLOGV || false;
131 static final boolean DEBUG_TASKS = localLOGV || false;
132 static final boolean DEBUG_PAUSE = localLOGV || false;
133 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
134 static final boolean DEBUG_TRANSITION = localLOGV || false;
135 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700136 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean DEBUG_SERVICE = localLOGV || false;
138 static final boolean DEBUG_VISBILITY = localLOGV || false;
139 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700140 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700142 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700143 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700144 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 static final boolean VALIDATE_TOKENS = false;
146 static final boolean SHOW_ACTIVITY_START_TIME = true;
147
148 // Control over CPU and battery monitoring.
149 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
150 static final boolean MONITOR_CPU_USAGE = true;
151 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
152 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
153 static final boolean MONITOR_THREAD_CPU_USAGE = false;
154
155 // Event log tags
156 static final int LOG_CONFIGURATION_CHANGED = 2719;
157 static final int LOG_CPU = 2721;
158 static final int LOG_AM_FINISH_ACTIVITY = 30001;
159 static final int LOG_TASK_TO_FRONT = 30002;
160 static final int LOG_AM_NEW_INTENT = 30003;
161 static final int LOG_AM_CREATE_TASK = 30004;
162 static final int LOG_AM_CREATE_ACTIVITY = 30005;
163 static final int LOG_AM_RESTART_ACTIVITY = 30006;
164 static final int LOG_AM_RESUME_ACTIVITY = 30007;
165 static final int LOG_ANR = 30008;
166 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
167 static final int LOG_AM_PROCESS_BOUND = 30010;
168 static final int LOG_AM_PROCESS_DIED = 30011;
169 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
170 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
171 static final int LOG_AM_PROCESS_START = 30014;
172 static final int LOG_AM_PROCESS_BAD = 30015;
173 static final int LOG_AM_PROCESS_GOOD = 30016;
174 static final int LOG_AM_LOW_MEMORY = 30017;
175 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
176 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
177 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
178 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
179 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
180 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
181 static final int LOG_AM_CREATE_SERVICE = 30030;
182 static final int LOG_AM_DESTROY_SERVICE = 30031;
183 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
184 static final int LOG_AM_DROP_PROCESS = 30033;
185 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
186 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
187 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
Dianne Hackbornf670ef72009-11-16 13:59:16 -0800188 static final int LOG_AM_PROCESS_START_TIMEOUT = 30037;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
190 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
191 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
192
Dianne Hackborn1655be42009-05-08 14:29:01 -0700193 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700194 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 private static final String SYSTEM_SECURE = "ro.secure";
197
198 // This is the maximum number of application processes we would like
199 // to have running. Due to the asynchronous nature of things, we can
200 // temporarily go beyond this limit.
201 static final int MAX_PROCESSES = 2;
202
203 // Set to false to leave processes running indefinitely, relying on
204 // the kernel killing them as resources are required.
205 static final boolean ENFORCE_PROCESS_LIMIT = false;
206
207 // This is the maximum number of activities that we would like to have
208 // running at a given time.
209 static final int MAX_ACTIVITIES = 20;
210
211 // Maximum number of recent tasks that we can remember.
212 static final int MAX_RECENT_TASKS = 20;
213
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700214 // Amount of time after a call to stopAppSwitches() during which we will
215 // prevent further untrusted switches from happening.
216 static final long APP_SWITCH_DELAY_TIME = 5*1000;
217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 // How long until we reset a task when the user returns to it. Currently
219 // 30 minutes.
220 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
221
222 // Set to true to disable the icon that is shown while a new activity
223 // is being started.
224 static final boolean SHOW_APP_STARTING_ICON = true;
225
226 // How long we wait until giving up on the last activity to pause. This
227 // is short because it directly impacts the responsiveness of starting the
228 // next activity.
229 static final int PAUSE_TIMEOUT = 500;
230
231 /**
232 * How long we can hold the launch wake lock before giving up.
233 */
234 static final int LAUNCH_TIMEOUT = 10*1000;
235
236 // How long we wait for a launched process to attach to the activity manager
237 // before we decide it's never going to come up for real.
238 static final int PROC_START_TIMEOUT = 10*1000;
239
240 // How long we wait until giving up on the last activity telling us it
241 // is idle.
242 static final int IDLE_TIMEOUT = 10*1000;
243
244 // How long to wait after going idle before forcing apps to GC.
245 static final int GC_TIMEOUT = 5*1000;
246
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700247 // The minimum amount of time between successive GC requests for a process.
248 static final int GC_MIN_INTERVAL = 60*1000;
249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 // How long we wait until giving up on an activity telling us it has
251 // finished destroying itself.
252 static final int DESTROY_TIMEOUT = 10*1000;
253
254 // How long we allow a receiver to run before giving up on it.
255 static final int BROADCAST_TIMEOUT = 10*1000;
256
257 // How long we wait for a service to finish executing.
258 static final int SERVICE_TIMEOUT = 20*1000;
259
260 // How long a service needs to be running until restarting its process
261 // is no longer considered to be a relaunch of the service.
262 static final int SERVICE_RESTART_DURATION = 5*1000;
263
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700264 // How long a service needs to be running until it will start back at
265 // SERVICE_RESTART_DURATION after being killed.
266 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
267
268 // Multiplying factor to increase restart duration time by, for each time
269 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
270 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
271
272 // The minimum amount of time between restarting services that we allow.
273 // That is, when multiple services are restarting, we won't allow each
274 // to restart less than this amount of time from the last one.
275 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 // Maximum amount of time for there to be no activity on a service before
278 // we consider it non-essential and allow its process to go on the
279 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700280 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281
282 // How long we wait until we timeout on key dispatching.
283 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
284
285 // The minimum time we allow between crashes, for us to consider this
286 // application to be bad and stop and its services and reject broadcasts.
287 static final int MIN_CRASH_INTERVAL = 60*1000;
288
289 // How long we wait until we timeout on key dispatching during instrumentation.
290 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
291
292 // OOM adjustments for processes in various states:
293
294 // This is a process without anything currently running in it. Definitely
295 // the first to go! Value set in system/rootdir/init.rc on startup.
296 // This value is initalized in the constructor, careful when refering to
297 // this static variable externally.
298 static int EMPTY_APP_ADJ;
299
300 // This is a process with a content provider that does not have any clients
301 // attached to it. If it did have any clients, its adjustment would be the
302 // one for the highest-priority of those processes.
303 static int CONTENT_PROVIDER_ADJ;
304
305 // This is a process only hosting activities that are not visible,
306 // so it can be killed without any disruption. Value set in
307 // system/rootdir/init.rc on startup.
308 final int HIDDEN_APP_MAX_ADJ;
309 static int HIDDEN_APP_MIN_ADJ;
310
The Android Open Source Project4df24232009-03-05 14:34:35 -0800311 // This is a process holding the home application -- we want to try
312 // avoiding killing it, even if it would normally be in the background,
313 // because the user interacts with it so much.
314 final int HOME_APP_ADJ;
315
Christopher Tate6fa95972009-06-05 18:43:55 -0700316 // This is a process currently hosting a backup operation. Killing it
317 // is not entirely fatal but is generally a bad idea.
318 final int BACKUP_APP_ADJ;
319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 // This is a process holding a secondary server -- killing it will not
321 // have much of an impact as far as the user is concerned. Value set in
322 // system/rootdir/init.rc on startup.
323 final int SECONDARY_SERVER_ADJ;
324
325 // This is a process only hosting activities that are visible to the
326 // user, so we'd prefer they don't disappear. Value set in
327 // system/rootdir/init.rc on startup.
328 final int VISIBLE_APP_ADJ;
329
330 // This is the process running the current foreground app. We'd really
331 // rather not kill it! Value set in system/rootdir/init.rc on startup.
332 final int FOREGROUND_APP_ADJ;
333
334 // This is a process running a core server, such as telephony. Definitely
335 // don't want to kill it, but doing so is not completely fatal.
336 static final int CORE_SERVER_ADJ = -12;
337
338 // The system process runs at the default adjustment.
339 static final int SYSTEM_ADJ = -16;
340
341 // Memory pages are 4K.
342 static final int PAGE_SIZE = 4*1024;
343
Jacek Surazski82a73df2009-06-17 14:33:18 +0200344 // System property defining error report receiver for system apps
345 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
346
347 // System property defining default error report receiver
348 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 // Corresponding memory levels for above adjustments.
351 final int EMPTY_APP_MEM;
352 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800353 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700354 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 final int SECONDARY_SERVER_MEM;
356 final int VISIBLE_APP_MEM;
357 final int FOREGROUND_APP_MEM;
358
359 final int MY_PID;
360
361 static final String[] EMPTY_STRING_ARRAY = new String[0];
362
363 enum ActivityState {
364 INITIALIZING,
365 RESUMED,
366 PAUSING,
367 PAUSED,
368 STOPPING,
369 STOPPED,
370 FINISHING,
371 DESTROYING,
372 DESTROYED
373 }
374
375 /**
376 * The back history of all previous (and possibly still
377 * running) activities. It contains HistoryRecord objects.
378 */
379 final ArrayList mHistory = new ArrayList();
380
381 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700382 * Description of a request to start a new activity, which has been held
383 * due to app switches being disabled.
384 */
385 class PendingActivityLaunch {
386 HistoryRecord r;
387 HistoryRecord sourceRecord;
388 Uri[] grantedUriPermissions;
389 int grantedMode;
390 boolean onlyIfNeeded;
391 }
392
393 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
394 = new ArrayList<PendingActivityLaunch>();
395
396 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 * List of all active broadcasts that are to be executed immediately
398 * (without waiting for another broadcast to finish). Currently this only
399 * contains broadcasts to registered receivers, to avoid spinning up
400 * a bunch of processes to execute IntentReceiver components.
401 */
402 final ArrayList<BroadcastRecord> mParallelBroadcasts
403 = new ArrayList<BroadcastRecord>();
404
405 /**
406 * List of all active broadcasts that are to be executed one at a time.
407 * The object at the top of the list is the currently activity broadcasts;
408 * those after it are waiting for the top to finish..
409 */
410 final ArrayList<BroadcastRecord> mOrderedBroadcasts
411 = new ArrayList<BroadcastRecord>();
412
413 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800414 * Historical data of past broadcasts, for debugging.
415 */
416 static final int MAX_BROADCAST_HISTORY = 100;
417 final BroadcastRecord[] mBroadcastHistory
418 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
419
420 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 * Set when we current have a BROADCAST_INTENT_MSG in flight.
422 */
423 boolean mBroadcastsScheduled = false;
424
425 /**
426 * Set to indicate whether to issue an onUserLeaving callback when a
427 * newly launched activity is being brought in front of us.
428 */
429 boolean mUserLeaving = false;
430
431 /**
432 * When we are in the process of pausing an activity, before starting the
433 * next one, this variable holds the activity that is currently being paused.
434 */
435 HistoryRecord mPausingActivity = null;
436
437 /**
438 * Current activity that is resumed, or null if there is none.
439 */
440 HistoryRecord mResumedActivity = null;
441
442 /**
443 * Activity we have told the window manager to have key focus.
444 */
445 HistoryRecord mFocusedActivity = null;
446
447 /**
448 * This is the last activity that we put into the paused state. This is
449 * used to determine if we need to do an activity transition while sleeping,
450 * when we normally hold the top activity paused.
451 */
452 HistoryRecord mLastPausedActivity = null;
453
454 /**
455 * List of activities that are waiting for a new activity
456 * to become visible before completing whatever operation they are
457 * supposed to do.
458 */
459 final ArrayList mWaitingVisibleActivities = new ArrayList();
460
461 /**
462 * List of activities that are ready to be stopped, but waiting
463 * for the next activity to settle down before doing so. It contains
464 * HistoryRecord objects.
465 */
466 final ArrayList<HistoryRecord> mStoppingActivities
467 = new ArrayList<HistoryRecord>();
468
469 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700470 * Animations that for the current transition have requested not to
471 * be considered for the transition animation.
472 */
473 final ArrayList<HistoryRecord> mNoAnimActivities
474 = new ArrayList<HistoryRecord>();
475
476 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 * List of intents that were used to start the most recent tasks.
478 */
479 final ArrayList<TaskRecord> mRecentTasks
480 = new ArrayList<TaskRecord>();
481
482 /**
483 * List of activities that are ready to be finished, but waiting
484 * for the previous activity to settle down before doing so. It contains
485 * HistoryRecord objects.
486 */
487 final ArrayList mFinishingActivities = new ArrayList();
488
489 /**
490 * All of the applications we currently have running organized by name.
491 * The keys are strings of the application package name (as
492 * returned by the package manager), and the keys are ApplicationRecord
493 * objects.
494 */
495 final ProcessMap<ProcessRecord> mProcessNames
496 = new ProcessMap<ProcessRecord>();
497
498 /**
499 * The last time that various processes have crashed.
500 */
501 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
502
503 /**
504 * Set of applications that we consider to be bad, and will reject
505 * incoming broadcasts from (which the user has no control over).
506 * Processes are added to this set when they have crashed twice within
507 * a minimum amount of time; they are removed from it when they are
508 * later restarted (hopefully due to some user action). The value is the
509 * time it was added to the list.
510 */
511 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
512
513 /**
514 * All of the processes we currently have running organized by pid.
515 * The keys are the pid running the application.
516 *
517 * <p>NOTE: This object is protected by its own lock, NOT the global
518 * activity manager lock!
519 */
520 final SparseArray<ProcessRecord> mPidsSelfLocked
521 = new SparseArray<ProcessRecord>();
522
523 /**
524 * All of the processes that have been forced to be foreground. The key
525 * is the pid of the caller who requested it (we hold a death
526 * link on it).
527 */
528 abstract class ForegroundToken implements IBinder.DeathRecipient {
529 int pid;
530 IBinder token;
531 }
532 final SparseArray<ForegroundToken> mForegroundProcesses
533 = new SparseArray<ForegroundToken>();
534
535 /**
536 * List of records for processes that someone had tried to start before the
537 * system was ready. We don't start them at that point, but ensure they
538 * are started by the time booting is complete.
539 */
540 final ArrayList<ProcessRecord> mProcessesOnHold
541 = new ArrayList<ProcessRecord>();
542
543 /**
544 * List of records for processes that we have started and are waiting
545 * for them to call back. This is really only needed when running in
546 * single processes mode, in which case we do not have a unique pid for
547 * each process.
548 */
549 final ArrayList<ProcessRecord> mStartingProcesses
550 = new ArrayList<ProcessRecord>();
551
552 /**
553 * List of persistent applications that are in the process
554 * of being started.
555 */
556 final ArrayList<ProcessRecord> mPersistentStartingProcesses
557 = new ArrayList<ProcessRecord>();
558
559 /**
560 * Processes that are being forcibly torn down.
561 */
562 final ArrayList<ProcessRecord> mRemovedProcesses
563 = new ArrayList<ProcessRecord>();
564
565 /**
566 * List of running applications, sorted by recent usage.
567 * The first entry in the list is the least recently used.
568 * It contains ApplicationRecord objects. This list does NOT include
569 * any persistent application records (since we never want to exit them).
570 */
571 final ArrayList<ProcessRecord> mLRUProcesses
572 = new ArrayList<ProcessRecord>();
573
574 /**
575 * List of processes that should gc as soon as things are idle.
576 */
577 final ArrayList<ProcessRecord> mProcessesToGc
578 = new ArrayList<ProcessRecord>();
579
580 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800581 * This is the process holding what we currently consider to be
582 * the "home" activity.
583 */
584 private ProcessRecord mHomeProcess;
585
586 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 * List of running activities, sorted by recent usage.
588 * The first entry in the list is the least recently used.
589 * It contains HistoryRecord objects.
590 */
591 private final ArrayList mLRUActivities = new ArrayList();
592
593 /**
594 * Set of PendingResultRecord objects that are currently active.
595 */
596 final HashSet mPendingResultRecords = new HashSet();
597
598 /**
599 * Set of IntentSenderRecord objects that are currently active.
600 */
601 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
602 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
603
604 /**
605 * Intent broadcast that we have tried to start, but are
606 * waiting for its application's process to be created. We only
607 * need one (instead of a list) because we always process broadcasts
608 * one at a time, so no others can be started while waiting for this
609 * one.
610 */
611 BroadcastRecord mPendingBroadcast = null;
612
613 /**
614 * Keeps track of all IIntentReceivers that have been registered for
615 * broadcasts. Hash keys are the receiver IBinder, hash value is
616 * a ReceiverList.
617 */
618 final HashMap mRegisteredReceivers = new HashMap();
619
620 /**
621 * Resolver for broadcast intents to registered receivers.
622 * Holds BroadcastFilter (subclass of IntentFilter).
623 */
624 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
625 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
626 @Override
627 protected boolean allowFilterResult(
628 BroadcastFilter filter, List<BroadcastFilter> dest) {
629 IBinder target = filter.receiverList.receiver.asBinder();
630 for (int i=dest.size()-1; i>=0; i--) {
631 if (dest.get(i).receiverList.receiver.asBinder() == target) {
632 return false;
633 }
634 }
635 return true;
636 }
637 };
638
639 /**
640 * State of all active sticky broadcasts. Keys are the action of the
641 * sticky Intent, values are an ArrayList of all broadcasted intents with
642 * that action (which should usually be one).
643 */
644 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
645 new HashMap<String, ArrayList<Intent>>();
646
647 /**
648 * All currently running services.
649 */
650 final HashMap<ComponentName, ServiceRecord> mServices =
651 new HashMap<ComponentName, ServiceRecord>();
652
653 /**
654 * All currently running services indexed by the Intent used to start them.
655 */
656 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
657 new HashMap<Intent.FilterComparison, ServiceRecord>();
658
659 /**
660 * All currently bound service connections. Keys are the IBinder of
661 * the client's IServiceConnection.
662 */
663 final HashMap<IBinder, ConnectionRecord> mServiceConnections
664 = new HashMap<IBinder, ConnectionRecord>();
665
666 /**
667 * List of services that we have been asked to start,
668 * but haven't yet been able to. It is used to hold start requests
669 * while waiting for their corresponding application thread to get
670 * going.
671 */
672 final ArrayList<ServiceRecord> mPendingServices
673 = new ArrayList<ServiceRecord>();
674
675 /**
676 * List of services that are scheduled to restart following a crash.
677 */
678 final ArrayList<ServiceRecord> mRestartingServices
679 = new ArrayList<ServiceRecord>();
680
681 /**
682 * List of services that are in the process of being stopped.
683 */
684 final ArrayList<ServiceRecord> mStoppingServices
685 = new ArrayList<ServiceRecord>();
686
687 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700688 * Backup/restore process management
689 */
690 String mBackupAppName = null;
691 BackupRecord mBackupTarget = null;
692
693 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 * List of PendingThumbnailsRecord objects of clients who are still
695 * waiting to receive all of the thumbnails for a task.
696 */
697 final ArrayList mPendingThumbnails = new ArrayList();
698
699 /**
700 * List of HistoryRecord objects that have been finished and must
701 * still report back to a pending thumbnail receiver.
702 */
703 final ArrayList mCancelledThumbnails = new ArrayList();
704
705 /**
706 * All of the currently running global content providers. Keys are a
707 * string containing the provider name and values are a
708 * ContentProviderRecord object containing the data about it. Note
709 * that a single provider may be published under multiple names, so
710 * there may be multiple entries here for a single one in mProvidersByClass.
711 */
712 final HashMap mProvidersByName = new HashMap();
713
714 /**
715 * All of the currently running global content providers. Keys are a
716 * string containing the provider's implementation class and values are a
717 * ContentProviderRecord object containing the data about it.
718 */
719 final HashMap mProvidersByClass = new HashMap();
720
721 /**
722 * List of content providers who have clients waiting for them. The
723 * application is currently being launched and the provider will be
724 * removed from this list once it is published.
725 */
726 final ArrayList mLaunchingProviders = new ArrayList();
727
728 /**
729 * Global set of specific Uri permissions that have been granted.
730 */
731 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
732 = new SparseArray<HashMap<Uri, UriPermission>>();
733
734 /**
735 * Thread-local storage used to carry caller permissions over through
736 * indirect content-provider access.
737 * @see #ActivityManagerService.openContentUri()
738 */
739 private class Identity {
740 public int pid;
741 public int uid;
742
743 Identity(int _pid, int _uid) {
744 pid = _pid;
745 uid = _uid;
746 }
747 }
748 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
749
750 /**
751 * All information we have collected about the runtime performance of
752 * any user id that can impact battery performance.
753 */
754 final BatteryStatsService mBatteryStatsService;
755
756 /**
757 * information about component usage
758 */
759 final UsageStatsService mUsageStatsService;
760
761 /**
762 * Current configuration information. HistoryRecord objects are given
763 * a reference to this object to indicate which configuration they are
764 * currently running in, so this object must be kept immutable.
765 */
766 Configuration mConfiguration = new Configuration();
767
768 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700769 * Hardware-reported OpenGLES version.
770 */
771 final int GL_ES_VERSION;
772
773 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 * List of initialization arguments to pass to all processes when binding applications to them.
775 * For example, references to the commonly used services.
776 */
777 HashMap<String, IBinder> mAppBindArgs;
778
779 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700780 * Temporary to avoid allocations. Protected by main lock.
781 */
782 final StringBuilder mStringBuilder = new StringBuilder(256);
783
784 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 * Used to control how we initialize the service.
786 */
787 boolean mStartRunning = false;
788 ComponentName mTopComponent;
789 String mTopAction;
790 String mTopData;
791 boolean mSystemReady = false;
792 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700793 boolean mWaitingUpdate = false;
794 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795
796 Context mContext;
797
798 int mFactoryTest;
799
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700800 boolean mCheckedForSetup;
801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700803 * The time at which we will allow normal application switches again,
804 * after a call to {@link #stopAppSwitches()}.
805 */
806 long mAppSwitchesAllowedTime;
807
808 /**
809 * This is set to true after the first switch after mAppSwitchesAllowedTime
810 * is set; any switches after that will clear the time.
811 */
812 boolean mDidAppSwitch;
813
814 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 * Set while we are wanting to sleep, to prevent any
816 * activities from being started/resumed.
817 */
818 boolean mSleeping = false;
819
820 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700821 * Set if we are shutting down the system, similar to sleeping.
822 */
823 boolean mShuttingDown = false;
824
825 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 * Set when the system is going to sleep, until we have
827 * successfully paused the current activity and released our wake lock.
828 * At that point the system is allowed to actually sleep.
829 */
830 PowerManager.WakeLock mGoingToSleep;
831
832 /**
833 * We don't want to allow the device to go to sleep while in the process
834 * of launching an activity. This is primarily to allow alarm intent
835 * receivers to launch an activity and get that to run before the device
836 * goes back to sleep.
837 */
838 PowerManager.WakeLock mLaunchingActivity;
839
840 /**
841 * Task identifier that activities are currently being started
842 * in. Incremented each time a new task is created.
843 * todo: Replace this with a TokenSpace class that generates non-repeating
844 * integers that won't wrap.
845 */
846 int mCurTask = 1;
847
848 /**
849 * Current sequence id for oom_adj computation traversal.
850 */
851 int mAdjSeq = 0;
852
853 /**
854 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
855 * is set, indicating the user wants processes started in such a way
856 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
857 * running in each process (thus no pre-initialized process, etc).
858 */
859 boolean mSimpleProcessManagement = false;
860
861 /**
862 * System monitoring: number of processes that died since the last
863 * N procs were started.
864 */
865 int[] mProcDeaths = new int[20];
866
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700867 /**
868 * This is set if we had to do a delayed dexopt of an app before launching
869 * it, to increasing the ANR timeouts in that case.
870 */
871 boolean mDidDexOpt;
872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 String mDebugApp = null;
874 boolean mWaitForDebugger = false;
875 boolean mDebugTransient = false;
876 String mOrigDebugApp = null;
877 boolean mOrigWaitForDebugger = false;
878 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700879 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700881 final RemoteCallbackList<IActivityWatcher> mWatchers
882 = new RemoteCallbackList<IActivityWatcher>();
883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 /**
885 * Callback of last caller to {@link #requestPss}.
886 */
887 Runnable mRequestPssCallback;
888
889 /**
890 * Remaining processes for which we are waiting results from the last
891 * call to {@link #requestPss}.
892 */
893 final ArrayList<ProcessRecord> mRequestPssList
894 = new ArrayList<ProcessRecord>();
895
896 /**
897 * Runtime statistics collection thread. This object's lock is used to
898 * protect all related state.
899 */
900 final Thread mProcessStatsThread;
901
902 /**
903 * Used to collect process stats when showing not responding dialog.
904 * Protected by mProcessStatsThread.
905 */
906 final ProcessStats mProcessStats = new ProcessStats(
907 MONITOR_THREAD_CPU_USAGE);
908 long mLastCpuTime = 0;
909 long mLastWriteTime = 0;
910
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700911 long mInitialStartTime = 0;
912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 /**
914 * Set to true after the system has finished booting.
915 */
916 boolean mBooted = false;
917
918 int mProcessLimit = 0;
919
920 WindowManagerService mWindowManager;
921
922 static ActivityManagerService mSelf;
923 static ActivityThread mSystemThread;
924
925 private final class AppDeathRecipient implements IBinder.DeathRecipient {
926 final ProcessRecord mApp;
927 final int mPid;
928 final IApplicationThread mAppThread;
929
930 AppDeathRecipient(ProcessRecord app, int pid,
931 IApplicationThread thread) {
932 if (localLOGV) Log.v(
933 TAG, "New death recipient " + this
934 + " for thread " + thread.asBinder());
935 mApp = app;
936 mPid = pid;
937 mAppThread = thread;
938 }
939
940 public void binderDied() {
941 if (localLOGV) Log.v(
942 TAG, "Death received in " + this
943 + " for thread " + mAppThread.asBinder());
944 removeRequestedPss(mApp);
945 synchronized(ActivityManagerService.this) {
946 appDiedLocked(mApp, mPid, mAppThread);
947 }
948 }
949 }
950
951 static final int SHOW_ERROR_MSG = 1;
952 static final int SHOW_NOT_RESPONDING_MSG = 2;
953 static final int SHOW_FACTORY_ERROR_MSG = 3;
954 static final int UPDATE_CONFIGURATION_MSG = 4;
955 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
956 static final int WAIT_FOR_DEBUGGER_MSG = 6;
957 static final int BROADCAST_INTENT_MSG = 7;
958 static final int BROADCAST_TIMEOUT_MSG = 8;
959 static final int PAUSE_TIMEOUT_MSG = 9;
960 static final int IDLE_TIMEOUT_MSG = 10;
961 static final int IDLE_NOW_MSG = 11;
962 static final int SERVICE_TIMEOUT_MSG = 12;
963 static final int UPDATE_TIME_ZONE = 13;
964 static final int SHOW_UID_ERROR_MSG = 14;
965 static final int IM_FEELING_LUCKY_MSG = 15;
966 static final int LAUNCH_TIMEOUT_MSG = 16;
967 static final int DESTROY_TIMEOUT_MSG = 17;
968 static final int SERVICE_ERROR_MSG = 18;
969 static final int RESUME_TOP_ACTIVITY_MSG = 19;
970 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700971 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700972 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973
974 AlertDialog mUidAlert;
975
976 final Handler mHandler = new Handler() {
977 //public Handler() {
978 // if (localLOGV) Log.v(TAG, "Handler started!");
979 //}
980
981 public void handleMessage(Message msg) {
982 switch (msg.what) {
983 case SHOW_ERROR_MSG: {
984 HashMap data = (HashMap) msg.obj;
985 byte[] crashData = (byte[])data.get("crashData");
986 if (crashData != null) {
987 // This needs to be *un*synchronized to avoid deadlock.
988 ContentResolver resolver = mContext.getContentResolver();
989 Checkin.reportCrash(resolver, crashData);
990 }
991 synchronized (ActivityManagerService.this) {
992 ProcessRecord proc = (ProcessRecord)data.get("app");
993 if (proc != null && proc.crashDialog != null) {
994 Log.e(TAG, "App already has crash dialog: " + proc);
995 return;
996 }
997 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700998 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 Dialog d = new AppErrorDialog(
1000 mContext, res, proc,
1001 (Integer)data.get("flags"),
1002 (String)data.get("shortMsg"),
1003 (String)data.get("longMsg"));
1004 d.show();
1005 proc.crashDialog = d;
1006 } else {
1007 // The device is asleep, so just pretend that the user
1008 // saw a crash dialog and hit "force quit".
1009 res.set(0);
1010 }
1011 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001012
1013 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 } break;
1015 case SHOW_NOT_RESPONDING_MSG: {
1016 synchronized (ActivityManagerService.this) {
1017 HashMap data = (HashMap) msg.obj;
1018 ProcessRecord proc = (ProcessRecord)data.get("app");
1019 if (proc != null && proc.anrDialog != null) {
1020 Log.e(TAG, "App already has anr dialog: " + proc);
1021 return;
1022 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001023
1024 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1025 null, null, 0, null, null, null,
1026 false, false, MY_PID, Process.SYSTEM_UID);
1027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1029 mContext, proc, (HistoryRecord)data.get("activity"));
1030 d.show();
1031 proc.anrDialog = d;
1032 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001033
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001034 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 } break;
1036 case SHOW_FACTORY_ERROR_MSG: {
1037 Dialog d = new FactoryErrorDialog(
1038 mContext, msg.getData().getCharSequence("msg"));
1039 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001040 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 } break;
1042 case UPDATE_CONFIGURATION_MSG: {
1043 final ContentResolver resolver = mContext.getContentResolver();
1044 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1045 } break;
1046 case GC_BACKGROUND_PROCESSES_MSG: {
1047 synchronized (ActivityManagerService.this) {
1048 performAppGcsIfAppropriateLocked();
1049 }
1050 } break;
1051 case WAIT_FOR_DEBUGGER_MSG: {
1052 synchronized (ActivityManagerService.this) {
1053 ProcessRecord app = (ProcessRecord)msg.obj;
1054 if (msg.arg1 != 0) {
1055 if (!app.waitedForDebugger) {
1056 Dialog d = new AppWaitingForDebuggerDialog(
1057 ActivityManagerService.this,
1058 mContext, app);
1059 app.waitDialog = d;
1060 app.waitedForDebugger = true;
1061 d.show();
1062 }
1063 } else {
1064 if (app.waitDialog != null) {
1065 app.waitDialog.dismiss();
1066 app.waitDialog = null;
1067 }
1068 }
1069 }
1070 } break;
1071 case BROADCAST_INTENT_MSG: {
1072 if (DEBUG_BROADCAST) Log.v(
1073 TAG, "Received BROADCAST_INTENT_MSG");
1074 processNextBroadcast(true);
1075 } break;
1076 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001077 if (mDidDexOpt) {
1078 mDidDexOpt = false;
1079 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1080 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1081 return;
1082 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 broadcastTimeout();
1084 } break;
1085 case PAUSE_TIMEOUT_MSG: {
1086 IBinder token = (IBinder)msg.obj;
1087 // We don't at this point know if the activity is fullscreen,
1088 // so we need to be conservative and assume it isn't.
1089 Log.w(TAG, "Activity pause timeout for " + token);
1090 activityPaused(token, null, true);
1091 } break;
1092 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001093 if (mDidDexOpt) {
1094 mDidDexOpt = false;
1095 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1096 nmsg.obj = msg.obj;
1097 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1098 return;
1099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 // We don't at this point know if the activity is fullscreen,
1101 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001102 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001104 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 } break;
1106 case DESTROY_TIMEOUT_MSG: {
1107 IBinder token = (IBinder)msg.obj;
1108 // We don't at this point know if the activity is fullscreen,
1109 // so we need to be conservative and assume it isn't.
1110 Log.w(TAG, "Activity destroy timeout for " + token);
1111 activityDestroyed(token);
1112 } break;
1113 case IDLE_NOW_MSG: {
1114 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001115 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 } break;
1117 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001118 if (mDidDexOpt) {
1119 mDidDexOpt = false;
1120 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1121 nmsg.obj = msg.obj;
1122 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1123 return;
1124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 serviceTimeout((ProcessRecord)msg.obj);
1126 } break;
1127 case UPDATE_TIME_ZONE: {
1128 synchronized (ActivityManagerService.this) {
1129 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1130 ProcessRecord r = mLRUProcesses.get(i);
1131 if (r.thread != null) {
1132 try {
1133 r.thread.updateTimeZone();
1134 } catch (RemoteException ex) {
1135 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1136 }
1137 }
1138 }
1139 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001140 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 case SHOW_UID_ERROR_MSG: {
1142 // XXX This is a temporary dialog, no need to localize.
1143 AlertDialog d = new BaseErrorDialog(mContext);
1144 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1145 d.setCancelable(false);
1146 d.setTitle("System UIDs Inconsistent");
1147 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1148 d.setButton("I'm Feeling Lucky",
1149 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1150 mUidAlert = d;
1151 d.show();
1152 } break;
1153 case IM_FEELING_LUCKY_MSG: {
1154 if (mUidAlert != null) {
1155 mUidAlert.dismiss();
1156 mUidAlert = null;
1157 }
1158 } break;
1159 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001160 if (mDidDexOpt) {
1161 mDidDexOpt = false;
1162 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1163 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1164 return;
1165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 synchronized (ActivityManagerService.this) {
1167 if (mLaunchingActivity.isHeld()) {
1168 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1169 mLaunchingActivity.release();
1170 }
1171 }
1172 } break;
1173 case SERVICE_ERROR_MSG: {
1174 ServiceRecord srv = (ServiceRecord)msg.obj;
1175 // This needs to be *un*synchronized to avoid deadlock.
1176 Checkin.logEvent(mContext.getContentResolver(),
1177 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1178 srv.name.toShortString());
1179 } break;
1180 case RESUME_TOP_ACTIVITY_MSG: {
1181 synchronized (ActivityManagerService.this) {
1182 resumeTopActivityLocked(null);
1183 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001184 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001186 if (mDidDexOpt) {
1187 mDidDexOpt = false;
1188 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1189 nmsg.obj = msg.obj;
1190 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1191 return;
1192 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 ProcessRecord app = (ProcessRecord)msg.obj;
1194 synchronized (ActivityManagerService.this) {
1195 processStartTimedOutLocked(app);
1196 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001197 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001198 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1199 synchronized (ActivityManagerService.this) {
1200 doPendingActivityLaunchesLocked(true);
1201 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001202 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001203 case KILL_APPLICATION_MSG: {
1204 synchronized (ActivityManagerService.this) {
1205 int uid = msg.arg1;
1206 boolean restart = (msg.arg2 == 1);
1207 String pkg = (String) msg.obj;
1208 uninstallPackageLocked(pkg, uid, restart);
1209 }
1210 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 }
1212 }
1213 };
1214
1215 public static void setSystemProcess() {
1216 try {
1217 ActivityManagerService m = mSelf;
1218
1219 ServiceManager.addService("activity", m);
1220 ServiceManager.addService("meminfo", new MemBinder(m));
1221 if (MONITOR_CPU_USAGE) {
1222 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1223 }
1224 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1225 ServiceManager.addService("activity.services", new ServicesBinder(m));
1226 ServiceManager.addService("activity.senders", new SendersBinder(m));
1227 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1228 ServiceManager.addService("permission", new PermissionController(m));
1229
1230 ApplicationInfo info =
1231 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001232 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001233 mSystemThread.installSystemApplicationInfo(info);
1234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 synchronized (mSelf) {
1236 ProcessRecord app = mSelf.newProcessRecordLocked(
1237 mSystemThread.getApplicationThread(), info,
1238 info.processName);
1239 app.persistent = true;
1240 app.pid = Process.myPid();
1241 app.maxAdj = SYSTEM_ADJ;
1242 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1243 synchronized (mSelf.mPidsSelfLocked) {
1244 mSelf.mPidsSelfLocked.put(app.pid, app);
1245 }
1246 mSelf.updateLRUListLocked(app, true);
1247 }
1248 } catch (PackageManager.NameNotFoundException e) {
1249 throw new RuntimeException(
1250 "Unable to find android system package", e);
1251 }
1252 }
1253
1254 public void setWindowManager(WindowManagerService wm) {
1255 mWindowManager = wm;
1256 }
1257
1258 public static final Context main(int factoryTest) {
1259 AThread thr = new AThread();
1260 thr.start();
1261
1262 synchronized (thr) {
1263 while (thr.mService == null) {
1264 try {
1265 thr.wait();
1266 } catch (InterruptedException e) {
1267 }
1268 }
1269 }
1270
1271 ActivityManagerService m = thr.mService;
1272 mSelf = m;
1273 ActivityThread at = ActivityThread.systemMain();
1274 mSystemThread = at;
1275 Context context = at.getSystemContext();
1276 m.mContext = context;
1277 m.mFactoryTest = factoryTest;
1278 PowerManager pm =
1279 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1280 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1281 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1282 m.mLaunchingActivity.setReferenceCounted(false);
1283
1284 m.mBatteryStatsService.publish(context);
1285 m.mUsageStatsService.publish(context);
1286
1287 synchronized (thr) {
1288 thr.mReady = true;
1289 thr.notifyAll();
1290 }
1291
1292 m.startRunning(null, null, null, null);
1293
1294 return context;
1295 }
1296
1297 public static ActivityManagerService self() {
1298 return mSelf;
1299 }
1300
1301 static class AThread extends Thread {
1302 ActivityManagerService mService;
1303 boolean mReady = false;
1304
1305 public AThread() {
1306 super("ActivityManager");
1307 }
1308
1309 public void run() {
1310 Looper.prepare();
1311
1312 android.os.Process.setThreadPriority(
1313 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1314
1315 ActivityManagerService m = new ActivityManagerService();
1316
1317 synchronized (this) {
1318 mService = m;
1319 notifyAll();
1320 }
1321
1322 synchronized (this) {
1323 while (!mReady) {
1324 try {
1325 wait();
1326 } catch (InterruptedException e) {
1327 }
1328 }
1329 }
1330
1331 Looper.loop();
1332 }
1333 }
1334
1335 static class BroadcastsBinder extends Binder {
1336 ActivityManagerService mActivityManagerService;
1337 BroadcastsBinder(ActivityManagerService activityManagerService) {
1338 mActivityManagerService = activityManagerService;
1339 }
1340
1341 @Override
1342 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1343 mActivityManagerService.dumpBroadcasts(pw);
1344 }
1345 }
1346
1347 static class ServicesBinder extends Binder {
1348 ActivityManagerService mActivityManagerService;
1349 ServicesBinder(ActivityManagerService activityManagerService) {
1350 mActivityManagerService = activityManagerService;
1351 }
1352
1353 @Override
1354 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1355 mActivityManagerService.dumpServices(pw);
1356 }
1357 }
1358
1359 static class SendersBinder extends Binder {
1360 ActivityManagerService mActivityManagerService;
1361 SendersBinder(ActivityManagerService activityManagerService) {
1362 mActivityManagerService = activityManagerService;
1363 }
1364
1365 @Override
1366 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1367 mActivityManagerService.dumpSenders(pw);
1368 }
1369 }
1370
1371 static class ProvidersBinder extends Binder {
1372 ActivityManagerService mActivityManagerService;
1373 ProvidersBinder(ActivityManagerService activityManagerService) {
1374 mActivityManagerService = activityManagerService;
1375 }
1376
1377 @Override
1378 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1379 mActivityManagerService.dumpProviders(pw);
1380 }
1381 }
1382
1383 static class MemBinder extends Binder {
1384 ActivityManagerService mActivityManagerService;
1385 MemBinder(ActivityManagerService activityManagerService) {
1386 mActivityManagerService = activityManagerService;
1387 }
1388
1389 @Override
1390 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1391 ActivityManagerService service = mActivityManagerService;
1392 ArrayList<ProcessRecord> procs;
1393 synchronized (mActivityManagerService) {
1394 if (args != null && args.length > 0
1395 && args[0].charAt(0) != '-') {
1396 procs = new ArrayList<ProcessRecord>();
1397 int pid = -1;
1398 try {
1399 pid = Integer.parseInt(args[0]);
1400 } catch (NumberFormatException e) {
1401
1402 }
1403 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1404 ProcessRecord proc = service.mLRUProcesses.get(i);
1405 if (proc.pid == pid) {
1406 procs.add(proc);
1407 } else if (proc.processName.equals(args[0])) {
1408 procs.add(proc);
1409 }
1410 }
1411 if (procs.size() <= 0) {
1412 pw.println("No process found for: " + args[0]);
1413 return;
1414 }
1415 } else {
1416 procs = service.mLRUProcesses;
1417 }
1418 }
1419 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1420 }
1421 }
1422
1423 static class CpuBinder extends Binder {
1424 ActivityManagerService mActivityManagerService;
1425 CpuBinder(ActivityManagerService activityManagerService) {
1426 mActivityManagerService = activityManagerService;
1427 }
1428
1429 @Override
1430 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1431 synchronized (mActivityManagerService.mProcessStatsThread) {
1432 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1433 }
1434 }
1435 }
1436
1437 private ActivityManagerService() {
1438 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1439 if (v != null && Integer.getInteger(v) != 0) {
1440 mSimpleProcessManagement = true;
1441 }
1442 v = System.getenv("ANDROID_DEBUG_APP");
1443 if (v != null) {
1444 mSimpleProcessManagement = true;
1445 }
1446
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001447 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 MY_PID = Process.myPid();
1450
1451 File dataDir = Environment.getDataDirectory();
1452 File systemDir = new File(dataDir, "system");
1453 systemDir.mkdirs();
1454 mBatteryStatsService = new BatteryStatsService(new File(
1455 systemDir, "batterystats.bin").toString());
1456 mBatteryStatsService.getActiveStatistics().readLocked();
1457 mBatteryStatsService.getActiveStatistics().writeLocked();
1458
1459 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001460 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461
Jack Palevichb90d28c2009-07-22 15:35:24 -07001462 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1463 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 mConfiguration.makeDefault();
1466 mProcessStats.init();
1467
1468 // Add ourself to the Watchdog monitors.
1469 Watchdog.getInstance().addMonitor(this);
1470
1471 // These values are set in system/rootdir/init.rc on startup.
1472 FOREGROUND_APP_ADJ =
1473 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1474 VISIBLE_APP_ADJ =
1475 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1476 SECONDARY_SERVER_ADJ =
1477 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001478 BACKUP_APP_ADJ =
1479 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001480 HOME_APP_ADJ =
1481 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 HIDDEN_APP_MIN_ADJ =
1483 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1484 CONTENT_PROVIDER_ADJ =
1485 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1486 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1487 EMPTY_APP_ADJ =
1488 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1489 FOREGROUND_APP_MEM =
1490 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1491 VISIBLE_APP_MEM =
1492 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1493 SECONDARY_SERVER_MEM =
1494 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001495 BACKUP_APP_MEM =
1496 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001497 HOME_APP_MEM =
1498 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 HIDDEN_APP_MEM =
1500 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1501 EMPTY_APP_MEM =
1502 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1503
1504 mProcessStatsThread = new Thread("ProcessStats") {
1505 public void run() {
1506 while (true) {
1507 try {
1508 try {
1509 synchronized(this) {
1510 final long now = SystemClock.uptimeMillis();
1511 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1512 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1513 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1514 // + ", write delay=" + nextWriteDelay);
1515 if (nextWriteDelay < nextCpuDelay) {
1516 nextCpuDelay = nextWriteDelay;
1517 }
1518 if (nextCpuDelay > 0) {
1519 this.wait(nextCpuDelay);
1520 }
1521 }
1522 } catch (InterruptedException e) {
1523 }
1524
1525 updateCpuStatsNow();
1526 } catch (Exception e) {
1527 Log.e(TAG, "Unexpected exception collecting process stats", e);
1528 }
1529 }
1530 }
1531 };
1532 mProcessStatsThread.start();
1533 }
1534
1535 @Override
1536 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1537 throws RemoteException {
1538 try {
1539 return super.onTransact(code, data, reply, flags);
1540 } catch (RuntimeException e) {
1541 // The activity manager only throws security exceptions, so let's
1542 // log all others.
1543 if (!(e instanceof SecurityException)) {
1544 Log.e(TAG, "Activity Manager Crash", e);
1545 }
1546 throw e;
1547 }
1548 }
1549
1550 void updateCpuStats() {
1551 synchronized (mProcessStatsThread) {
1552 final long now = SystemClock.uptimeMillis();
1553 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1554 mProcessStatsThread.notify();
1555 }
1556 }
1557 }
1558
1559 void updateCpuStatsNow() {
1560 synchronized (mProcessStatsThread) {
1561 final long now = SystemClock.uptimeMillis();
1562 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 if (MONITOR_CPU_USAGE &&
1565 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1566 mLastCpuTime = now;
1567 haveNewCpuStats = true;
1568 mProcessStats.update();
1569 //Log.i(TAG, mProcessStats.printCurrentState());
1570 //Log.i(TAG, "Total CPU usage: "
1571 // + mProcessStats.getTotalCpuPercent() + "%");
1572
1573 // Log the cpu usage if the property is set.
1574 if ("true".equals(SystemProperties.get("events.cpu"))) {
1575 int user = mProcessStats.getLastUserTime();
1576 int system = mProcessStats.getLastSystemTime();
1577 int iowait = mProcessStats.getLastIoWaitTime();
1578 int irq = mProcessStats.getLastIrqTime();
1579 int softIrq = mProcessStats.getLastSoftIrqTime();
1580 int idle = mProcessStats.getLastIdleTime();
1581
1582 int total = user + system + iowait + irq + softIrq + idle;
1583 if (total == 0) total = 1;
1584
1585 EventLog.writeEvent(LOG_CPU,
1586 ((user+system+iowait+irq+softIrq) * 100) / total,
1587 (user * 100) / total,
1588 (system * 100) / total,
1589 (iowait * 100) / total,
1590 (irq * 100) / total,
1591 (softIrq * 100) / total);
1592 }
1593 }
1594
Amith Yamasanie43530a2009-08-21 13:11:37 -07001595 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001596 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001597 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 synchronized(mPidsSelfLocked) {
1599 if (haveNewCpuStats) {
1600 if (mBatteryStatsService.isOnBattery()) {
1601 final int N = mProcessStats.countWorkingStats();
1602 for (int i=0; i<N; i++) {
1603 ProcessStats.Stats st
1604 = mProcessStats.getWorkingStats(i);
1605 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1606 if (pr != null) {
1607 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1608 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001609 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001610 } else {
1611 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001612 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001613 if (ps != null) {
1614 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001615 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001616 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 }
1618 }
1619 }
1620 }
1621 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1624 mLastWriteTime = now;
1625 mBatteryStatsService.getActiveStatistics().writeLocked();
1626 }
1627 }
1628 }
1629 }
1630
1631 /**
1632 * Initialize the application bind args. These are passed to each
1633 * process when the bindApplication() IPC is sent to the process. They're
1634 * lazily setup to make sure the services are running when they're asked for.
1635 */
1636 private HashMap<String, IBinder> getCommonServicesLocked() {
1637 if (mAppBindArgs == null) {
1638 mAppBindArgs = new HashMap<String, IBinder>();
1639
1640 // Setup the application init args
1641 mAppBindArgs.put("package", ServiceManager.getService("package"));
1642 mAppBindArgs.put("window", ServiceManager.getService("window"));
1643 mAppBindArgs.put(Context.ALARM_SERVICE,
1644 ServiceManager.getService(Context.ALARM_SERVICE));
1645 }
1646 return mAppBindArgs;
1647 }
1648
1649 private final void setFocusedActivityLocked(HistoryRecord r) {
1650 if (mFocusedActivity != r) {
1651 mFocusedActivity = r;
1652 mWindowManager.setFocusedApp(r, true);
1653 }
1654 }
1655
1656 private final void updateLRUListLocked(ProcessRecord app,
1657 boolean oomAdj) {
1658 // put it on the LRU to keep track of when it should be exited.
1659 int lrui = mLRUProcesses.indexOf(app);
1660 if (lrui >= 0) mLRUProcesses.remove(lrui);
1661 mLRUProcesses.add(app);
1662 //Log.i(TAG, "Putting proc to front: " + app.processName);
1663 if (oomAdj) {
1664 updateOomAdjLocked();
1665 }
1666 }
1667
1668 private final boolean updateLRUListLocked(HistoryRecord r) {
1669 final boolean hadit = mLRUActivities.remove(r);
1670 mLRUActivities.add(r);
1671 return hadit;
1672 }
1673
1674 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1675 int i = mHistory.size()-1;
1676 while (i >= 0) {
1677 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1678 if (!r.finishing && r != notTop) {
1679 return r;
1680 }
1681 i--;
1682 }
1683 return null;
1684 }
1685
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001686 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1687 int i = mHistory.size()-1;
1688 while (i >= 0) {
1689 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1690 if (!r.finishing && !r.delayedResume && r != notTop) {
1691 return r;
1692 }
1693 i--;
1694 }
1695 return null;
1696 }
1697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 /**
1699 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001700 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 *
1702 * @param token If non-null, any history records matching this token will be skipped.
1703 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1704 *
1705 * @return Returns the HistoryRecord of the next activity on the stack.
1706 */
1707 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1708 int i = mHistory.size()-1;
1709 while (i >= 0) {
1710 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1711 // Note: the taskId check depends on real taskId fields being non-zero
1712 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1713 return r;
1714 }
1715 i--;
1716 }
1717 return null;
1718 }
1719
1720 private final ProcessRecord getProcessRecordLocked(
1721 String processName, int uid) {
1722 if (uid == Process.SYSTEM_UID) {
1723 // The system gets to run in any process. If there are multiple
1724 // processes with the same uid, just pick the first (this
1725 // should never happen).
1726 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1727 processName);
1728 return procs != null ? procs.valueAt(0) : null;
1729 }
1730 ProcessRecord proc = mProcessNames.get(processName, uid);
1731 return proc;
1732 }
1733
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001734 private void ensurePackageDexOpt(String packageName) {
1735 IPackageManager pm = ActivityThread.getPackageManager();
1736 try {
1737 if (pm.performDexOpt(packageName)) {
1738 mDidDexOpt = true;
1739 }
1740 } catch (RemoteException e) {
1741 }
1742 }
1743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 private boolean isNextTransitionForward() {
1745 int transit = mWindowManager.getPendingAppTransition();
1746 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1747 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1748 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1749 }
1750
1751 private final boolean realStartActivityLocked(HistoryRecord r,
1752 ProcessRecord app, boolean andResume, boolean checkConfig)
1753 throws RemoteException {
1754
1755 r.startFreezingScreenLocked(app, 0);
1756 mWindowManager.setAppVisibility(r, true);
1757
1758 // Have the window manager re-evaluate the orientation of
1759 // the screen based on the new activity order. Note that
1760 // as a result of this, it can call back into the activity
1761 // manager with a new orientation. We don't care about that,
1762 // because the activity is not currently running so we are
1763 // just restarting it anyway.
1764 if (checkConfig) {
1765 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001766 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 r.mayFreezeScreenLocked(app) ? r : null);
1768 updateConfigurationLocked(config, r);
1769 }
1770
1771 r.app = app;
1772
1773 if (localLOGV) Log.v(TAG, "Launching: " + r);
1774
1775 int idx = app.activities.indexOf(r);
1776 if (idx < 0) {
1777 app.activities.add(r);
1778 }
1779 updateLRUListLocked(app, true);
1780
1781 try {
1782 if (app.thread == null) {
1783 throw new RemoteException();
1784 }
1785 List<ResultInfo> results = null;
1786 List<Intent> newIntents = null;
1787 if (andResume) {
1788 results = r.results;
1789 newIntents = r.newIntents;
1790 }
1791 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1792 + " icicle=" + r.icicle
1793 + " with results=" + results + " newIntents=" + newIntents
1794 + " andResume=" + andResume);
1795 if (andResume) {
1796 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1797 System.identityHashCode(r),
1798 r.task.taskId, r.shortComponentName);
1799 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001800 if (r.isHomeActivity) {
1801 mHomeProcess = app;
1802 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001803 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001805 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 r.info, r.icicle, results, newIntents, !andResume,
1807 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 } catch (RemoteException e) {
1809 if (r.launchFailed) {
1810 // This is the second time we failed -- finish activity
1811 // and give up.
1812 Log.e(TAG, "Second failure launching "
1813 + r.intent.getComponent().flattenToShortString()
1814 + ", giving up", e);
1815 appDiedLocked(app, app.pid, app.thread);
1816 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1817 "2nd-crash");
1818 return false;
1819 }
1820
1821 // This is the first time we failed -- restart process and
1822 // retry.
1823 app.activities.remove(r);
1824 throw e;
1825 }
1826
1827 r.launchFailed = false;
1828 if (updateLRUListLocked(r)) {
1829 Log.w(TAG, "Activity " + r
1830 + " being launched, but already in LRU list");
1831 }
1832
1833 if (andResume) {
1834 // As part of the process of launching, ActivityThread also performs
1835 // a resume.
1836 r.state = ActivityState.RESUMED;
1837 r.icicle = null;
1838 r.haveState = false;
1839 r.stopped = false;
1840 mResumedActivity = r;
1841 r.task.touchActiveTime();
1842 completeResumeLocked(r);
1843 pauseIfSleepingLocked();
1844 } else {
1845 // This activity is not starting in the resumed state... which
1846 // should look like we asked it to pause+stop (but remain visible),
1847 // and it has done so and reported back the current icicle and
1848 // other state.
1849 r.state = ActivityState.STOPPED;
1850 r.stopped = true;
1851 }
1852
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001853 // Launch the new version setup screen if needed. We do this -after-
1854 // launching the initial activity (that is, home), so that it can have
1855 // a chance to initialize itself while in the background, making the
1856 // switch back to it faster and look better.
1857 startSetupActivityLocked();
1858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 return true;
1860 }
1861
1862 private final void startSpecificActivityLocked(HistoryRecord r,
1863 boolean andResume, boolean checkConfig) {
1864 // Is this activity's application already running?
1865 ProcessRecord app = getProcessRecordLocked(r.processName,
1866 r.info.applicationInfo.uid);
1867
1868 if (r.startTime == 0) {
1869 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001870 if (mInitialStartTime == 0) {
1871 mInitialStartTime = r.startTime;
1872 }
1873 } else if (mInitialStartTime == 0) {
1874 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 }
1876
1877 if (app != null && app.thread != null) {
1878 try {
1879 realStartActivityLocked(r, app, andResume, checkConfig);
1880 return;
1881 } catch (RemoteException e) {
1882 Log.w(TAG, "Exception when starting activity "
1883 + r.intent.getComponent().flattenToShortString(), e);
1884 }
1885
1886 // If a dead object exception was thrown -- fall through to
1887 // restart the application.
1888 }
1889
1890 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001891 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 }
1893
1894 private final ProcessRecord startProcessLocked(String processName,
1895 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001896 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1898 // We don't have to do anything more if:
1899 // (1) There is an existing application record; and
1900 // (2) The caller doesn't think it is dead, OR there is no thread
1901 // object attached to it so we know it couldn't have crashed; and
1902 // (3) There is a pid assigned to it, so it is either starting or
1903 // already running.
1904 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1905 + " app=" + app + " knownToBeDead=" + knownToBeDead
1906 + " thread=" + (app != null ? app.thread : null)
1907 + " pid=" + (app != null ? app.pid : -1));
Magnus Edlund7bb25812010-02-24 15:45:06 +01001908 if (app != null && app.pid > 0) {
1909 if (!knownToBeDead || app.thread == null) {
1910 return app;
1911 } else {
1912 // An application record is attached to a previous process,
1913 // clean it up now.
1914 handleAppDiedLocked(app, true);
1915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 }
Magnus Edlund7bb25812010-02-24 15:45:06 +01001917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918 String hostingNameStr = hostingName != null
1919 ? hostingName.flattenToShortString() : null;
1920
1921 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1922 // If we are in the background, then check to see if this process
1923 // is bad. If so, we will just silently fail.
1924 if (mBadProcesses.get(info.processName, info.uid) != null) {
1925 return null;
1926 }
1927 } else {
1928 // When the user is explicitly starting a process, then clear its
1929 // crash count so that we won't make it bad until they see at
1930 // least one crash dialog again, and make the process good again
1931 // if it had been bad.
1932 mProcessCrashTimes.remove(info.processName, info.uid);
1933 if (mBadProcesses.get(info.processName, info.uid) != null) {
1934 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1935 info.processName);
1936 mBadProcesses.remove(info.processName, info.uid);
1937 if (app != null) {
1938 app.bad = false;
1939 }
1940 }
1941 }
1942
1943 if (app == null) {
1944 app = newProcessRecordLocked(null, info, processName);
1945 mProcessNames.put(processName, info.uid, app);
1946 } else {
1947 // If this is a new package in the process, add the package to the list
1948 app.addPackage(info.packageName);
1949 }
1950
1951 // If the system is not ready yet, then hold off on starting this
1952 // process until it is.
1953 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001954 && !isAllowedWhileBooting(info)
1955 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 if (!mProcessesOnHold.contains(app)) {
1957 mProcessesOnHold.add(app);
1958 }
1959 return app;
1960 }
1961
1962 startProcessLocked(app, hostingType, hostingNameStr);
1963 return (app.pid != 0) ? app : null;
1964 }
1965
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001966 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1967 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1968 }
1969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 private final void startProcessLocked(ProcessRecord app,
1971 String hostingType, String hostingNameStr) {
1972 if (app.pid > 0 && app.pid != MY_PID) {
1973 synchronized (mPidsSelfLocked) {
1974 mPidsSelfLocked.remove(app.pid);
1975 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1976 }
1977 app.pid = 0;
1978 }
1979
1980 mProcessesOnHold.remove(app);
1981
1982 updateCpuStats();
1983
1984 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1985 mProcDeaths[0] = 0;
1986
1987 try {
1988 int uid = app.info.uid;
1989 int[] gids = null;
1990 try {
1991 gids = mContext.getPackageManager().getPackageGids(
1992 app.info.packageName);
1993 } catch (PackageManager.NameNotFoundException e) {
1994 Log.w(TAG, "Unable to retrieve gids", e);
1995 }
1996 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1997 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1998 && mTopComponent != null
1999 && app.processName.equals(mTopComponent.getPackageName())) {
2000 uid = 0;
2001 }
2002 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
2003 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
2004 uid = 0;
2005 }
2006 }
2007 int debugFlags = 0;
2008 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
2009 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
2010 }
2011 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
2012 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
2013 }
2014 if ("1".equals(SystemProperties.get("debug.assert"))) {
2015 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2016 }
2017 int pid = Process.start("android.app.ActivityThread",
2018 mSimpleProcessManagement ? app.processName : null, uid, uid,
2019 gids, debugFlags, null);
2020 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2021 synchronized (bs) {
2022 if (bs.isOnBattery()) {
2023 app.batteryStats.incStartsLocked();
2024 }
2025 }
2026
2027 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2028 app.processName, hostingType,
2029 hostingNameStr != null ? hostingNameStr : "");
2030
2031 if (app.persistent) {
2032 Watchdog.getInstance().processStarted(app, app.processName, pid);
2033 }
2034
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002035 StringBuilder buf = mStringBuilder;
2036 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 buf.append("Start proc ");
2038 buf.append(app.processName);
2039 buf.append(" for ");
2040 buf.append(hostingType);
2041 if (hostingNameStr != null) {
2042 buf.append(" ");
2043 buf.append(hostingNameStr);
2044 }
2045 buf.append(": pid=");
2046 buf.append(pid);
2047 buf.append(" uid=");
2048 buf.append(uid);
2049 buf.append(" gids={");
2050 if (gids != null) {
2051 for (int gi=0; gi<gids.length; gi++) {
2052 if (gi != 0) buf.append(", ");
2053 buf.append(gids[gi]);
2054
2055 }
2056 }
2057 buf.append("}");
2058 Log.i(TAG, buf.toString());
2059 if (pid == 0 || pid == MY_PID) {
2060 // Processes are being emulated with threads.
2061 app.pid = MY_PID;
2062 app.removed = false;
2063 mStartingProcesses.add(app);
2064 } else if (pid > 0) {
2065 app.pid = pid;
2066 app.removed = false;
2067 synchronized (mPidsSelfLocked) {
2068 this.mPidsSelfLocked.put(pid, app);
2069 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2070 msg.obj = app;
2071 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2072 }
2073 } else {
2074 app.pid = 0;
2075 RuntimeException e = new RuntimeException(
2076 "Failure starting process " + app.processName
2077 + ": returned pid=" + pid);
2078 Log.e(TAG, e.getMessage(), e);
2079 }
2080 } catch (RuntimeException e) {
2081 // XXX do better error recovery.
2082 app.pid = 0;
2083 Log.e(TAG, "Failure starting process " + app.processName, e);
2084 }
2085 }
2086
2087 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2088 if (mPausingActivity != null) {
2089 RuntimeException e = new RuntimeException();
2090 Log.e(TAG, "Trying to pause when pause is already pending for "
2091 + mPausingActivity, e);
2092 }
2093 HistoryRecord prev = mResumedActivity;
2094 if (prev == null) {
2095 RuntimeException e = new RuntimeException();
2096 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2097 resumeTopActivityLocked(null);
2098 return;
2099 }
2100 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2101 mResumedActivity = null;
2102 mPausingActivity = prev;
2103 mLastPausedActivity = prev;
2104 prev.state = ActivityState.PAUSING;
2105 prev.task.touchActiveTime();
2106
2107 updateCpuStats();
2108
2109 if (prev.app != null && prev.app.thread != null) {
2110 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2111 try {
2112 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2113 System.identityHashCode(prev),
2114 prev.shortComponentName);
2115 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2116 prev.configChangeFlags);
2117 updateUsageStats(prev, false);
2118 } catch (Exception e) {
2119 // Ignore exception, if process died other code will cleanup.
2120 Log.w(TAG, "Exception thrown during pause", e);
2121 mPausingActivity = null;
2122 mLastPausedActivity = null;
2123 }
2124 } else {
2125 mPausingActivity = null;
2126 mLastPausedActivity = null;
2127 }
2128
2129 // If we are not going to sleep, we want to ensure the device is
2130 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002131 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 mLaunchingActivity.acquire();
2133 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2134 // To be safe, don't allow the wake lock to be held for too long.
2135 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2136 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2137 }
2138 }
2139
2140
2141 if (mPausingActivity != null) {
2142 // Have the window manager pause its key dispatching until the new
2143 // activity has started. If we're pausing the activity just because
2144 // the screen is being turned off and the UI is sleeping, don't interrupt
2145 // key dispatch; the same activity will pick it up again on wakeup.
2146 if (!uiSleeping) {
2147 prev.pauseKeyDispatchingLocked();
2148 } else {
2149 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2150 }
2151
2152 // Schedule a pause timeout in case the app doesn't respond.
2153 // We don't give it much time because this directly impacts the
2154 // responsiveness seen by the user.
2155 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2156 msg.obj = prev;
2157 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2158 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2159 } else {
2160 // This activity failed to schedule the
2161 // pause, so just treat it as being paused now.
2162 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2163 resumeTopActivityLocked(null);
2164 }
2165 }
2166
2167 private final void completePauseLocked() {
2168 HistoryRecord prev = mPausingActivity;
2169 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2170
2171 if (prev != null) {
2172 if (prev.finishing) {
2173 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2174 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2175 } else if (prev.app != null) {
2176 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2177 if (prev.waitingVisible) {
2178 prev.waitingVisible = false;
2179 mWaitingVisibleActivities.remove(prev);
2180 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2181 TAG, "Complete pause, no longer waiting: " + prev);
2182 }
2183 if (prev.configDestroy) {
2184 // The previous is being paused because the configuration
2185 // is changing, which means it is actually stopping...
2186 // To juggle the fact that we are also starting a new
2187 // instance right now, we need to first completely stop
2188 // the current instance before starting the new one.
2189 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2190 destroyActivityLocked(prev, true);
2191 } else {
2192 mStoppingActivities.add(prev);
2193 if (mStoppingActivities.size() > 3) {
2194 // If we already have a few activities waiting to stop,
2195 // then give up on things going idle and start clearing
2196 // them out.
2197 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2198 Message msg = Message.obtain();
2199 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2200 mHandler.sendMessage(msg);
2201 }
2202 }
2203 } else {
2204 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2205 prev = null;
2206 }
2207 mPausingActivity = null;
2208 }
2209
Dianne Hackborn55280a92009-05-07 15:53:46 -07002210 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 resumeTopActivityLocked(prev);
2212 } else {
2213 if (mGoingToSleep.isHeld()) {
2214 mGoingToSleep.release();
2215 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002216 if (mShuttingDown) {
2217 notifyAll();
2218 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 }
2220
2221 if (prev != null) {
2222 prev.resumeKeyDispatchingLocked();
2223 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002224
2225 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2226 long diff = 0;
2227 synchronized (mProcessStatsThread) {
2228 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2229 }
2230 if (diff > 0) {
2231 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2232 synchronized (bsi) {
2233 BatteryStatsImpl.Uid.Proc ps =
2234 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2235 prev.info.packageName);
2236 if (ps != null) {
2237 ps.addForegroundTimeLocked(diff);
2238 }
2239 }
2240 }
2241 }
2242 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002243 }
2244
2245 /**
2246 * Once we know that we have asked an application to put an activity in
2247 * the resumed state (either by launching it or explicitly telling it),
2248 * this function updates the rest of our state to match that fact.
2249 */
2250 private final void completeResumeLocked(HistoryRecord next) {
2251 next.idle = false;
2252 next.results = null;
2253 next.newIntents = null;
2254
2255 // schedule an idle timeout in case the app doesn't do it for us.
2256 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2257 msg.obj = next;
2258 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2259
2260 if (false) {
2261 // The activity was never told to pause, so just keep
2262 // things going as-is. To maintain our own state,
2263 // we need to emulate it coming back and saying it is
2264 // idle.
2265 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2266 msg.obj = next;
2267 mHandler.sendMessage(msg);
2268 }
2269
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002270 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002272 next.thumbnail = null;
2273 setFocusedActivityLocked(next);
2274 next.resumeKeyDispatchingLocked();
2275 ensureActivitiesVisibleLocked(null, 0);
2276 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002277 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002278
2279 // Mark the point when the activity is resuming
2280 // TODO: To be more accurate, the mark should be before the onCreate,
2281 // not after the onResume. But for subsequent starts, onResume is fine.
2282 if (next.app != null) {
2283 synchronized (mProcessStatsThread) {
2284 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2285 }
2286 } else {
2287 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2288 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002289 }
2290
2291 /**
2292 * Make sure that all activities that need to be visible (that is, they
2293 * currently can be seen by the user) actually are.
2294 */
2295 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2296 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2297 if (DEBUG_VISBILITY) Log.v(
2298 TAG, "ensureActivitiesVisible behind " + top
2299 + " configChanges=0x" + Integer.toHexString(configChanges));
2300
2301 // If the top activity is not fullscreen, then we need to
2302 // make sure any activities under it are now visible.
2303 final int count = mHistory.size();
2304 int i = count-1;
2305 while (mHistory.get(i) != top) {
2306 i--;
2307 }
2308 HistoryRecord r;
2309 boolean behindFullscreen = false;
2310 for (; i>=0; i--) {
2311 r = (HistoryRecord)mHistory.get(i);
2312 if (DEBUG_VISBILITY) Log.v(
2313 TAG, "Make visible? " + r + " finishing=" + r.finishing
2314 + " state=" + r.state);
2315 if (r.finishing) {
2316 continue;
2317 }
2318
2319 final boolean doThisProcess = onlyThisProcess == null
2320 || onlyThisProcess.equals(r.processName);
2321
2322 // First: if this is not the current activity being started, make
2323 // sure it matches the current configuration.
2324 if (r != starting && doThisProcess) {
2325 ensureActivityConfigurationLocked(r, 0);
2326 }
2327
2328 if (r.app == null || r.app.thread == null) {
2329 if (onlyThisProcess == null
2330 || onlyThisProcess.equals(r.processName)) {
2331 // This activity needs to be visible, but isn't even
2332 // running... get it started, but don't resume it
2333 // at this point.
2334 if (DEBUG_VISBILITY) Log.v(
2335 TAG, "Start and freeze screen for " + r);
2336 if (r != starting) {
2337 r.startFreezingScreenLocked(r.app, configChanges);
2338 }
2339 if (!r.visible) {
2340 if (DEBUG_VISBILITY) Log.v(
2341 TAG, "Starting and making visible: " + r);
2342 mWindowManager.setAppVisibility(r, true);
2343 }
2344 if (r != starting) {
2345 startSpecificActivityLocked(r, false, false);
2346 }
2347 }
2348
2349 } else if (r.visible) {
2350 // If this activity is already visible, then there is nothing
2351 // else to do here.
2352 if (DEBUG_VISBILITY) Log.v(
2353 TAG, "Skipping: already visible at " + r);
2354 r.stopFreezingScreenLocked(false);
2355
2356 } else if (onlyThisProcess == null) {
2357 // This activity is not currently visible, but is running.
2358 // Tell it to become visible.
2359 r.visible = true;
2360 if (r.state != ActivityState.RESUMED && r != starting) {
2361 // If this activity is paused, tell it
2362 // to now show its window.
2363 if (DEBUG_VISBILITY) Log.v(
2364 TAG, "Making visible and scheduling visibility: " + r);
2365 try {
2366 mWindowManager.setAppVisibility(r, true);
2367 r.app.thread.scheduleWindowVisibility(r, true);
2368 r.stopFreezingScreenLocked(false);
2369 } catch (Exception e) {
2370 // Just skip on any failure; we'll make it
2371 // visible when it next restarts.
2372 Log.w(TAG, "Exception thrown making visibile: "
2373 + r.intent.getComponent(), e);
2374 }
2375 }
2376 }
2377
2378 // Aggregate current change flags.
2379 configChanges |= r.configChangeFlags;
2380
2381 if (r.fullscreen) {
2382 // At this point, nothing else needs to be shown
2383 if (DEBUG_VISBILITY) Log.v(
2384 TAG, "Stopping: fullscreen at " + r);
2385 behindFullscreen = true;
2386 i--;
2387 break;
2388 }
2389 }
2390
2391 // Now for any activities that aren't visible to the user, make
2392 // sure they no longer are keeping the screen frozen.
2393 while (i >= 0) {
2394 r = (HistoryRecord)mHistory.get(i);
2395 if (DEBUG_VISBILITY) Log.v(
2396 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2397 + " state=" + r.state
2398 + " behindFullscreen=" + behindFullscreen);
2399 if (!r.finishing) {
2400 if (behindFullscreen) {
2401 if (r.visible) {
2402 if (DEBUG_VISBILITY) Log.v(
2403 TAG, "Making invisible: " + r);
2404 r.visible = false;
2405 try {
2406 mWindowManager.setAppVisibility(r, false);
2407 if ((r.state == ActivityState.STOPPING
2408 || r.state == ActivityState.STOPPED)
2409 && r.app != null && r.app.thread != null) {
2410 if (DEBUG_VISBILITY) Log.v(
2411 TAG, "Scheduling invisibility: " + r);
2412 r.app.thread.scheduleWindowVisibility(r, false);
2413 }
2414 } catch (Exception e) {
2415 // Just skip on any failure; we'll make it
2416 // visible when it next restarts.
2417 Log.w(TAG, "Exception thrown making hidden: "
2418 + r.intent.getComponent(), e);
2419 }
2420 } else {
2421 if (DEBUG_VISBILITY) Log.v(
2422 TAG, "Already invisible: " + r);
2423 }
2424 } else if (r.fullscreen) {
2425 if (DEBUG_VISBILITY) Log.v(
2426 TAG, "Now behindFullscreen: " + r);
2427 behindFullscreen = true;
2428 }
2429 }
2430 i--;
2431 }
2432 }
2433
2434 /**
2435 * Version of ensureActivitiesVisible that can easily be called anywhere.
2436 */
2437 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2438 int configChanges) {
2439 HistoryRecord r = topRunningActivityLocked(null);
2440 if (r != null) {
2441 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2442 }
2443 }
2444
2445 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2446 if (resumed) {
2447 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2448 } else {
2449 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2450 }
2451 }
2452
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002453 private boolean startHomeActivityLocked() {
2454 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2455 && mTopAction == null) {
2456 // We are running in factory test mode, but unable to find
2457 // the factory test app, so just sit around displaying the
2458 // error message and don't try to start anything.
2459 return false;
2460 }
2461 Intent intent = new Intent(
2462 mTopAction,
2463 mTopData != null ? Uri.parse(mTopData) : null);
2464 intent.setComponent(mTopComponent);
2465 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2466 intent.addCategory(Intent.CATEGORY_HOME);
2467 }
2468 ActivityInfo aInfo =
2469 intent.resolveActivityInfo(mContext.getPackageManager(),
2470 STOCK_PM_FLAGS);
2471 if (aInfo != null) {
2472 intent.setComponent(new ComponentName(
2473 aInfo.applicationInfo.packageName, aInfo.name));
2474 // Don't do this if the home app is currently being
2475 // instrumented.
2476 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2477 aInfo.applicationInfo.uid);
2478 if (app == null || app.instrumentationClass == null) {
2479 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2480 startActivityLocked(null, intent, null, null, 0, aInfo,
2481 null, null, 0, 0, 0, false, false);
2482 }
2483 }
2484
2485
2486 return true;
2487 }
2488
2489 /**
2490 * Starts the "new version setup screen" if appropriate.
2491 */
2492 private void startSetupActivityLocked() {
2493 // Only do this once per boot.
2494 if (mCheckedForSetup) {
2495 return;
2496 }
2497
2498 // We will show this screen if the current one is a different
2499 // version than the last one shown, and we are not running in
2500 // low-level factory test mode.
2501 final ContentResolver resolver = mContext.getContentResolver();
2502 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2503 Settings.Secure.getInt(resolver,
2504 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2505 mCheckedForSetup = true;
2506
2507 // See if we should be showing the platform update setup UI.
2508 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2509 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2510 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2511
2512 // We don't allow third party apps to replace this.
2513 ResolveInfo ri = null;
2514 for (int i=0; ris != null && i<ris.size(); i++) {
2515 if ((ris.get(i).activityInfo.applicationInfo.flags
2516 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2517 ri = ris.get(i);
2518 break;
2519 }
2520 }
2521
2522 if (ri != null) {
2523 String vers = ri.activityInfo.metaData != null
2524 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2525 : null;
2526 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2527 vers = ri.activityInfo.applicationInfo.metaData.getString(
2528 Intent.METADATA_SETUP_VERSION);
2529 }
2530 String lastVers = Settings.Secure.getString(
2531 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2532 if (vers != null && !vers.equals(lastVers)) {
2533 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2534 intent.setComponent(new ComponentName(
2535 ri.activityInfo.packageName, ri.activityInfo.name));
2536 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2537 null, null, 0, 0, 0, false, false);
2538 }
2539 }
2540 }
2541 }
2542
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002543 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002544 //Log.i(TAG, "**** REPORT RESUME: " + r);
2545
2546 final int identHash = System.identityHashCode(r);
2547 updateUsageStats(r, true);
2548
2549 int i = mWatchers.beginBroadcast();
2550 while (i > 0) {
2551 i--;
2552 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2553 if (w != null) {
2554 try {
2555 w.activityResuming(identHash);
2556 } catch (RemoteException e) {
2557 }
2558 }
2559 }
2560 mWatchers.finishBroadcast();
2561 }
2562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002563 /**
2564 * Ensure that the top activity in the stack is resumed.
2565 *
2566 * @param prev The previously resumed activity, for when in the process
2567 * of pausing; can be null to call from elsewhere.
2568 *
2569 * @return Returns true if something is being resumed, or false if
2570 * nothing happened.
2571 */
2572 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2573 // Find the first activity that is not finishing.
2574 HistoryRecord next = topRunningActivityLocked(null);
2575
2576 // Remember how we'll process this pause/resume situation, and ensure
2577 // that the state is reset however we wind up proceeding.
2578 final boolean userLeaving = mUserLeaving;
2579 mUserLeaving = false;
2580
2581 if (next == null) {
2582 // There are no more activities! Let's just start up the
2583 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002584 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002585 }
2586
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002587 next.delayedResume = false;
2588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589 // If the top activity is the resumed one, nothing to do.
2590 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2591 // Make sure we have executed any pending transitions, since there
2592 // should be nothing left to do at this point.
2593 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002594 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002595 return false;
2596 }
2597
2598 // If we are sleeping, and there is no resumed activity, and the top
2599 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002600 if ((mSleeping || mShuttingDown)
2601 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002602 // Make sure we have executed any pending transitions, since there
2603 // should be nothing left to do at this point.
2604 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002605 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002606 return false;
2607 }
2608
2609 // The activity may be waiting for stop, but that is no longer
2610 // appropriate for it.
2611 mStoppingActivities.remove(next);
2612 mWaitingVisibleActivities.remove(next);
2613
2614 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2615
2616 // If we are currently pausing an activity, then don't do anything
2617 // until that is done.
2618 if (mPausingActivity != null) {
2619 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2620 return false;
2621 }
2622
2623 // We need to start pausing the current activity so the top one
2624 // can be resumed...
2625 if (mResumedActivity != null) {
2626 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2627 startPausingLocked(userLeaving, false);
2628 return true;
2629 }
2630
2631 if (prev != null && prev != next) {
2632 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2633 prev.waitingVisible = true;
2634 mWaitingVisibleActivities.add(prev);
2635 if (DEBUG_SWITCH) Log.v(
2636 TAG, "Resuming top, waiting visible to hide: " + prev);
2637 } else {
2638 // The next activity is already visible, so hide the previous
2639 // activity's windows right now so we can show the new one ASAP.
2640 // We only do this if the previous is finishing, which should mean
2641 // it is on top of the one being resumed so hiding it quickly
2642 // is good. Otherwise, we want to do the normal route of allowing
2643 // the resumed activity to be shown so we can decide if the
2644 // previous should actually be hidden depending on whether the
2645 // new one is found to be full-screen or not.
2646 if (prev.finishing) {
2647 mWindowManager.setAppVisibility(prev, false);
2648 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2649 + prev + ", waitingVisible="
2650 + (prev != null ? prev.waitingVisible : null)
2651 + ", nowVisible=" + next.nowVisible);
2652 } else {
2653 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2654 + prev + ", waitingVisible="
2655 + (prev != null ? prev.waitingVisible : null)
2656 + ", nowVisible=" + next.nowVisible);
2657 }
2658 }
2659 }
2660
2661 // We are starting up the next activity, so tell the window manager
2662 // that the previous one will be hidden soon. This way it can know
2663 // to ignore it when computing the desired screen orientation.
2664 if (prev != null) {
2665 if (prev.finishing) {
2666 if (DEBUG_TRANSITION) Log.v(TAG,
2667 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002668 if (mNoAnimActivities.contains(prev)) {
2669 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2670 } else {
2671 mWindowManager.prepareAppTransition(prev.task == next.task
2672 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2673 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2674 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 mWindowManager.setAppWillBeHidden(prev);
2676 mWindowManager.setAppVisibility(prev, false);
2677 } else {
2678 if (DEBUG_TRANSITION) Log.v(TAG,
2679 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002680 if (mNoAnimActivities.contains(next)) {
2681 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2682 } else {
2683 mWindowManager.prepareAppTransition(prev.task == next.task
2684 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2685 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 }
2688 if (false) {
2689 mWindowManager.setAppWillBeHidden(prev);
2690 mWindowManager.setAppVisibility(prev, false);
2691 }
2692 } else if (mHistory.size() > 1) {
2693 if (DEBUG_TRANSITION) Log.v(TAG,
2694 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002695 if (mNoAnimActivities.contains(next)) {
2696 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2697 } else {
2698 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2699 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002700 }
2701
2702 if (next.app != null && next.app.thread != null) {
2703 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2704
2705 // This activity is now becoming visible.
2706 mWindowManager.setAppVisibility(next, true);
2707
2708 HistoryRecord lastResumedActivity = mResumedActivity;
2709 ActivityState lastState = next.state;
2710
2711 updateCpuStats();
2712
2713 next.state = ActivityState.RESUMED;
2714 mResumedActivity = next;
2715 next.task.touchActiveTime();
2716 updateLRUListLocked(next.app, true);
2717 updateLRUListLocked(next);
2718
2719 // Have the window manager re-evaluate the orientation of
2720 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002721 boolean updated;
2722 synchronized (this) {
2723 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2724 mConfiguration,
2725 next.mayFreezeScreenLocked(next.app) ? next : null);
2726 if (config != null) {
2727 /*
2728 * Explicitly restore the locale to the one from the
2729 * old configuration, since the one that comes back from
2730 * the window manager has the default (boot) locale.
2731 *
2732 * It looks like previously the locale picker only worked
2733 * by coincidence: usually it would do its setting of
2734 * the locale after the activity transition, so it didn't
2735 * matter that this lost it. With the synchronized
2736 * block now keeping them from happening at the same time,
2737 * this one always would happen second and undo what the
2738 * locale picker had just done.
2739 */
2740 config.locale = mConfiguration.locale;
2741 next.frozenBeforeDestroy = true;
2742 }
2743 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002745 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002746 // The configuration update wasn't able to keep the existing
2747 // instance of the activity, and instead started a new one.
2748 // We should be all done, but let's just make sure our activity
2749 // is still at the top and schedule another run if something
2750 // weird happened.
2751 HistoryRecord nextNext = topRunningActivityLocked(null);
2752 if (DEBUG_SWITCH) Log.i(TAG,
2753 "Activity config changed during resume: " + next
2754 + ", new next: " + nextNext);
2755 if (nextNext != next) {
2756 // Do over!
2757 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2758 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002759 setFocusedActivityLocked(next);
2760 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002761 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002762 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002763 return true;
2764 }
2765
2766 try {
2767 // Deliver all pending results.
2768 ArrayList a = next.results;
2769 if (a != null) {
2770 final int N = a.size();
2771 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002772 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002773 TAG, "Delivering results to " + next
2774 + ": " + a);
2775 next.app.thread.scheduleSendResult(next, a);
2776 }
2777 }
2778
2779 if (next.newIntents != null) {
2780 next.app.thread.scheduleNewIntent(next.newIntents, next);
2781 }
2782
2783 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2784 System.identityHashCode(next),
2785 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002786
2787 next.app.thread.scheduleResumeActivity(next,
2788 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002790 pauseIfSleepingLocked();
2791
2792 } catch (Exception e) {
2793 // Whoops, need to restart this activity!
2794 next.state = lastState;
2795 mResumedActivity = lastResumedActivity;
2796 if (Config.LOGD) Log.d(TAG,
2797 "Restarting because process died: " + next);
2798 if (!next.hasBeenLaunched) {
2799 next.hasBeenLaunched = true;
2800 } else {
2801 if (SHOW_APP_STARTING_ICON) {
2802 mWindowManager.setAppStartingWindow(
2803 next, next.packageName, next.theme,
2804 next.nonLocalizedLabel,
2805 next.labelRes, next.icon, null, true);
2806 }
2807 }
2808 startSpecificActivityLocked(next, true, false);
2809 return true;
2810 }
2811
2812 // From this point on, if something goes wrong there is no way
2813 // to recover the activity.
2814 try {
2815 next.visible = true;
2816 completeResumeLocked(next);
2817 } catch (Exception e) {
2818 // If any exception gets thrown, toss away this
2819 // activity and try the next one.
2820 Log.w(TAG, "Exception thrown during resume of " + next, e);
2821 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2822 "resume-exception");
2823 return true;
2824 }
2825
2826 // Didn't need to use the icicle, and it is now out of date.
2827 next.icicle = null;
2828 next.haveState = false;
2829 next.stopped = false;
2830
2831 } else {
2832 // Whoops, need to restart this activity!
2833 if (!next.hasBeenLaunched) {
2834 next.hasBeenLaunched = true;
2835 } else {
2836 if (SHOW_APP_STARTING_ICON) {
2837 mWindowManager.setAppStartingWindow(
2838 next, next.packageName, next.theme,
2839 next.nonLocalizedLabel,
2840 next.labelRes, next.icon, null, true);
2841 }
2842 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2843 }
2844 startSpecificActivityLocked(next, true, true);
2845 }
2846
2847 return true;
2848 }
2849
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002850 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2851 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002852 final int NH = mHistory.size();
2853
2854 int addPos = -1;
2855
2856 if (!newTask) {
2857 // If starting in an existing task, find where that is...
2858 HistoryRecord next = null;
2859 boolean startIt = true;
2860 for (int i = NH-1; i >= 0; i--) {
2861 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2862 if (p.finishing) {
2863 continue;
2864 }
2865 if (p.task == r.task) {
2866 // Here it is! Now, if this is not yet visible to the
2867 // user, then just add it without starting; it will
2868 // get started when the user navigates back to it.
2869 addPos = i+1;
2870 if (!startIt) {
2871 mHistory.add(addPos, r);
2872 r.inHistory = true;
2873 r.task.numActivities++;
2874 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2875 r.info.screenOrientation, r.fullscreen);
2876 if (VALIDATE_TOKENS) {
2877 mWindowManager.validateAppTokens(mHistory);
2878 }
2879 return;
2880 }
2881 break;
2882 }
2883 if (p.fullscreen) {
2884 startIt = false;
2885 }
2886 next = p;
2887 }
2888 }
2889
2890 // Place a new activity at top of stack, so it is next to interact
2891 // with the user.
2892 if (addPos < 0) {
2893 addPos = mHistory.size();
2894 }
2895
2896 // If we are not placing the new activity frontmost, we do not want
2897 // to deliver the onUserLeaving callback to the actual frontmost
2898 // activity
2899 if (addPos < NH) {
2900 mUserLeaving = false;
2901 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2902 }
2903
2904 // Slot the activity into the history stack and proceed
2905 mHistory.add(addPos, r);
2906 r.inHistory = true;
2907 r.frontOfTask = newTask;
2908 r.task.numActivities++;
2909 if (NH > 0) {
2910 // We want to show the starting preview window if we are
2911 // switching to a new task, or the next activity's process is
2912 // not currently running.
2913 boolean showStartingIcon = newTask;
2914 ProcessRecord proc = r.app;
2915 if (proc == null) {
2916 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2917 }
2918 if (proc == null || proc.thread == null) {
2919 showStartingIcon = true;
2920 }
2921 if (DEBUG_TRANSITION) Log.v(TAG,
2922 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002923 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2924 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2925 mNoAnimActivities.add(r);
2926 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2927 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2928 mNoAnimActivities.remove(r);
2929 } else {
2930 mWindowManager.prepareAppTransition(newTask
2931 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2932 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2933 mNoAnimActivities.remove(r);
2934 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 mWindowManager.addAppToken(
2936 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2937 boolean doShow = true;
2938 if (newTask) {
2939 // Even though this activity is starting fresh, we still need
2940 // to reset it to make sure we apply affinities to move any
2941 // existing activities from other tasks in to it.
2942 // If the caller has requested that the target task be
2943 // reset, then do so.
2944 if ((r.intent.getFlags()
2945 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2946 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002947 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 }
2949 }
2950 if (SHOW_APP_STARTING_ICON && doShow) {
2951 // Figure out if we are transitioning from another activity that is
2952 // "has the same starting icon" as the next one. This allows the
2953 // window manager to keep the previous window it had previously
2954 // created, if it still had one.
2955 HistoryRecord prev = mResumedActivity;
2956 if (prev != null) {
2957 // We don't want to reuse the previous starting preview if:
2958 // (1) The current activity is in a different task.
2959 if (prev.task != r.task) prev = null;
2960 // (2) The current activity is already displayed.
2961 else if (prev.nowVisible) prev = null;
2962 }
2963 mWindowManager.setAppStartingWindow(
2964 r, r.packageName, r.theme, r.nonLocalizedLabel,
2965 r.labelRes, r.icon, prev, showStartingIcon);
2966 }
2967 } else {
2968 // If this is the first activity, don't do any fancy animations,
2969 // because there is nothing for it to animate on top of.
2970 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2971 r.info.screenOrientation, r.fullscreen);
2972 }
2973 if (VALIDATE_TOKENS) {
2974 mWindowManager.validateAppTokens(mHistory);
2975 }
2976
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002977 if (doResume) {
2978 resumeTopActivityLocked(null);
2979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 }
2981
2982 /**
2983 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002984 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2985 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002986 * an instance of that activity in the stack and, if found, finish all
2987 * activities on top of it and return the instance.
2988 *
2989 * @param newR Description of the new activity being started.
2990 * @return Returns the old activity that should be continue to be used,
2991 * or null if none was found.
2992 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002993 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002994 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002995 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002996
2997 // First find the requested task.
2998 while (i > 0) {
2999 i--;
3000 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3001 if (r.task.taskId == taskId) {
3002 i++;
3003 break;
3004 }
3005 }
3006
3007 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003008 while (i > 0) {
3009 i--;
3010 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3011 if (r.finishing) {
3012 continue;
3013 }
3014 if (r.task.taskId != taskId) {
3015 return null;
3016 }
3017 if (r.realActivity.equals(newR.realActivity)) {
3018 // Here it is! Now finish everything in front...
3019 HistoryRecord ret = r;
3020 if (doClear) {
3021 while (i < (mHistory.size()-1)) {
3022 i++;
3023 r = (HistoryRecord)mHistory.get(i);
3024 if (r.finishing) {
3025 continue;
3026 }
3027 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
3028 null, "clear")) {
3029 i--;
3030 }
3031 }
3032 }
3033
3034 // Finally, if this is a normal launch mode (that is, not
3035 // expecting onNewIntent()), then we will finish the current
3036 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003037 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3038 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003039 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003040 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003041 if (index >= 0) {
3042 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3043 null, "clear");
3044 }
3045 return null;
3046 }
3047 }
3048
3049 return ret;
3050 }
3051 }
3052
3053 return null;
3054 }
3055
3056 /**
3057 * Find the activity in the history stack within the given task. Returns
3058 * the index within the history at which it's found, or < 0 if not found.
3059 */
3060 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3061 int i = mHistory.size();
3062 while (i > 0) {
3063 i--;
3064 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3065 if (candidate.task.taskId != task) {
3066 break;
3067 }
3068 if (candidate.realActivity.equals(r.realActivity)) {
3069 return i;
3070 }
3071 }
3072
3073 return -1;
3074 }
3075
3076 /**
3077 * Reorder the history stack so that the activity at the given index is
3078 * brought to the front.
3079 */
3080 private final HistoryRecord moveActivityToFrontLocked(int where) {
3081 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3082 int top = mHistory.size();
3083 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3084 mHistory.add(top, newTop);
3085 oldTop.frontOfTask = false;
3086 newTop.frontOfTask = true;
3087 return newTop;
3088 }
3089
3090 /**
3091 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3092 * method will be called at the proper time.
3093 */
3094 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3095 boolean sent = false;
3096 if (r.state == ActivityState.RESUMED
3097 && r.app != null && r.app.thread != null) {
3098 try {
3099 ArrayList<Intent> ar = new ArrayList<Intent>();
3100 ar.add(new Intent(intent));
3101 r.app.thread.scheduleNewIntent(ar, r);
3102 sent = true;
3103 } catch (Exception e) {
3104 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3105 }
3106 }
3107 if (!sent) {
3108 r.addNewIntentLocked(new Intent(intent));
3109 }
3110 }
3111
3112 private final void logStartActivity(int tag, HistoryRecord r,
3113 TaskRecord task) {
3114 EventLog.writeEvent(tag,
3115 System.identityHashCode(r), task.taskId,
3116 r.shortComponentName, r.intent.getAction(),
3117 r.intent.getType(), r.intent.getDataString(),
3118 r.intent.getFlags());
3119 }
3120
3121 private final int startActivityLocked(IApplicationThread caller,
3122 Intent intent, String resolvedType,
3123 Uri[] grantedUriPermissions,
3124 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3125 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003126 int callingPid, int callingUid, boolean onlyIfNeeded,
3127 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128 Log.i(TAG, "Starting activity: " + intent);
3129
3130 HistoryRecord sourceRecord = null;
3131 HistoryRecord resultRecord = null;
3132 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003133 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003134 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003135 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3136 if (index >= 0) {
3137 sourceRecord = (HistoryRecord)mHistory.get(index);
3138 if (requestCode >= 0 && !sourceRecord.finishing) {
3139 resultRecord = sourceRecord;
3140 }
3141 }
3142 }
3143
3144 int launchFlags = intent.getFlags();
3145
3146 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3147 && sourceRecord != null) {
3148 // Transfer the result target from the source activity to the new
3149 // one being started, including any failures.
3150 if (requestCode >= 0) {
3151 return START_FORWARD_AND_REQUEST_CONFLICT;
3152 }
3153 resultRecord = sourceRecord.resultTo;
3154 resultWho = sourceRecord.resultWho;
3155 requestCode = sourceRecord.requestCode;
3156 sourceRecord.resultTo = null;
3157 if (resultRecord != null) {
3158 resultRecord.removeResultsLocked(
3159 sourceRecord, resultWho, requestCode);
3160 }
3161 }
3162
3163 int err = START_SUCCESS;
3164
3165 if (intent.getComponent() == null) {
3166 // We couldn't find a class that can handle the given Intent.
3167 // That's the end of that!
3168 err = START_INTENT_NOT_RESOLVED;
3169 }
3170
3171 if (err == START_SUCCESS && aInfo == null) {
3172 // We couldn't find the specific class specified in the Intent.
3173 // Also the end of the line.
3174 err = START_CLASS_NOT_FOUND;
3175 }
3176
3177 ProcessRecord callerApp = null;
3178 if (err == START_SUCCESS && caller != null) {
3179 callerApp = getRecordForAppLocked(caller);
3180 if (callerApp != null) {
3181 callingPid = callerApp.pid;
3182 callingUid = callerApp.info.uid;
3183 } else {
3184 Log.w(TAG, "Unable to find app for caller " + caller
3185 + " (pid=" + callingPid + ") when starting: "
3186 + intent.toString());
3187 err = START_PERMISSION_DENIED;
3188 }
3189 }
3190
3191 if (err != START_SUCCESS) {
3192 if (resultRecord != null) {
3193 sendActivityResultLocked(-1,
3194 resultRecord, resultWho, requestCode,
3195 Activity.RESULT_CANCELED, null);
3196 }
3197 return err;
3198 }
3199
3200 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3201 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3202 if (perm != PackageManager.PERMISSION_GRANTED) {
3203 if (resultRecord != null) {
3204 sendActivityResultLocked(-1,
3205 resultRecord, resultWho, requestCode,
3206 Activity.RESULT_CANCELED, null);
3207 }
3208 String msg = "Permission Denial: starting " + intent.toString()
3209 + " from " + callerApp + " (pid=" + callingPid
3210 + ", uid=" + callingUid + ")"
3211 + " requires " + aInfo.permission;
3212 Log.w(TAG, msg);
3213 throw new SecurityException(msg);
3214 }
3215
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003216 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 boolean abort = false;
3218 try {
3219 // The Intent we give to the watcher has the extra data
3220 // stripped off, since it can contain private information.
3221 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003222 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 aInfo.applicationInfo.packageName);
3224 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003225 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003226 }
3227
3228 if (abort) {
3229 if (resultRecord != null) {
3230 sendActivityResultLocked(-1,
3231 resultRecord, resultWho, requestCode,
3232 Activity.RESULT_CANCELED, null);
3233 }
3234 // We pretend to the caller that it was really started, but
3235 // they will just get a cancel result.
3236 return START_SUCCESS;
3237 }
3238 }
3239
3240 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3241 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003242 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003244 if (mResumedActivity == null
3245 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3246 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3247 PendingActivityLaunch pal = new PendingActivityLaunch();
3248 pal.r = r;
3249 pal.sourceRecord = sourceRecord;
3250 pal.grantedUriPermissions = grantedUriPermissions;
3251 pal.grantedMode = grantedMode;
3252 pal.onlyIfNeeded = onlyIfNeeded;
3253 mPendingActivityLaunches.add(pal);
3254 return START_SWITCHES_CANCELED;
3255 }
3256 }
3257
3258 if (mDidAppSwitch) {
3259 // This is the second allowed switch since we stopped switches,
3260 // so now just generally allow switches. Use case: user presses
3261 // home (switches disabled, switch to home, mDidAppSwitch now true);
3262 // user taps a home icon (coming from home so allowed, we hit here
3263 // and now allow anyone to switch again).
3264 mAppSwitchesAllowedTime = 0;
3265 } else {
3266 mDidAppSwitch = true;
3267 }
3268
3269 doPendingActivityLaunchesLocked(false);
3270
3271 return startActivityUncheckedLocked(r, sourceRecord,
3272 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3273 }
3274
3275 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3276 final int N = mPendingActivityLaunches.size();
3277 if (N <= 0) {
3278 return;
3279 }
3280 for (int i=0; i<N; i++) {
3281 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3282 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3283 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3284 doResume && i == (N-1));
3285 }
3286 mPendingActivityLaunches.clear();
3287 }
3288
3289 private final int startActivityUncheckedLocked(HistoryRecord r,
3290 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3291 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3292 final Intent intent = r.intent;
3293 final int callingUid = r.launchedFromUid;
3294
3295 int launchFlags = intent.getFlags();
3296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 // We'll invoke onUserLeaving before onPause only if the launching
3298 // activity did not explicitly state that this is an automated launch.
3299 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3300 if (DEBUG_USER_LEAVING) Log.v(TAG,
3301 "startActivity() => mUserLeaving=" + mUserLeaving);
3302
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003303 // If the caller has asked not to resume at this point, we make note
3304 // of this in the record so that we can skip it when trying to find
3305 // the top running activity.
3306 if (!doResume) {
3307 r.delayedResume = true;
3308 }
3309
3310 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3311 != 0 ? r : null;
3312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003313 // If the onlyIfNeeded flag is set, then we can do this if the activity
3314 // being launched is the same as the one making the call... or, as
3315 // a special case, if we do not know the caller then we count the
3316 // current top activity as the caller.
3317 if (onlyIfNeeded) {
3318 HistoryRecord checkedCaller = sourceRecord;
3319 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003320 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321 }
3322 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3323 // Caller is not the same as launcher, so always needed.
3324 onlyIfNeeded = false;
3325 }
3326 }
3327
3328 if (grantedUriPermissions != null && callingUid > 0) {
3329 for (int i=0; i<grantedUriPermissions.length; i++) {
3330 grantUriPermissionLocked(callingUid, r.packageName,
3331 grantedUriPermissions[i], grantedMode, r);
3332 }
3333 }
3334
3335 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3336 intent, r);
3337
3338 if (sourceRecord == null) {
3339 // This activity is not being started from another... in this
3340 // case we -always- start a new task.
3341 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3342 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3343 + intent);
3344 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3345 }
3346 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3347 // The original activity who is starting us is running as a single
3348 // instance... this new activity it is starting must go on its
3349 // own task.
3350 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3351 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3352 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3353 // The activity being started is a single instance... it always
3354 // gets launched into its own task.
3355 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3356 }
3357
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003358 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 // For whatever reason this activity is being launched into a new
3360 // task... yet the caller has requested a result back. Well, that
3361 // is pretty messed up, so instead immediately send back a cancel
3362 // and let the new task continue launched as normal without a
3363 // dependency on its originator.
3364 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3365 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003366 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 Activity.RESULT_CANCELED, null);
3368 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 }
3370
3371 boolean addingToTask = false;
3372 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3373 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3374 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3375 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3376 // If bring to front is requested, and no result is requested, and
3377 // we can find a task that was started with this same
3378 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003379 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003380 // See if there is a task to bring to the front. If this is
3381 // a SINGLE_INSTANCE activity, there can be one and only one
3382 // instance of it in the history, and it is always in its own
3383 // unique task, so we do a special search.
3384 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3385 ? findTaskLocked(intent, r.info)
3386 : findActivityLocked(intent, r.info);
3387 if (taskTop != null) {
3388 if (taskTop.task.intent == null) {
3389 // This task was started because of movement of
3390 // the activity based on affinity... now that we
3391 // are actually launching it, we can assign the
3392 // base intent.
3393 taskTop.task.setIntent(intent, r.info);
3394 }
3395 // If the target task is not in the front, then we need
3396 // to bring it to the front... except... well, with
3397 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3398 // to have the same behavior as if a new instance was
3399 // being started, which means not bringing it to the front
3400 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003401 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003402 if (curTop.task != taskTop.task) {
3403 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3404 boolean callerAtFront = sourceRecord == null
3405 || curTop.task == sourceRecord.task;
3406 if (callerAtFront) {
3407 // We really do want to push this one into the
3408 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003409 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003410 }
3411 }
3412 // If the caller has requested that the target task be
3413 // reset, then do so.
3414 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3415 taskTop = resetTaskIfNeededLocked(taskTop, r);
3416 }
3417 if (onlyIfNeeded) {
3418 // We don't need to start a new activity, and
3419 // the client said not to do anything if that
3420 // is the case, so this is it! And for paranoia, make
3421 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003422 if (doResume) {
3423 resumeTopActivityLocked(null);
3424 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003425 return START_RETURN_INTENT_TO_CALLER;
3426 }
3427 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3428 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3429 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3430 // In this situation we want to remove all activities
3431 // from the task up to the one being started. In most
3432 // cases this means we are resetting the task to its
3433 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003434 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003435 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 if (top != null) {
3437 if (top.frontOfTask) {
3438 // Activity aliases may mean we use different
3439 // intents for the top activity, so make sure
3440 // the task now has the identity of the new
3441 // intent.
3442 top.task.setIntent(r.intent, r.info);
3443 }
3444 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3445 deliverNewIntentLocked(top, r.intent);
3446 } else {
3447 // A special case: we need to
3448 // start the activity because it is not currently
3449 // running, and the caller has asked to clear the
3450 // current task to have this activity at the top.
3451 addingToTask = true;
3452 // Now pretend like this activity is being started
3453 // by the top of its task, so it is put in the
3454 // right place.
3455 sourceRecord = taskTop;
3456 }
3457 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3458 // In this case the top activity on the task is the
3459 // same as the one being launched, so we take that
3460 // as a request to bring the task to the foreground.
3461 // If the top activity in the task is the root
3462 // activity, deliver this new intent to it if it
3463 // desires.
3464 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3465 && taskTop.realActivity.equals(r.realActivity)) {
3466 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3467 if (taskTop.frontOfTask) {
3468 taskTop.task.setIntent(r.intent, r.info);
3469 }
3470 deliverNewIntentLocked(taskTop, r.intent);
3471 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3472 // In this case we are launching the root activity
3473 // of the task, but with a different intent. We
3474 // should start a new instance on top.
3475 addingToTask = true;
3476 sourceRecord = taskTop;
3477 }
3478 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3479 // In this case an activity is being launched in to an
3480 // existing task, without resetting that task. This
3481 // is typically the situation of launching an activity
3482 // from a notification or shortcut. We want to place
3483 // the new activity on top of the current task.
3484 addingToTask = true;
3485 sourceRecord = taskTop;
3486 } else if (!taskTop.task.rootWasReset) {
3487 // In this case we are launching in to an existing task
3488 // that has not yet been started from its front door.
3489 // The current task has been brought to the front.
3490 // Ideally, we'd probably like to place this new task
3491 // at the bottom of its stack, but that's a little hard
3492 // to do with the current organization of the code so
3493 // for now we'll just drop it.
3494 taskTop.task.setIntent(r.intent, r.info);
3495 }
3496 if (!addingToTask) {
3497 // We didn't do anything... but it was needed (a.k.a., client
3498 // don't use that intent!) And for paranoia, make
3499 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003500 if (doResume) {
3501 resumeTopActivityLocked(null);
3502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003503 return START_TASK_TO_FRONT;
3504 }
3505 }
3506 }
3507 }
3508
3509 //String uri = r.intent.toURI();
3510 //Intent intent2 = new Intent(uri);
3511 //Log.i(TAG, "Given intent: " + r.intent);
3512 //Log.i(TAG, "URI is: " + uri);
3513 //Log.i(TAG, "To intent: " + intent2);
3514
3515 if (r.packageName != null) {
3516 // If the activity being launched is the same as the one currently
3517 // at the top, then we need to check if it should only be launched
3518 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003519 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3520 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 if (top.realActivity.equals(r.realActivity)) {
3522 if (top.app != null && top.app.thread != null) {
3523 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3524 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3525 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3526 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3527 // For paranoia, make sure we have correctly
3528 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003529 if (doResume) {
3530 resumeTopActivityLocked(null);
3531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 if (onlyIfNeeded) {
3533 // We don't need to start a new activity, and
3534 // the client said not to do anything if that
3535 // is the case, so this is it!
3536 return START_RETURN_INTENT_TO_CALLER;
3537 }
3538 deliverNewIntentLocked(top, r.intent);
3539 return START_DELIVERED_TO_TOP;
3540 }
3541 }
3542 }
3543 }
3544
3545 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003546 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003547 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003548 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 Activity.RESULT_CANCELED, null);
3550 }
3551 return START_CLASS_NOT_FOUND;
3552 }
3553
3554 boolean newTask = false;
3555
3556 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003557 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003558 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3559 // todo: should do better management of integers.
3560 mCurTask++;
3561 if (mCurTask <= 0) {
3562 mCurTask = 1;
3563 }
3564 r.task = new TaskRecord(mCurTask, r.info, intent,
3565 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3566 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3567 + " in new task " + r.task);
3568 newTask = true;
Josh Bartel7f208742010-02-25 11:01:44 -06003569 addRecentTaskLocked(r.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003570
3571 } else if (sourceRecord != null) {
3572 if (!addingToTask &&
3573 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3574 // In this case, we are adding the activity to an existing
3575 // task, but the caller has asked to clear that task if the
3576 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003577 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003578 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003579 if (top != null) {
3580 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3581 deliverNewIntentLocked(top, r.intent);
3582 // For paranoia, make sure we have correctly
3583 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003584 if (doResume) {
3585 resumeTopActivityLocked(null);
3586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003587 return START_DELIVERED_TO_TOP;
3588 }
3589 } else if (!addingToTask &&
3590 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3591 // In this case, we are launching an activity in our own task
3592 // that may already be running somewhere in the history, and
3593 // we want to shuffle it to the front of the stack if so.
3594 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3595 if (where >= 0) {
3596 HistoryRecord top = moveActivityToFrontLocked(where);
3597 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3598 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003599 if (doResume) {
3600 resumeTopActivityLocked(null);
3601 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003602 return START_DELIVERED_TO_TOP;
3603 }
3604 }
3605 // An existing activity is starting this new activity, so we want
3606 // to keep the new one in the same task as the one that is starting
3607 // it.
3608 r.task = sourceRecord.task;
3609 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3610 + " in existing task " + r.task);
3611
3612 } else {
3613 // This not being started from an existing activity, and not part
3614 // of a new task... just put it in the top task, though these days
3615 // this case should never happen.
3616 final int N = mHistory.size();
3617 HistoryRecord prev =
3618 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3619 r.task = prev != null
3620 ? prev.task
3621 : new TaskRecord(mCurTask, r.info, intent,
3622 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3623 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3624 + " in new guessed " + r.task);
3625 }
3626 if (newTask) {
3627 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3628 }
3629 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003630 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003631 return START_SUCCESS;
3632 }
3633
3634 public final int startActivity(IApplicationThread caller,
3635 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3636 int grantedMode, IBinder resultTo,
3637 String resultWho, int requestCode, boolean onlyIfNeeded,
3638 boolean debug) {
3639 // Refuse possible leaked file descriptors
3640 if (intent != null && intent.hasFileDescriptors()) {
3641 throw new IllegalArgumentException("File descriptors passed in Intent");
3642 }
3643
The Android Open Source Project4df24232009-03-05 14:34:35 -08003644 final boolean componentSpecified = intent.getComponent() != null;
3645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003646 // Don't modify the client's object!
3647 intent = new Intent(intent);
3648
3649 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 ActivityInfo aInfo;
3651 try {
3652 ResolveInfo rInfo =
3653 ActivityThread.getPackageManager().resolveIntent(
3654 intent, resolvedType,
3655 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003656 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003657 aInfo = rInfo != null ? rInfo.activityInfo : null;
3658 } catch (RemoteException e) {
3659 aInfo = null;
3660 }
3661
3662 if (aInfo != null) {
3663 // Store the found target back into the intent, because now that
3664 // we have it we never want to do this again. For example, if the
3665 // user navigates back to this point in the history, we should
3666 // always restart the exact same activity.
3667 intent.setComponent(new ComponentName(
3668 aInfo.applicationInfo.packageName, aInfo.name));
3669
3670 // Don't debug things in the system process
3671 if (debug) {
3672 if (!aInfo.processName.equals("system")) {
3673 setDebugApp(aInfo.processName, true, false);
3674 }
3675 }
3676 }
3677
3678 synchronized(this) {
3679 final long origId = Binder.clearCallingIdentity();
3680 int res = startActivityLocked(caller, intent, resolvedType,
3681 grantedUriPermissions, grantedMode, aInfo,
3682 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003683 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003684 Binder.restoreCallingIdentity(origId);
3685 return res;
3686 }
3687 }
3688
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003689 public int startActivityIntentSender(IApplicationThread caller,
3690 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003691 IBinder resultTo, String resultWho, int requestCode,
3692 int flagsMask, int flagsValues) {
3693 // Refuse possible leaked file descriptors
3694 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3695 throw new IllegalArgumentException("File descriptors passed in Intent");
3696 }
3697
3698 IIntentSender sender = intent.getTarget();
3699 if (!(sender instanceof PendingIntentRecord)) {
3700 throw new IllegalArgumentException("Bad PendingIntent object");
3701 }
3702
3703 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003704
3705 synchronized (this) {
3706 // If this is coming from the currently resumed activity, it is
3707 // effectively saying that app switches are allowed at this point.
3708 if (mResumedActivity != null
3709 && mResumedActivity.info.applicationInfo.uid ==
3710 Binder.getCallingUid()) {
3711 mAppSwitchesAllowedTime = 0;
3712 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003713 }
3714
3715 return pir.sendInner(0, fillInIntent, resolvedType,
3716 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3717 }
3718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003719 public boolean startNextMatchingActivity(IBinder callingActivity,
3720 Intent intent) {
3721 // Refuse possible leaked file descriptors
3722 if (intent != null && intent.hasFileDescriptors() == true) {
3723 throw new IllegalArgumentException("File descriptors passed in Intent");
3724 }
3725
3726 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003727 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003728 if (index < 0) {
3729 return false;
3730 }
3731 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3732 if (r.app == null || r.app.thread == null) {
3733 // The caller is not running... d'oh!
3734 return false;
3735 }
3736 intent = new Intent(intent);
3737 // The caller is not allowed to change the data.
3738 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3739 // And we are resetting to find the next component...
3740 intent.setComponent(null);
3741
3742 ActivityInfo aInfo = null;
3743 try {
3744 List<ResolveInfo> resolves =
3745 ActivityThread.getPackageManager().queryIntentActivities(
3746 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003747 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003748
3749 // Look for the original activity in the list...
3750 final int N = resolves != null ? resolves.size() : 0;
3751 for (int i=0; i<N; i++) {
3752 ResolveInfo rInfo = resolves.get(i);
3753 if (rInfo.activityInfo.packageName.equals(r.packageName)
3754 && rInfo.activityInfo.name.equals(r.info.name)) {
3755 // We found the current one... the next matching is
3756 // after it.
3757 i++;
3758 if (i<N) {
3759 aInfo = resolves.get(i).activityInfo;
3760 }
3761 break;
3762 }
3763 }
3764 } catch (RemoteException e) {
3765 }
3766
3767 if (aInfo == null) {
3768 // Nobody who is next!
3769 return false;
3770 }
3771
3772 intent.setComponent(new ComponentName(
3773 aInfo.applicationInfo.packageName, aInfo.name));
3774 intent.setFlags(intent.getFlags()&~(
3775 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3776 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3777 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3778 Intent.FLAG_ACTIVITY_NEW_TASK));
3779
3780 // Okay now we need to start the new activity, replacing the
3781 // currently running activity. This is a little tricky because
3782 // we want to start the new one as if the current one is finished,
3783 // but not finish the current one first so that there is no flicker.
3784 // And thus...
3785 final boolean wasFinishing = r.finishing;
3786 r.finishing = true;
3787
3788 // Propagate reply information over to the new activity.
3789 final HistoryRecord resultTo = r.resultTo;
3790 final String resultWho = r.resultWho;
3791 final int requestCode = r.requestCode;
3792 r.resultTo = null;
3793 if (resultTo != null) {
3794 resultTo.removeResultsLocked(r, resultWho, requestCode);
3795 }
3796
3797 final long origId = Binder.clearCallingIdentity();
3798 // XXX we are not dealing with propagating grantedUriPermissions...
3799 // those are not yet exposed to user code, so there is no need.
3800 int res = startActivityLocked(r.app.thread, intent,
3801 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003802 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 Binder.restoreCallingIdentity(origId);
3804
3805 r.finishing = wasFinishing;
3806 if (res != START_SUCCESS) {
3807 return false;
3808 }
3809 return true;
3810 }
3811 }
3812
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003813 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003814 Intent intent, String resolvedType, IBinder resultTo,
3815 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003816
3817 // This is so super not safe, that only the system (or okay root)
3818 // can do it.
3819 final int callingUid = Binder.getCallingUid();
3820 if (callingUid != 0 && callingUid != Process.myUid()) {
3821 throw new SecurityException(
3822 "startActivityInPackage only available to the system");
3823 }
3824
The Android Open Source Project4df24232009-03-05 14:34:35 -08003825 final boolean componentSpecified = intent.getComponent() != null;
3826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 // Don't modify the client's object!
3828 intent = new Intent(intent);
3829
3830 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003831 ActivityInfo aInfo;
3832 try {
3833 ResolveInfo rInfo =
3834 ActivityThread.getPackageManager().resolveIntent(
3835 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003836 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837 aInfo = rInfo != null ? rInfo.activityInfo : null;
3838 } catch (RemoteException e) {
3839 aInfo = null;
3840 }
3841
3842 if (aInfo != null) {
3843 // Store the found target back into the intent, because now that
3844 // we have it we never want to do this again. For example, if the
3845 // user navigates back to this point in the history, we should
3846 // always restart the exact same activity.
3847 intent.setComponent(new ComponentName(
3848 aInfo.applicationInfo.packageName, aInfo.name));
3849 }
3850
3851 synchronized(this) {
3852 return startActivityLocked(null, intent, resolvedType,
3853 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003854 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003855 }
3856 }
3857
Josh Bartel7f208742010-02-25 11:01:44 -06003858 private final void addRecentTaskLocked(TaskRecord task) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003859 // Remove any existing entries that are the same kind of task.
3860 int N = mRecentTasks.size();
3861 for (int i=0; i<N; i++) {
3862 TaskRecord tr = mRecentTasks.get(i);
3863 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3864 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3865 mRecentTasks.remove(i);
3866 i--;
3867 N--;
3868 if (task.intent == null) {
3869 // If the new recent task we are adding is not fully
3870 // specified, then replace it with the existing recent task.
3871 task = tr;
3872 }
3873 }
3874 }
3875 if (N >= MAX_RECENT_TASKS) {
3876 mRecentTasks.remove(N-1);
3877 }
3878 mRecentTasks.add(0, task);
3879 }
3880
3881 public void setRequestedOrientation(IBinder token,
3882 int requestedOrientation) {
3883 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003884 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885 if (index < 0) {
3886 return;
3887 }
3888 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3889 final long origId = Binder.clearCallingIdentity();
3890 mWindowManager.setAppOrientation(r, requestedOrientation);
3891 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003892 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003893 r.mayFreezeScreenLocked(r.app) ? r : null);
3894 if (config != null) {
3895 r.frozenBeforeDestroy = true;
3896 if (!updateConfigurationLocked(config, r)) {
3897 resumeTopActivityLocked(null);
3898 }
3899 }
3900 Binder.restoreCallingIdentity(origId);
3901 }
3902 }
3903
3904 public int getRequestedOrientation(IBinder token) {
3905 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003906 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003907 if (index < 0) {
3908 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3909 }
3910 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3911 return mWindowManager.getAppOrientation(r);
3912 }
3913 }
3914
3915 private final void stopActivityLocked(HistoryRecord r) {
3916 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3917 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3918 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3919 if (!r.finishing) {
3920 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3921 "no-history");
3922 }
3923 } else if (r.app != null && r.app.thread != null) {
3924 if (mFocusedActivity == r) {
3925 setFocusedActivityLocked(topRunningActivityLocked(null));
3926 }
3927 r.resumeKeyDispatchingLocked();
3928 try {
3929 r.stopped = false;
3930 r.state = ActivityState.STOPPING;
3931 if (DEBUG_VISBILITY) Log.v(
3932 TAG, "Stopping visible=" + r.visible + " for " + r);
3933 if (!r.visible) {
3934 mWindowManager.setAppVisibility(r, false);
3935 }
3936 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3937 } catch (Exception e) {
3938 // Maybe just ignore exceptions here... if the process
3939 // has crashed, our death notification will clean things
3940 // up.
3941 Log.w(TAG, "Exception thrown during pause", e);
3942 // Just in case, assume it to be stopped.
3943 r.stopped = true;
3944 r.state = ActivityState.STOPPED;
3945 if (r.configDestroy) {
3946 destroyActivityLocked(r, true);
3947 }
3948 }
3949 }
3950 }
3951
3952 /**
3953 * @return Returns true if the activity is being finished, false if for
3954 * some reason it is being left as-is.
3955 */
3956 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3957 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003958 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003959 TAG, "Finishing activity: token=" + token
3960 + ", result=" + resultCode + ", data=" + resultData);
3961
Dianne Hackborn75b03852009-06-12 15:43:26 -07003962 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003963 if (index < 0) {
3964 return false;
3965 }
3966 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3967
3968 // Is this the last activity left?
3969 boolean lastActivity = true;
3970 for (int i=mHistory.size()-1; i>=0; i--) {
3971 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3972 if (!p.finishing && p != r) {
3973 lastActivity = false;
3974 break;
3975 }
3976 }
3977
3978 // If this is the last activity, but it is the home activity, then
3979 // just don't finish it.
3980 if (lastActivity) {
3981 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3982 return false;
3983 }
3984 }
3985
3986 finishActivityLocked(r, index, resultCode, resultData, reason);
3987 return true;
3988 }
3989
3990 /**
3991 * @return Returns true if this activity has been removed from the history
3992 * list, or false if it is still in the list and will be removed later.
3993 */
3994 private final boolean finishActivityLocked(HistoryRecord r, int index,
3995 int resultCode, Intent resultData, String reason) {
3996 if (r.finishing) {
3997 Log.w(TAG, "Duplicate finish request for " + r);
3998 return false;
3999 }
4000
4001 r.finishing = true;
4002 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
4003 System.identityHashCode(r),
4004 r.task.taskId, r.shortComponentName, reason);
4005 r.task.numActivities--;
4006 if (r.frontOfTask && index < (mHistory.size()-1)) {
4007 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
4008 if (next.task == r.task) {
4009 next.frontOfTask = true;
4010 }
4011 }
4012
4013 r.pauseKeyDispatchingLocked();
4014 if (mFocusedActivity == r) {
4015 setFocusedActivityLocked(topRunningActivityLocked(null));
4016 }
4017
4018 // send the result
4019 HistoryRecord resultTo = r.resultTo;
4020 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07004021 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
4022 + " who=" + r.resultWho + " req=" + r.requestCode
4023 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004024 if (r.info.applicationInfo.uid > 0) {
4025 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
4026 r.packageName, resultData, r);
4027 }
4028 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
4029 resultData);
4030 r.resultTo = null;
4031 }
Chris Tate8a7dc172009-03-24 20:11:42 -07004032 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033
4034 // Make sure this HistoryRecord is not holding on to other resources,
4035 // because clients have remote IPC references to this object so we
4036 // can't assume that will go away and want to avoid circular IPC refs.
4037 r.results = null;
4038 r.pendingResults = null;
4039 r.newIntents = null;
4040 r.icicle = null;
4041
4042 if (mPendingThumbnails.size() > 0) {
4043 // There are clients waiting to receive thumbnails so, in case
4044 // this is an activity that someone is waiting for, add it
4045 // to the pending list so we can correctly update the clients.
4046 mCancelledThumbnails.add(r);
4047 }
4048
4049 if (mResumedActivity == r) {
4050 boolean endTask = index <= 0
4051 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4052 if (DEBUG_TRANSITION) Log.v(TAG,
4053 "Prepare close transition: finishing " + r);
4054 mWindowManager.prepareAppTransition(endTask
4055 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4056 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4057
4058 // Tell window manager to prepare for this one to be removed.
4059 mWindowManager.setAppVisibility(r, false);
4060
4061 if (mPausingActivity == null) {
4062 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4063 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4064 startPausingLocked(false, false);
4065 }
4066
4067 } else if (r.state != ActivityState.PAUSING) {
4068 // If the activity is PAUSING, we will complete the finish once
4069 // it is done pausing; else we can just directly finish it here.
4070 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4071 return finishCurrentActivityLocked(r, index,
4072 FINISH_AFTER_PAUSE) == null;
4073 } else {
4074 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4075 }
4076
4077 return false;
4078 }
4079
4080 private static final int FINISH_IMMEDIATELY = 0;
4081 private static final int FINISH_AFTER_PAUSE = 1;
4082 private static final int FINISH_AFTER_VISIBLE = 2;
4083
4084 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4085 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004086 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004087 if (index < 0) {
4088 return null;
4089 }
4090
4091 return finishCurrentActivityLocked(r, index, mode);
4092 }
4093
4094 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4095 int index, int mode) {
4096 // First things first: if this activity is currently visible,
4097 // and the resumed activity is not yet visible, then hold off on
4098 // finishing until the resumed one becomes visible.
4099 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4100 if (!mStoppingActivities.contains(r)) {
4101 mStoppingActivities.add(r);
4102 if (mStoppingActivities.size() > 3) {
4103 // If we already have a few activities waiting to stop,
4104 // then give up on things going idle and start clearing
4105 // them out.
4106 Message msg = Message.obtain();
4107 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4108 mHandler.sendMessage(msg);
4109 }
4110 }
4111 r.state = ActivityState.STOPPING;
4112 updateOomAdjLocked();
4113 return r;
4114 }
4115
4116 // make sure the record is cleaned out of other places.
4117 mStoppingActivities.remove(r);
4118 mWaitingVisibleActivities.remove(r);
4119 if (mResumedActivity == r) {
4120 mResumedActivity = null;
4121 }
4122 final ActivityState prevState = r.state;
4123 r.state = ActivityState.FINISHING;
4124
4125 if (mode == FINISH_IMMEDIATELY
4126 || prevState == ActivityState.STOPPED
4127 || prevState == ActivityState.INITIALIZING) {
4128 // If this activity is already stopped, we can just finish
4129 // it right now.
4130 return destroyActivityLocked(r, true) ? null : r;
4131 } else {
4132 // Need to go through the full pause cycle to get this
4133 // activity into the stopped state and then finish it.
4134 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4135 mFinishingActivities.add(r);
4136 resumeTopActivityLocked(null);
4137 }
4138 return r;
4139 }
4140
4141 /**
4142 * This is the internal entry point for handling Activity.finish().
4143 *
4144 * @param token The Binder token referencing the Activity we want to finish.
4145 * @param resultCode Result code, if any, from this Activity.
4146 * @param resultData Result data (Intent), if any, from this Activity.
4147 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004148 * @return Returns true if the activity successfully finished, or false if it is still running.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004149 */
4150 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4151 // Refuse possible leaked file descriptors
4152 if (resultData != null && resultData.hasFileDescriptors() == true) {
4153 throw new IllegalArgumentException("File descriptors passed in Intent");
4154 }
4155
4156 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004157 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004158 // Find the first activity that is not finishing.
4159 HistoryRecord next = topRunningActivityLocked(token, 0);
4160 if (next != null) {
4161 // ask watcher if this is allowed
4162 boolean resumeOK = true;
4163 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004164 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004165 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004166 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004167 }
4168
4169 if (!resumeOK) {
4170 return false;
4171 }
4172 }
4173 }
4174 final long origId = Binder.clearCallingIdentity();
4175 boolean res = requestFinishActivityLocked(token, resultCode,
4176 resultData, "app-request");
4177 Binder.restoreCallingIdentity(origId);
4178 return res;
4179 }
4180 }
4181
4182 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4183 String resultWho, int requestCode, int resultCode, Intent data) {
4184
4185 if (callingUid > 0) {
4186 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4187 data, r);
4188 }
4189
The Android Open Source Project10592532009-03-18 17:39:46 -07004190 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4191 + " : who=" + resultWho + " req=" + requestCode
4192 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004193 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4194 try {
4195 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4196 list.add(new ResultInfo(resultWho, requestCode,
4197 resultCode, data));
4198 r.app.thread.scheduleSendResult(r, list);
4199 return;
4200 } catch (Exception e) {
4201 Log.w(TAG, "Exception thrown sending result to " + r, e);
4202 }
4203 }
4204
4205 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4206 }
4207
4208 public final void finishSubActivity(IBinder token, String resultWho,
4209 int requestCode) {
4210 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004211 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004212 if (index < 0) {
4213 return;
4214 }
4215 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4216
4217 final long origId = Binder.clearCallingIdentity();
4218
4219 int i;
4220 for (i=mHistory.size()-1; i>=0; i--) {
4221 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4222 if (r.resultTo == self && r.requestCode == requestCode) {
4223 if ((r.resultWho == null && resultWho == null) ||
4224 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4225 finishActivityLocked(r, i,
4226 Activity.RESULT_CANCELED, null, "request-sub");
4227 }
4228 }
4229 }
4230
4231 Binder.restoreCallingIdentity(origId);
4232 }
4233 }
4234
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004235 public void overridePendingTransition(IBinder token, String packageName,
4236 int enterAnim, int exitAnim) {
4237 synchronized(this) {
4238 int index = indexOfTokenLocked(token);
4239 if (index < 0) {
4240 return;
4241 }
4242 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4243
4244 final long origId = Binder.clearCallingIdentity();
4245
4246 if (self.state == ActivityState.RESUMED
4247 || self.state == ActivityState.PAUSING) {
4248 mWindowManager.overridePendingAppTransition(packageName,
4249 enterAnim, exitAnim);
4250 }
4251
4252 Binder.restoreCallingIdentity(origId);
4253 }
4254 }
4255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004256 /**
4257 * Perform clean-up of service connections in an activity record.
4258 */
4259 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4260 // Throw away any services that have been bound by this activity.
4261 if (r.connections != null) {
4262 Iterator<ConnectionRecord> it = r.connections.iterator();
4263 while (it.hasNext()) {
4264 ConnectionRecord c = it.next();
4265 removeConnectionLocked(c, null, r);
4266 }
4267 r.connections = null;
4268 }
4269 }
4270
4271 /**
4272 * Perform the common clean-up of an activity record. This is called both
4273 * as part of destroyActivityLocked() (when destroying the client-side
4274 * representation) and cleaning things up as a result of its hosting
4275 * processing going away, in which case there is no remaining client-side
4276 * state to destroy so only the cleanup here is needed.
4277 */
4278 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4279 if (mResumedActivity == r) {
4280 mResumedActivity = null;
4281 }
4282 if (mFocusedActivity == r) {
4283 mFocusedActivity = null;
4284 }
4285
4286 r.configDestroy = false;
4287 r.frozenBeforeDestroy = false;
4288
4289 // Make sure this record is no longer in the pending finishes list.
4290 // This could happen, for example, if we are trimming activities
4291 // down to the max limit while they are still waiting to finish.
4292 mFinishingActivities.remove(r);
4293 mWaitingVisibleActivities.remove(r);
4294
4295 // Remove any pending results.
4296 if (r.finishing && r.pendingResults != null) {
4297 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4298 PendingIntentRecord rec = apr.get();
4299 if (rec != null) {
4300 cancelIntentSenderLocked(rec, false);
4301 }
4302 }
4303 r.pendingResults = null;
4304 }
4305
4306 if (cleanServices) {
4307 cleanUpActivityServicesLocked(r);
4308 }
4309
4310 if (mPendingThumbnails.size() > 0) {
4311 // There are clients waiting to receive thumbnails so, in case
4312 // this is an activity that someone is waiting for, add it
4313 // to the pending list so we can correctly update the clients.
4314 mCancelledThumbnails.add(r);
4315 }
4316
4317 // Get rid of any pending idle timeouts.
4318 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4319 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4320 }
4321
4322 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4323 if (r.state != ActivityState.DESTROYED) {
4324 mHistory.remove(r);
4325 r.inHistory = false;
4326 r.state = ActivityState.DESTROYED;
4327 mWindowManager.removeAppToken(r);
4328 if (VALIDATE_TOKENS) {
4329 mWindowManager.validateAppTokens(mHistory);
4330 }
4331 cleanUpActivityServicesLocked(r);
4332 removeActivityUriPermissionsLocked(r);
4333 }
4334 }
4335
4336 /**
4337 * Destroy the current CLIENT SIDE instance of an activity. This may be
4338 * called both when actually finishing an activity, or when performing
4339 * a configuration switch where we destroy the current client-side object
4340 * but then create a new client-side object for this same HistoryRecord.
4341 */
4342 private final boolean destroyActivityLocked(HistoryRecord r,
4343 boolean removeFromApp) {
4344 if (DEBUG_SWITCH) Log.v(
4345 TAG, "Removing activity: token=" + r
4346 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4347 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4348 System.identityHashCode(r),
4349 r.task.taskId, r.shortComponentName);
4350
4351 boolean removedFromHistory = false;
4352
4353 cleanUpActivityLocked(r, false);
4354
4355 if (r.app != null) {
4356 if (removeFromApp) {
4357 int idx = r.app.activities.indexOf(r);
4358 if (idx >= 0) {
4359 r.app.activities.remove(idx);
4360 }
4361 if (r.persistent) {
4362 decPersistentCountLocked(r.app);
4363 }
4364 }
4365
4366 boolean skipDestroy = false;
4367
4368 try {
4369 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4370 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4371 r.configChangeFlags);
4372 } catch (Exception e) {
4373 // We can just ignore exceptions here... if the process
4374 // has crashed, our death notification will clean things
4375 // up.
4376 //Log.w(TAG, "Exception thrown during finish", e);
4377 if (r.finishing) {
4378 removeActivityFromHistoryLocked(r);
4379 removedFromHistory = true;
4380 skipDestroy = true;
4381 }
4382 }
4383
4384 r.app = null;
4385 r.nowVisible = false;
4386
4387 if (r.finishing && !skipDestroy) {
4388 r.state = ActivityState.DESTROYING;
4389 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4390 msg.obj = r;
4391 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4392 } else {
4393 r.state = ActivityState.DESTROYED;
4394 }
4395 } else {
4396 // remove this record from the history.
4397 if (r.finishing) {
4398 removeActivityFromHistoryLocked(r);
4399 removedFromHistory = true;
4400 } else {
4401 r.state = ActivityState.DESTROYED;
4402 }
4403 }
4404
4405 r.configChangeFlags = 0;
4406
4407 if (!mLRUActivities.remove(r)) {
4408 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4409 }
4410
4411 return removedFromHistory;
4412 }
4413
4414 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4415 ProcessRecord app)
4416 {
4417 int i = list.size();
4418 if (localLOGV) Log.v(
4419 TAG, "Removing app " + app + " from list " + list
4420 + " with " + i + " entries");
4421 while (i > 0) {
4422 i--;
4423 HistoryRecord r = (HistoryRecord)list.get(i);
4424 if (localLOGV) Log.v(
4425 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4426 if (r.app == app) {
4427 if (localLOGV) Log.v(TAG, "Removing this entry!");
4428 list.remove(i);
4429 }
4430 }
4431 }
4432
4433 /**
4434 * Main function for removing an existing process from the activity manager
4435 * as a result of that process going away. Clears out all connections
4436 * to the process.
4437 */
4438 private final void handleAppDiedLocked(ProcessRecord app,
4439 boolean restarting) {
4440 cleanUpApplicationRecordLocked(app, restarting, -1);
4441 if (!restarting) {
4442 mLRUProcesses.remove(app);
4443 }
4444
4445 // Just in case...
4446 if (mPausingActivity != null && mPausingActivity.app == app) {
4447 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4448 mPausingActivity = null;
4449 }
4450 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4451 mLastPausedActivity = null;
4452 }
4453
4454 // Remove this application's activities from active lists.
4455 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4456 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4457 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4458 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4459
4460 boolean atTop = true;
4461 boolean hasVisibleActivities = false;
4462
4463 // Clean out the history list.
4464 int i = mHistory.size();
4465 if (localLOGV) Log.v(
4466 TAG, "Removing app " + app + " from history with " + i + " entries");
4467 while (i > 0) {
4468 i--;
4469 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4470 if (localLOGV) Log.v(
4471 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4472 if (r.app == app) {
4473 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4474 if (localLOGV) Log.v(
4475 TAG, "Removing this entry! frozen=" + r.haveState
4476 + " finishing=" + r.finishing);
4477 mHistory.remove(i);
4478
4479 r.inHistory = false;
4480 mWindowManager.removeAppToken(r);
4481 if (VALIDATE_TOKENS) {
4482 mWindowManager.validateAppTokens(mHistory);
4483 }
4484 removeActivityUriPermissionsLocked(r);
4485
4486 } else {
4487 // We have the current state for this activity, so
4488 // it can be restarted later when needed.
4489 if (localLOGV) Log.v(
4490 TAG, "Keeping entry, setting app to null");
4491 if (r.visible) {
4492 hasVisibleActivities = true;
4493 }
4494 r.app = null;
4495 r.nowVisible = false;
4496 if (!r.haveState) {
4497 r.icicle = null;
4498 }
4499 }
4500
4501 cleanUpActivityLocked(r, true);
4502 r.state = ActivityState.STOPPED;
4503 }
4504 atTop = false;
4505 }
4506
4507 app.activities.clear();
4508
4509 if (app.instrumentationClass != null) {
4510 Log.w(TAG, "Crash of app " + app.processName
4511 + " running instrumentation " + app.instrumentationClass);
4512 Bundle info = new Bundle();
4513 info.putString("shortMsg", "Process crashed.");
4514 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4515 }
4516
4517 if (!restarting) {
4518 if (!resumeTopActivityLocked(null)) {
4519 // If there was nothing to resume, and we are not already
4520 // restarting this process, but there is a visible activity that
4521 // is hosted by the process... then make sure all visible
4522 // activities are running, taking care of restarting this
4523 // process.
4524 if (hasVisibleActivities) {
4525 ensureActivitiesVisibleLocked(null, 0);
4526 }
4527 }
4528 }
4529 }
4530
4531 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4532 IBinder threadBinder = thread.asBinder();
4533
4534 // Find the application record.
4535 int count = mLRUProcesses.size();
4536 int i;
4537 for (i=0; i<count; i++) {
4538 ProcessRecord rec = mLRUProcesses.get(i);
4539 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4540 return i;
4541 }
4542 }
4543 return -1;
4544 }
4545
4546 private final ProcessRecord getRecordForAppLocked(
4547 IApplicationThread thread) {
4548 if (thread == null) {
4549 return null;
4550 }
4551
4552 int appIndex = getLRURecordIndexForAppLocked(thread);
4553 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4554 }
4555
4556 private final void appDiedLocked(ProcessRecord app, int pid,
4557 IApplicationThread thread) {
4558
4559 mProcDeaths[0]++;
4560
Magnus Edlund7bb25812010-02-24 15:45:06 +01004561 // Clean up already done if the process has been re-started.
4562 if (app.pid == pid && app.thread != null &&
4563 app.thread.asBinder() == thread.asBinder()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004564 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4565 + ") has died.");
4566 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4567 if (localLOGV) Log.v(
4568 TAG, "Dying app: " + app + ", pid: " + pid
4569 + ", thread: " + thread.asBinder());
4570 boolean doLowMem = app.instrumentationClass == null;
4571 handleAppDiedLocked(app, false);
4572
4573 if (doLowMem) {
4574 // If there are no longer any background processes running,
4575 // and the app that died was not running instrumentation,
4576 // then tell everyone we are now low on memory.
4577 boolean haveBg = false;
4578 int count = mLRUProcesses.size();
4579 int i;
4580 for (i=0; i<count; i++) {
4581 ProcessRecord rec = mLRUProcesses.get(i);
4582 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4583 haveBg = true;
4584 break;
4585 }
4586 }
4587
4588 if (!haveBg) {
4589 Log.i(TAG, "Low Memory: No more background processes.");
4590 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004591 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004592 for (i=0; i<count; i++) {
4593 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004594 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004595 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4596 // The low memory report is overriding any current
4597 // state for a GC request. Make sure to do
4598 // visible/foreground processes first.
4599 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4600 rec.lastRequestedGc = 0;
4601 } else {
4602 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004603 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004604 rec.reportLowMemory = true;
4605 rec.lastLowMemory = now;
4606 mProcessesToGc.remove(rec);
4607 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 }
4609 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004610 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004611 }
4612 }
Magnus Edlund7bb25812010-02-24 15:45:06 +01004613 } else if (app.pid != pid) {
4614 // A new process has already been started.
4615 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4616 + ") has died and restarted (pid " + app.pid + ").");
4617 EventLog.writeEvent(LOG_AM_PROCESS_DIED, pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004618 } else if (Config.LOGD) {
4619 Log.d(TAG, "Received spurious death notification for thread "
4620 + thread.asBinder());
4621 }
4622 }
4623
4624 final String readFile(String filename) {
4625 try {
4626 FileInputStream fs = new FileInputStream(filename);
4627 byte[] inp = new byte[8192];
4628 int size = fs.read(inp);
4629 fs.close();
4630 return new String(inp, 0, 0, size);
4631 } catch (java.io.IOException e) {
4632 }
4633 return "";
4634 }
4635
4636 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004637 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004638 if (app.notResponding || app.crashing) {
4639 return;
4640 }
4641
4642 // Log the ANR to the event log.
4643 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4644
4645 // If we are on a secure build and the application is not interesting to the user (it is
4646 // not visible or in the background), just kill it instead of displaying a dialog.
4647 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4648 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4649 Process.killProcess(app.pid);
4650 return;
4651 }
4652
4653 // DeviceMonitor.start();
4654
4655 String processInfo = null;
4656 if (MONITOR_CPU_USAGE) {
4657 updateCpuStatsNow();
4658 synchronized (mProcessStatsThread) {
4659 processInfo = mProcessStats.printCurrentState();
4660 }
4661 }
4662
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004663 StringBuilder info = mStringBuilder;
4664 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004665 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004666 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004667 if (reportedActivity != null && reportedActivity.app != null) {
4668 info.append(" (last in ");
4669 info.append(reportedActivity.app.processName);
4670 info.append(")");
4671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004672 if (annotation != null) {
4673 info.append("\nAnnotation: ");
4674 info.append(annotation);
4675 }
4676 if (MONITOR_CPU_USAGE) {
4677 info.append("\nCPU usage:\n");
4678 info.append(processInfo);
4679 }
4680 Log.i(TAG, info.toString());
4681
4682 // The application is not responding. Dump as many thread traces as we can.
4683 boolean fileDump = prepareTraceFile(true);
4684 if (!fileDump) {
4685 // Dumping traces to the log, just dump the process that isn't responding so
4686 // we don't overflow the log
4687 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4688 } else {
4689 // Dumping traces to a file so dump all active processes we know about
4690 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004691 // First, these are the most important processes.
4692 final int[] imppids = new int[3];
4693 int i=0;
4694 imppids[0] = app.pid;
4695 i++;
4696 if (reportedActivity != null && reportedActivity.app != null
4697 && reportedActivity.app.thread != null
4698 && reportedActivity.app.pid != app.pid) {
4699 imppids[i] = reportedActivity.app.pid;
4700 i++;
4701 }
4702 imppids[i] = Process.myPid();
4703 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4704 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4705 synchronized (this) {
4706 try {
4707 wait(200);
4708 } catch (InterruptedException e) {
4709 }
4710 }
4711 }
4712 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004713 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004714 boolean done = false;
4715 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4716 if (imppids[j] == r.pid) {
4717 done = true;
4718 break;
4719 }
4720 }
4721 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004722 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004723 synchronized (this) {
4724 try {
4725 wait(200);
4726 } catch (InterruptedException e) {
4727 }
4728 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004729 }
4730 }
4731 }
4732 }
4733
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004734 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004735 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004736 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004737 app.pid, info.toString());
4738 if (res != 0) {
4739 if (res < 0) {
4740 // wait until the SIGQUIT has had a chance to process before killing the
4741 // process.
4742 try {
4743 wait(2000);
4744 } catch (InterruptedException e) {
4745 }
4746
4747 Process.killProcess(app.pid);
4748 return;
4749 }
4750 }
4751 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004752 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004753 }
4754 }
4755
4756 makeAppNotRespondingLocked(app,
4757 activity != null ? activity.shortComponentName : null,
4758 annotation != null ? "ANR " + annotation : "ANR",
4759 info.toString(), null);
4760 Message msg = Message.obtain();
4761 HashMap map = new HashMap();
4762 msg.what = SHOW_NOT_RESPONDING_MSG;
4763 msg.obj = map;
4764 map.put("app", app);
4765 if (activity != null) {
4766 map.put("activity", activity);
4767 }
4768
4769 mHandler.sendMessage(msg);
4770 return;
4771 }
4772
4773 /**
4774 * If a stack trace file has been configured, prepare the filesystem
4775 * by creating the directory if it doesn't exist and optionally
4776 * removing the old trace file.
4777 *
4778 * @param removeExisting If set, the existing trace file will be removed.
4779 * @return Returns true if the trace file preparations succeeded
4780 */
4781 public static boolean prepareTraceFile(boolean removeExisting) {
4782 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4783 boolean fileReady = false;
4784 if (!TextUtils.isEmpty(tracesPath)) {
4785 File f = new File(tracesPath);
4786 if (!f.exists()) {
4787 // Ensure the enclosing directory exists
4788 File dir = f.getParentFile();
4789 if (!dir.exists()) {
4790 fileReady = dir.mkdirs();
4791 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004792 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004793 } else if (dir.isDirectory()) {
4794 fileReady = true;
4795 }
4796 } else if (removeExisting) {
4797 // Remove the previous traces file, so we don't fill the disk.
4798 // The VM will recreate it
4799 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4800 fileReady = f.delete();
4801 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004802
4803 if (removeExisting) {
4804 try {
4805 f.createNewFile();
4806 FileUtils.setPermissions(f.getAbsolutePath(),
4807 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4808 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4809 fileReady = true;
4810 } catch (IOException e) {
4811 Log.w(TAG, "Unable to make ANR traces file", e);
4812 }
4813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004814 }
4815
4816 return fileReady;
4817 }
4818
4819
4820 private final void decPersistentCountLocked(ProcessRecord app)
4821 {
4822 app.persistentActivities--;
4823 if (app.persistentActivities > 0) {
4824 // Still more of 'em...
4825 return;
4826 }
4827 if (app.persistent) {
4828 // Ah, but the application itself is persistent. Whatever!
4829 return;
4830 }
4831
4832 // App is no longer persistent... make sure it and the ones
4833 // following it in the LRU list have the correc oom_adj.
4834 updateOomAdjLocked();
4835 }
4836
4837 public void setPersistent(IBinder token, boolean isPersistent) {
4838 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4839 != PackageManager.PERMISSION_GRANTED) {
4840 String msg = "Permission Denial: setPersistent() from pid="
4841 + Binder.getCallingPid()
4842 + ", uid=" + Binder.getCallingUid()
4843 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4844 Log.w(TAG, msg);
4845 throw new SecurityException(msg);
4846 }
4847
4848 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004849 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004850 if (index < 0) {
4851 return;
4852 }
4853 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4854 ProcessRecord app = r.app;
4855
4856 if (localLOGV) Log.v(
4857 TAG, "Setting persistence " + isPersistent + ": " + r);
4858
4859 if (isPersistent) {
4860 if (r.persistent) {
4861 // Okay okay, I heard you already!
4862 if (localLOGV) Log.v(TAG, "Already persistent!");
4863 return;
4864 }
4865 r.persistent = true;
4866 app.persistentActivities++;
4867 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4868 if (app.persistentActivities > 1) {
4869 // We aren't the first...
4870 if (localLOGV) Log.v(TAG, "Not the first!");
4871 return;
4872 }
4873 if (app.persistent) {
4874 // This would be redundant.
4875 if (localLOGV) Log.v(TAG, "App is persistent!");
4876 return;
4877 }
4878
4879 // App is now persistent... make sure it and the ones
4880 // following it now have the correct oom_adj.
4881 final long origId = Binder.clearCallingIdentity();
4882 updateOomAdjLocked();
4883 Binder.restoreCallingIdentity(origId);
4884
4885 } else {
4886 if (!r.persistent) {
4887 // Okay okay, I heard you already!
4888 return;
4889 }
4890 r.persistent = false;
4891 final long origId = Binder.clearCallingIdentity();
4892 decPersistentCountLocked(app);
4893 Binder.restoreCallingIdentity(origId);
4894
4895 }
4896 }
4897 }
4898
4899 public boolean clearApplicationUserData(final String packageName,
4900 final IPackageDataObserver observer) {
4901 int uid = Binder.getCallingUid();
4902 int pid = Binder.getCallingPid();
4903 long callingId = Binder.clearCallingIdentity();
4904 try {
4905 IPackageManager pm = ActivityThread.getPackageManager();
4906 int pkgUid = -1;
4907 synchronized(this) {
4908 try {
4909 pkgUid = pm.getPackageUid(packageName);
4910 } catch (RemoteException e) {
4911 }
4912 if (pkgUid == -1) {
4913 Log.w(TAG, "Invalid packageName:" + packageName);
4914 return false;
4915 }
4916 if (uid == pkgUid || checkComponentPermission(
4917 android.Manifest.permission.CLEAR_APP_USER_DATA,
4918 pid, uid, -1)
4919 == PackageManager.PERMISSION_GRANTED) {
4920 restartPackageLocked(packageName, pkgUid);
4921 } else {
4922 throw new SecurityException(pid+" does not have permission:"+
4923 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4924 "for process:"+packageName);
4925 }
4926 }
4927
4928 try {
4929 //clear application user data
4930 pm.clearApplicationUserData(packageName, observer);
4931 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4932 Uri.fromParts("package", packageName, null));
4933 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4934 broadcastIntentLocked(null, null, intent,
4935 null, null, 0, null, null, null,
4936 false, false, MY_PID, Process.SYSTEM_UID);
4937 } catch (RemoteException e) {
4938 }
4939 } finally {
4940 Binder.restoreCallingIdentity(callingId);
4941 }
4942 return true;
4943 }
4944
4945 public void restartPackage(final String packageName) {
4946 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4947 != PackageManager.PERMISSION_GRANTED) {
4948 String msg = "Permission Denial: restartPackage() from pid="
4949 + Binder.getCallingPid()
4950 + ", uid=" + Binder.getCallingUid()
4951 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4952 Log.w(TAG, msg);
4953 throw new SecurityException(msg);
4954 }
4955
4956 long callingId = Binder.clearCallingIdentity();
4957 try {
4958 IPackageManager pm = ActivityThread.getPackageManager();
4959 int pkgUid = -1;
4960 synchronized(this) {
4961 try {
4962 pkgUid = pm.getPackageUid(packageName);
4963 } catch (RemoteException e) {
4964 }
4965 if (pkgUid == -1) {
4966 Log.w(TAG, "Invalid packageName: " + packageName);
4967 return;
4968 }
4969 restartPackageLocked(packageName, pkgUid);
4970 }
4971 } finally {
4972 Binder.restoreCallingIdentity(callingId);
4973 }
4974 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004975
4976 /*
4977 * The pkg name and uid have to be specified.
4978 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4979 */
4980 public void killApplicationWithUid(String pkg, int uid) {
4981 if (pkg == null) {
4982 return;
4983 }
4984 // Make sure the uid is valid.
4985 if (uid < 0) {
4986 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4987 return;
4988 }
4989 int callerUid = Binder.getCallingUid();
4990 // Only the system server can kill an application
4991 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004992 // Post an aysnc message to kill the application
4993 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4994 msg.arg1 = uid;
4995 msg.arg2 = 0;
4996 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004997 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004998 } else {
4999 throw new SecurityException(callerUid + " cannot kill pkg: " +
5000 pkg);
5001 }
5002 }
5003
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005004 public void closeSystemDialogs(String reason) {
5005 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
5006 if (reason != null) {
5007 intent.putExtra("reason", reason);
5008 }
5009
5010 final int uid = Binder.getCallingUid();
5011 final long origId = Binder.clearCallingIdentity();
5012 synchronized (this) {
5013 int i = mWatchers.beginBroadcast();
5014 while (i > 0) {
5015 i--;
5016 IActivityWatcher w = mWatchers.getBroadcastItem(i);
5017 if (w != null) {
5018 try {
5019 w.closingSystemDialogs(reason);
5020 } catch (RemoteException e) {
5021 }
5022 }
5023 }
5024 mWatchers.finishBroadcast();
5025
Dianne Hackbornffa42482009-09-23 22:20:11 -07005026 mWindowManager.closeSystemDialogs(reason);
5027
5028 for (i=mHistory.size()-1; i>=0; i--) {
5029 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5030 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
5031 finishActivityLocked(r, i,
5032 Activity.RESULT_CANCELED, null, "close-sys");
5033 }
5034 }
5035
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005036 broadcastIntentLocked(null, null, intent, null,
5037 null, 0, null, null, null, false, false, -1, uid);
5038 }
5039 Binder.restoreCallingIdentity(origId);
5040 }
5041
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005042 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005043 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005044 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5045 for (int i=pids.length-1; i>=0; i--) {
5046 infos[i] = new Debug.MemoryInfo();
5047 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005048 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005049 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005050 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005051
5052 public void killApplicationProcess(String processName, int uid) {
5053 if (processName == null) {
5054 return;
5055 }
5056
5057 int callerUid = Binder.getCallingUid();
5058 // Only the system server can kill an application
5059 if (callerUid == Process.SYSTEM_UID) {
5060 synchronized (this) {
5061 ProcessRecord app = getProcessRecordLocked(processName, uid);
5062 if (app != null) {
5063 try {
5064 app.thread.scheduleSuicide();
5065 } catch (RemoteException e) {
5066 // If the other end already died, then our work here is done.
5067 }
5068 } else {
5069 Log.w(TAG, "Process/uid not found attempting kill of "
5070 + processName + " / " + uid);
5071 }
5072 }
5073 } else {
5074 throw new SecurityException(callerUid + " cannot kill app process: " +
5075 processName);
5076 }
5077 }
5078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005079 private void restartPackageLocked(final String packageName, int uid) {
5080 uninstallPackageLocked(packageName, uid, false);
5081 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5082 Uri.fromParts("package", packageName, null));
5083 intent.putExtra(Intent.EXTRA_UID, uid);
5084 broadcastIntentLocked(null, null, intent,
5085 null, null, 0, null, null, null,
5086 false, false, MY_PID, Process.SYSTEM_UID);
5087 }
5088
5089 private final void uninstallPackageLocked(String name, int uid,
5090 boolean callerWillRestart) {
5091 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5092
5093 int i, N;
5094
5095 final String procNamePrefix = name + ":";
5096 if (uid < 0) {
5097 try {
5098 uid = ActivityThread.getPackageManager().getPackageUid(name);
5099 } catch (RemoteException e) {
5100 }
5101 }
5102
5103 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5104 while (badApps.hasNext()) {
5105 SparseArray<Long> ba = badApps.next();
5106 if (ba.get(uid) != null) {
5107 badApps.remove();
5108 }
5109 }
5110
5111 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5112
5113 // Remove all processes this package may have touched: all with the
5114 // same UID (except for the system or root user), and all whose name
5115 // matches the package name.
5116 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5117 final int NA = apps.size();
5118 for (int ia=0; ia<NA; ia++) {
5119 ProcessRecord app = apps.valueAt(ia);
5120 if (app.removed) {
5121 procs.add(app);
5122 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5123 || app.processName.equals(name)
5124 || app.processName.startsWith(procNamePrefix)) {
5125 app.removed = true;
5126 procs.add(app);
5127 }
5128 }
5129 }
5130
5131 N = procs.size();
5132 for (i=0; i<N; i++) {
5133 removeProcessLocked(procs.get(i), callerWillRestart);
5134 }
5135
5136 for (i=mHistory.size()-1; i>=0; i--) {
5137 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5138 if (r.packageName.equals(name)) {
5139 if (Config.LOGD) Log.d(
5140 TAG, " Force finishing activity "
5141 + r.intent.getComponent().flattenToShortString());
5142 if (r.app != null) {
5143 r.app.removed = true;
5144 }
5145 r.app = null;
5146 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5147 }
5148 }
5149
5150 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5151 for (ServiceRecord service : mServices.values()) {
5152 if (service.packageName.equals(name)) {
5153 if (service.app != null) {
5154 service.app.removed = true;
5155 }
5156 service.app = null;
5157 services.add(service);
5158 }
5159 }
5160
5161 N = services.size();
5162 for (i=0; i<N; i++) {
5163 bringDownServiceLocked(services.get(i), true);
5164 }
5165
5166 resumeTopActivityLocked(null);
5167 }
5168
5169 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5170 final String name = app.processName;
5171 final int uid = app.info.uid;
5172 if (Config.LOGD) Log.d(
5173 TAG, "Force removing process " + app + " (" + name
5174 + "/" + uid + ")");
5175
5176 mProcessNames.remove(name, uid);
5177 boolean needRestart = false;
5178 if (app.pid > 0 && app.pid != MY_PID) {
5179 int pid = app.pid;
5180 synchronized (mPidsSelfLocked) {
5181 mPidsSelfLocked.remove(pid);
5182 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5183 }
5184 handleAppDiedLocked(app, true);
5185 mLRUProcesses.remove(app);
5186 Process.killProcess(pid);
5187
5188 if (app.persistent) {
5189 if (!callerWillRestart) {
5190 addAppLocked(app.info);
5191 } else {
5192 needRestart = true;
5193 }
5194 }
5195 } else {
5196 mRemovedProcesses.add(app);
5197 }
5198
5199 return needRestart;
5200 }
5201
5202 private final void processStartTimedOutLocked(ProcessRecord app) {
5203 final int pid = app.pid;
5204 boolean gone = false;
5205 synchronized (mPidsSelfLocked) {
5206 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5207 if (knownApp != null && knownApp.thread == null) {
5208 mPidsSelfLocked.remove(pid);
5209 gone = true;
5210 }
5211 }
5212
5213 if (gone) {
5214 Log.w(TAG, "Process " + app + " failed to attach");
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005215 EventLog.writeEvent(LOG_AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
5216 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005217 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005218 // Take care of any launching providers waiting for this process.
5219 checkAppInLaunchingProvidersLocked(app, true);
5220 // Take care of any services that are waiting for the process.
5221 for (int i=0; i<mPendingServices.size(); i++) {
5222 ServiceRecord sr = mPendingServices.get(i);
5223 if (app.info.uid == sr.appInfo.uid
5224 && app.processName.equals(sr.processName)) {
5225 Log.w(TAG, "Forcing bringing down service: " + sr);
5226 mPendingServices.remove(i);
5227 i--;
5228 bringDownServiceLocked(sr, true);
5229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005230 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005231 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005232 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5233 Log.w(TAG, "Unattached app died before backup, skipping");
5234 try {
5235 IBackupManager bm = IBackupManager.Stub.asInterface(
5236 ServiceManager.getService(Context.BACKUP_SERVICE));
5237 bm.agentDisconnected(app.info.packageName);
5238 } catch (RemoteException e) {
5239 // Can't happen; the backup manager is local
5240 }
5241 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005242 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5243 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5244 mPendingBroadcast = null;
5245 scheduleBroadcastsLocked();
5246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005247 } else {
5248 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5249 }
5250 }
5251
5252 private final boolean attachApplicationLocked(IApplicationThread thread,
5253 int pid) {
5254
5255 // Find the application record that is being attached... either via
5256 // the pid if we are running in multiple processes, or just pull the
5257 // next app record if we are emulating process with anonymous threads.
5258 ProcessRecord app;
5259 if (pid != MY_PID && pid >= 0) {
5260 synchronized (mPidsSelfLocked) {
5261 app = mPidsSelfLocked.get(pid);
5262 }
5263 } else if (mStartingProcesses.size() > 0) {
5264 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005265 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005266 } else {
5267 app = null;
5268 }
5269
5270 if (app == null) {
5271 Log.w(TAG, "No pending application record for pid " + pid
5272 + " (IApplicationThread " + thread + "); dropping process");
5273 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5274 if (pid > 0 && pid != MY_PID) {
5275 Process.killProcess(pid);
5276 } else {
5277 try {
5278 thread.scheduleExit();
5279 } catch (Exception e) {
5280 // Ignore exceptions.
5281 }
5282 }
5283 return false;
5284 }
5285
5286 // If this application record is still attached to a previous
5287 // process, clean it up now.
5288 if (app.thread != null) {
5289 handleAppDiedLocked(app, true);
5290 }
5291
5292 // Tell the process all about itself.
5293
5294 if (localLOGV) Log.v(
5295 TAG, "Binding process pid " + pid + " to record " + app);
5296
5297 String processName = app.processName;
5298 try {
5299 thread.asBinder().linkToDeath(new AppDeathRecipient(
5300 app, pid, thread), 0);
5301 } catch (RemoteException e) {
5302 app.resetPackageList();
5303 startProcessLocked(app, "link fail", processName);
5304 return false;
5305 }
5306
5307 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5308
5309 app.thread = thread;
5310 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005311 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005312 app.forcingToForeground = null;
5313 app.foregroundServices = false;
5314 app.debugging = false;
5315
5316 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5317
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005318 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5319 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005320
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005321 if (!normalMode) {
5322 Log.i(TAG, "Launching preboot mode app: " + app);
5323 }
5324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005325 if (localLOGV) Log.v(
5326 TAG, "New app record " + app
5327 + " thread=" + thread.asBinder() + " pid=" + pid);
5328 try {
5329 int testMode = IApplicationThread.DEBUG_OFF;
5330 if (mDebugApp != null && mDebugApp.equals(processName)) {
5331 testMode = mWaitForDebugger
5332 ? IApplicationThread.DEBUG_WAIT
5333 : IApplicationThread.DEBUG_ON;
5334 app.debugging = true;
5335 if (mDebugTransient) {
5336 mDebugApp = mOrigDebugApp;
5337 mWaitForDebugger = mOrigWaitForDebugger;
5338 }
5339 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005340
Christopher Tate181fafa2009-05-14 11:12:14 -07005341 // If the app is being launched for restore or full backup, set it up specially
5342 boolean isRestrictedBackupMode = false;
5343 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5344 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5345 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5346 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005347
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005348 ensurePackageDexOpt(app.instrumentationInfo != null
5349 ? app.instrumentationInfo.packageName
5350 : app.info.packageName);
5351 if (app.instrumentationClass != null) {
5352 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005353 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005354 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5355 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005356 thread.bindApplication(processName, app.instrumentationInfo != null
5357 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005358 app.instrumentationClass, app.instrumentationProfileFile,
5359 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005360 isRestrictedBackupMode || !normalMode,
5361 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005362 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005363 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005364 } catch (Exception e) {
5365 // todo: Yikes! What should we do? For now we will try to
5366 // start another process, but that could easily get us in
5367 // an infinite loop of restarting processes...
5368 Log.w(TAG, "Exception thrown during bind!", e);
5369
5370 app.resetPackageList();
5371 startProcessLocked(app, "bind fail", processName);
5372 return false;
5373 }
5374
5375 // Remove this record from the list of starting applications.
5376 mPersistentStartingProcesses.remove(app);
5377 mProcessesOnHold.remove(app);
5378
5379 boolean badApp = false;
5380 boolean didSomething = false;
5381
5382 // See if the top visible activity is waiting to run in this process...
5383 HistoryRecord hr = topRunningActivityLocked(null);
5384 if (hr != null) {
5385 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5386 && processName.equals(hr.processName)) {
5387 try {
5388 if (realStartActivityLocked(hr, app, true, true)) {
5389 didSomething = true;
5390 }
5391 } catch (Exception e) {
5392 Log.w(TAG, "Exception in new application when starting activity "
5393 + hr.intent.getComponent().flattenToShortString(), e);
5394 badApp = true;
5395 }
5396 } else {
5397 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5398 }
5399 }
5400
5401 // Find any services that should be running in this process...
5402 if (!badApp && mPendingServices.size() > 0) {
5403 ServiceRecord sr = null;
5404 try {
5405 for (int i=0; i<mPendingServices.size(); i++) {
5406 sr = mPendingServices.get(i);
5407 if (app.info.uid != sr.appInfo.uid
5408 || !processName.equals(sr.processName)) {
5409 continue;
5410 }
5411
5412 mPendingServices.remove(i);
5413 i--;
5414 realStartServiceLocked(sr, app);
5415 didSomething = true;
5416 }
5417 } catch (Exception e) {
5418 Log.w(TAG, "Exception in new application when starting service "
5419 + sr.shortName, e);
5420 badApp = true;
5421 }
5422 }
5423
5424 // Check if the next broadcast receiver is in this process...
5425 BroadcastRecord br = mPendingBroadcast;
5426 if (!badApp && br != null && br.curApp == app) {
5427 try {
5428 mPendingBroadcast = null;
5429 processCurBroadcastLocked(br, app);
5430 didSomething = true;
5431 } catch (Exception e) {
5432 Log.w(TAG, "Exception in new application when starting receiver "
5433 + br.curComponent.flattenToShortString(), e);
5434 badApp = true;
5435 logBroadcastReceiverDiscard(br);
5436 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5437 br.resultExtras, br.resultAbort, true);
5438 scheduleBroadcastsLocked();
Magnus Edlund7bb25812010-02-24 15:45:06 +01005439 // We need to reset the state if we fails to start the receiver.
5440 br.state = BroadcastRecord.IDLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005441 }
5442 }
5443
Christopher Tate181fafa2009-05-14 11:12:14 -07005444 // Check whether the next backup agent is in this process...
5445 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5446 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005447 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005448 try {
5449 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5450 } catch (Exception e) {
5451 Log.w(TAG, "Exception scheduling backup agent creation: ");
5452 e.printStackTrace();
5453 }
5454 }
5455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005456 if (badApp) {
5457 // todo: Also need to kill application to deal with all
5458 // kinds of exceptions.
5459 handleAppDiedLocked(app, false);
5460 return false;
5461 }
5462
5463 if (!didSomething) {
5464 updateOomAdjLocked();
5465 }
5466
5467 return true;
5468 }
5469
5470 public final void attachApplication(IApplicationThread thread) {
5471 synchronized (this) {
5472 int callingPid = Binder.getCallingPid();
5473 final long origId = Binder.clearCallingIdentity();
5474 attachApplicationLocked(thread, callingPid);
5475 Binder.restoreCallingIdentity(origId);
5476 }
5477 }
5478
Dianne Hackborne88846e2009-09-30 21:34:25 -07005479 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005480 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005481 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005482 Binder.restoreCallingIdentity(origId);
5483 }
5484
5485 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5486 boolean remove) {
5487 int N = mStoppingActivities.size();
5488 if (N <= 0) return null;
5489
5490 ArrayList<HistoryRecord> stops = null;
5491
5492 final boolean nowVisible = mResumedActivity != null
5493 && mResumedActivity.nowVisible
5494 && !mResumedActivity.waitingVisible;
5495 for (int i=0; i<N; i++) {
5496 HistoryRecord s = mStoppingActivities.get(i);
5497 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5498 + nowVisible + " waitingVisible=" + s.waitingVisible
5499 + " finishing=" + s.finishing);
5500 if (s.waitingVisible && nowVisible) {
5501 mWaitingVisibleActivities.remove(s);
5502 s.waitingVisible = false;
5503 if (s.finishing) {
5504 // If this activity is finishing, it is sitting on top of
5505 // everyone else but we now know it is no longer needed...
5506 // so get rid of it. Otherwise, we need to go through the
5507 // normal flow and hide it once we determine that it is
5508 // hidden by the activities in front of it.
5509 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5510 mWindowManager.setAppVisibility(s, false);
5511 }
5512 }
5513 if (!s.waitingVisible && remove) {
5514 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5515 if (stops == null) {
5516 stops = new ArrayList<HistoryRecord>();
5517 }
5518 stops.add(s);
5519 mStoppingActivities.remove(i);
5520 N--;
5521 i--;
5522 }
5523 }
5524
5525 return stops;
5526 }
5527
5528 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005529 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5530 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005531 mWindowManager.enableScreenAfterBoot();
5532 }
5533
Dianne Hackborne88846e2009-09-30 21:34:25 -07005534 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5535 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005536 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5537
5538 ArrayList<HistoryRecord> stops = null;
5539 ArrayList<HistoryRecord> finishes = null;
5540 ArrayList<HistoryRecord> thumbnails = null;
5541 int NS = 0;
5542 int NF = 0;
5543 int NT = 0;
5544 IApplicationThread sendThumbnail = null;
5545 boolean booting = false;
5546 boolean enableScreen = false;
5547
5548 synchronized (this) {
5549 if (token != null) {
5550 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5551 }
5552
5553 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005554 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005555 if (index >= 0) {
5556 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5557
Dianne Hackborne88846e2009-09-30 21:34:25 -07005558 // This is a hack to semi-deal with a race condition
5559 // in the client where it can be constructed with a
5560 // newer configuration from when we asked it to launch.
5561 // We'll update with whatever configuration it now says
5562 // it used to launch.
5563 if (config != null) {
5564 r.configuration = config;
5565 }
5566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005567 // No longer need to keep the device awake.
5568 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5569 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5570 mLaunchingActivity.release();
5571 }
5572
5573 // We are now idle. If someone is waiting for a thumbnail from
5574 // us, we can now deliver.
5575 r.idle = true;
5576 scheduleAppGcsLocked();
5577 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5578 sendThumbnail = r.app.thread;
5579 r.thumbnailNeeded = false;
5580 }
5581
5582 // If this activity is fullscreen, set up to hide those under it.
5583
5584 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5585 ensureActivitiesVisibleLocked(null, 0);
5586
5587 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5588 if (!mBooted && !fromTimeout) {
5589 mBooted = true;
5590 enableScreen = true;
5591 }
5592 }
5593
5594 // Atomically retrieve all of the other things to do.
5595 stops = processStoppingActivitiesLocked(true);
5596 NS = stops != null ? stops.size() : 0;
5597 if ((NF=mFinishingActivities.size()) > 0) {
5598 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5599 mFinishingActivities.clear();
5600 }
5601 if ((NT=mCancelledThumbnails.size()) > 0) {
5602 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5603 mCancelledThumbnails.clear();
5604 }
5605
5606 booting = mBooting;
5607 mBooting = false;
5608 }
5609
5610 int i;
5611
5612 // Send thumbnail if requested.
5613 if (sendThumbnail != null) {
5614 try {
5615 sendThumbnail.requestThumbnail(token);
5616 } catch (Exception e) {
5617 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5618 sendPendingThumbnail(null, token, null, null, true);
5619 }
5620 }
5621
5622 // Stop any activities that are scheduled to do so but have been
5623 // waiting for the next one to start.
5624 for (i=0; i<NS; i++) {
5625 HistoryRecord r = (HistoryRecord)stops.get(i);
5626 synchronized (this) {
5627 if (r.finishing) {
5628 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5629 } else {
5630 stopActivityLocked(r);
5631 }
5632 }
5633 }
5634
5635 // Finish any activities that are scheduled to do so but have been
5636 // waiting for the next one to start.
5637 for (i=0; i<NF; i++) {
5638 HistoryRecord r = (HistoryRecord)finishes.get(i);
5639 synchronized (this) {
5640 destroyActivityLocked(r, true);
5641 }
5642 }
5643
5644 // Report back to any thumbnail receivers.
5645 for (i=0; i<NT; i++) {
5646 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5647 sendPendingThumbnail(r, null, null, null, true);
5648 }
5649
5650 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005651 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005652 }
5653
5654 trimApplications();
5655 //dump();
5656 //mWindowManager.dump();
5657
5658 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005659 enableScreenAfterBoot();
5660 }
5661 }
5662
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005663 final void finishBooting() {
5664 // Ensure that any processes we had put on hold are now started
5665 // up.
5666 final int NP = mProcessesOnHold.size();
5667 if (NP > 0) {
5668 ArrayList<ProcessRecord> procs =
5669 new ArrayList<ProcessRecord>(mProcessesOnHold);
5670 for (int ip=0; ip<NP; ip++) {
5671 this.startProcessLocked(procs.get(ip), "on-hold", null);
5672 }
5673 }
5674 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5675 // Tell anyone interested that we are done booting!
5676 synchronized (this) {
5677 broadcastIntentLocked(null, null,
5678 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5679 null, null, 0, null, null,
5680 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5681 false, false, MY_PID, Process.SYSTEM_UID);
5682 }
5683 }
5684 }
5685
5686 final void ensureBootCompleted() {
5687 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005688 boolean enableScreen;
5689 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005690 booting = mBooting;
5691 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005692 enableScreen = !mBooted;
5693 mBooted = true;
5694 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005695
5696 if (booting) {
5697 finishBooting();
5698 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005699
5700 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005701 enableScreenAfterBoot();
5702 }
5703 }
5704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005705 public final void activityPaused(IBinder token, Bundle icicle) {
5706 // Refuse possible leaked file descriptors
5707 if (icicle != null && icicle.hasFileDescriptors()) {
5708 throw new IllegalArgumentException("File descriptors passed in Bundle");
5709 }
5710
5711 final long origId = Binder.clearCallingIdentity();
5712 activityPaused(token, icicle, false);
5713 Binder.restoreCallingIdentity(origId);
5714 }
5715
5716 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5717 if (DEBUG_PAUSE) Log.v(
5718 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5719 + ", timeout=" + timeout);
5720
5721 HistoryRecord r = null;
5722
5723 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005724 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005725 if (index >= 0) {
5726 r = (HistoryRecord)mHistory.get(index);
5727 if (!timeout) {
5728 r.icicle = icicle;
5729 r.haveState = true;
5730 }
5731 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5732 if (mPausingActivity == r) {
5733 r.state = ActivityState.PAUSED;
5734 completePauseLocked();
5735 } else {
5736 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5737 System.identityHashCode(r), r.shortComponentName,
5738 mPausingActivity != null
5739 ? mPausingActivity.shortComponentName : "(none)");
5740 }
5741 }
5742 }
5743 }
5744
5745 public final void activityStopped(IBinder token, Bitmap thumbnail,
5746 CharSequence description) {
5747 if (localLOGV) Log.v(
5748 TAG, "Activity stopped: token=" + token);
5749
5750 HistoryRecord r = null;
5751
5752 final long origId = Binder.clearCallingIdentity();
5753
5754 synchronized (this) {
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 r = (HistoryRecord)mHistory.get(index);
5758 r.thumbnail = thumbnail;
5759 r.description = description;
5760 r.stopped = true;
5761 r.state = ActivityState.STOPPED;
5762 if (!r.finishing) {
5763 if (r.configDestroy) {
5764 destroyActivityLocked(r, true);
5765 resumeTopActivityLocked(null);
5766 }
5767 }
5768 }
5769 }
5770
5771 if (r != null) {
5772 sendPendingThumbnail(r, null, null, null, false);
5773 }
5774
5775 trimApplications();
5776
5777 Binder.restoreCallingIdentity(origId);
5778 }
5779
5780 public final void activityDestroyed(IBinder token) {
5781 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5782 synchronized (this) {
5783 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5784
Dianne Hackborn75b03852009-06-12 15:43:26 -07005785 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005786 if (index >= 0) {
5787 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5788 if (r.state == ActivityState.DESTROYING) {
5789 final long origId = Binder.clearCallingIdentity();
5790 removeActivityFromHistoryLocked(r);
5791 Binder.restoreCallingIdentity(origId);
5792 }
5793 }
5794 }
5795 }
5796
5797 public String getCallingPackage(IBinder token) {
5798 synchronized (this) {
5799 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005800 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005801 }
5802 }
5803
5804 public ComponentName getCallingActivity(IBinder token) {
5805 synchronized (this) {
5806 HistoryRecord r = getCallingRecordLocked(token);
5807 return r != null ? r.intent.getComponent() : null;
5808 }
5809 }
5810
5811 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005812 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005813 if (index >= 0) {
5814 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5815 if (r != null) {
5816 return r.resultTo;
5817 }
5818 }
5819 return null;
5820 }
5821
5822 public ComponentName getActivityClassForToken(IBinder token) {
5823 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005824 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005825 if (index >= 0) {
5826 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5827 return r.intent.getComponent();
5828 }
5829 return null;
5830 }
5831 }
5832
5833 public String getPackageForToken(IBinder token) {
5834 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005835 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005836 if (index >= 0) {
5837 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5838 return r.packageName;
5839 }
5840 return null;
5841 }
5842 }
5843
5844 public IIntentSender getIntentSender(int type,
5845 String packageName, IBinder token, String resultWho,
5846 int requestCode, Intent intent, String resolvedType, int flags) {
5847 // Refuse possible leaked file descriptors
5848 if (intent != null && intent.hasFileDescriptors() == true) {
5849 throw new IllegalArgumentException("File descriptors passed in Intent");
5850 }
5851
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005852 if (type == INTENT_SENDER_BROADCAST) {
5853 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5854 throw new IllegalArgumentException(
5855 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5856 }
5857 }
5858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005859 synchronized(this) {
5860 int callingUid = Binder.getCallingUid();
5861 try {
5862 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5863 Process.supportsProcesses()) {
5864 int uid = ActivityThread.getPackageManager()
5865 .getPackageUid(packageName);
5866 if (uid != Binder.getCallingUid()) {
5867 String msg = "Permission Denial: getIntentSender() from pid="
5868 + Binder.getCallingPid()
5869 + ", uid=" + Binder.getCallingUid()
5870 + ", (need uid=" + uid + ")"
5871 + " is not allowed to send as package " + packageName;
5872 Log.w(TAG, msg);
5873 throw new SecurityException(msg);
5874 }
5875 }
5876 } catch (RemoteException e) {
5877 throw new SecurityException(e);
5878 }
5879 HistoryRecord activity = null;
5880 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005881 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005882 if (index < 0) {
5883 return null;
5884 }
5885 activity = (HistoryRecord)mHistory.get(index);
5886 if (activity.finishing) {
5887 return null;
5888 }
5889 }
5890
5891 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5892 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5893 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5894 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5895 |PendingIntent.FLAG_UPDATE_CURRENT);
5896
5897 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5898 type, packageName, activity, resultWho,
5899 requestCode, intent, resolvedType, flags);
5900 WeakReference<PendingIntentRecord> ref;
5901 ref = mIntentSenderRecords.get(key);
5902 PendingIntentRecord rec = ref != null ? ref.get() : null;
5903 if (rec != null) {
5904 if (!cancelCurrent) {
5905 if (updateCurrent) {
5906 rec.key.requestIntent.replaceExtras(intent);
5907 }
5908 return rec;
5909 }
5910 rec.canceled = true;
5911 mIntentSenderRecords.remove(key);
5912 }
5913 if (noCreate) {
5914 return rec;
5915 }
5916 rec = new PendingIntentRecord(this, key, callingUid);
5917 mIntentSenderRecords.put(key, rec.ref);
5918 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5919 if (activity.pendingResults == null) {
5920 activity.pendingResults
5921 = new HashSet<WeakReference<PendingIntentRecord>>();
5922 }
5923 activity.pendingResults.add(rec.ref);
5924 }
5925 return rec;
5926 }
5927 }
5928
5929 public void cancelIntentSender(IIntentSender sender) {
5930 if (!(sender instanceof PendingIntentRecord)) {
5931 return;
5932 }
5933 synchronized(this) {
5934 PendingIntentRecord rec = (PendingIntentRecord)sender;
5935 try {
5936 int uid = ActivityThread.getPackageManager()
5937 .getPackageUid(rec.key.packageName);
5938 if (uid != Binder.getCallingUid()) {
5939 String msg = "Permission Denial: cancelIntentSender() from pid="
5940 + Binder.getCallingPid()
5941 + ", uid=" + Binder.getCallingUid()
5942 + " is not allowed to cancel packges "
5943 + rec.key.packageName;
5944 Log.w(TAG, msg);
5945 throw new SecurityException(msg);
5946 }
5947 } catch (RemoteException e) {
5948 throw new SecurityException(e);
5949 }
5950 cancelIntentSenderLocked(rec, true);
5951 }
5952 }
5953
5954 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5955 rec.canceled = true;
5956 mIntentSenderRecords.remove(rec.key);
5957 if (cleanActivity && rec.key.activity != null) {
5958 rec.key.activity.pendingResults.remove(rec.ref);
5959 }
5960 }
5961
5962 public String getPackageForIntentSender(IIntentSender pendingResult) {
5963 if (!(pendingResult instanceof PendingIntentRecord)) {
5964 return null;
5965 }
5966 synchronized(this) {
5967 try {
5968 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5969 return res.key.packageName;
5970 } catch (ClassCastException e) {
5971 }
5972 }
5973 return null;
5974 }
5975
5976 public void setProcessLimit(int max) {
5977 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5978 "setProcessLimit()");
5979 mProcessLimit = max;
5980 }
5981
5982 public int getProcessLimit() {
5983 return mProcessLimit;
5984 }
5985
5986 void foregroundTokenDied(ForegroundToken token) {
5987 synchronized (ActivityManagerService.this) {
5988 synchronized (mPidsSelfLocked) {
5989 ForegroundToken cur
5990 = mForegroundProcesses.get(token.pid);
5991 if (cur != token) {
5992 return;
5993 }
5994 mForegroundProcesses.remove(token.pid);
5995 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5996 if (pr == null) {
5997 return;
5998 }
5999 pr.forcingToForeground = null;
6000 pr.foregroundServices = false;
6001 }
6002 updateOomAdjLocked();
6003 }
6004 }
6005
6006 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
6007 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
6008 "setProcessForeground()");
6009 synchronized(this) {
6010 boolean changed = false;
6011
6012 synchronized (mPidsSelfLocked) {
6013 ProcessRecord pr = mPidsSelfLocked.get(pid);
6014 if (pr == null) {
6015 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
6016 return;
6017 }
6018 ForegroundToken oldToken = mForegroundProcesses.get(pid);
6019 if (oldToken != null) {
6020 oldToken.token.unlinkToDeath(oldToken, 0);
6021 mForegroundProcesses.remove(pid);
6022 pr.forcingToForeground = null;
6023 changed = true;
6024 }
6025 if (isForeground && token != null) {
6026 ForegroundToken newToken = new ForegroundToken() {
6027 public void binderDied() {
6028 foregroundTokenDied(this);
6029 }
6030 };
6031 newToken.pid = pid;
6032 newToken.token = token;
6033 try {
6034 token.linkToDeath(newToken, 0);
6035 mForegroundProcesses.put(pid, newToken);
6036 pr.forcingToForeground = token;
6037 changed = true;
6038 } catch (RemoteException e) {
6039 // If the process died while doing this, we will later
6040 // do the cleanup with the process death link.
6041 }
6042 }
6043 }
6044
6045 if (changed) {
6046 updateOomAdjLocked();
6047 }
6048 }
6049 }
6050
6051 // =========================================================
6052 // PERMISSIONS
6053 // =========================================================
6054
6055 static class PermissionController extends IPermissionController.Stub {
6056 ActivityManagerService mActivityManagerService;
6057 PermissionController(ActivityManagerService activityManagerService) {
6058 mActivityManagerService = activityManagerService;
6059 }
6060
6061 public boolean checkPermission(String permission, int pid, int uid) {
6062 return mActivityManagerService.checkPermission(permission, pid,
6063 uid) == PackageManager.PERMISSION_GRANTED;
6064 }
6065 }
6066
6067 /**
6068 * This can be called with or without the global lock held.
6069 */
6070 int checkComponentPermission(String permission, int pid, int uid,
6071 int reqUid) {
6072 // We might be performing an operation on behalf of an indirect binder
6073 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6074 // client identity accordingly before proceeding.
6075 Identity tlsIdentity = sCallerIdentity.get();
6076 if (tlsIdentity != null) {
6077 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6078 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6079 uid = tlsIdentity.uid;
6080 pid = tlsIdentity.pid;
6081 }
6082
6083 // Root, system server and our own process get to do everything.
6084 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6085 !Process.supportsProcesses()) {
6086 return PackageManager.PERMISSION_GRANTED;
6087 }
6088 // If the target requires a specific UID, always fail for others.
6089 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006090 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006091 return PackageManager.PERMISSION_DENIED;
6092 }
6093 if (permission == null) {
6094 return PackageManager.PERMISSION_GRANTED;
6095 }
6096 try {
6097 return ActivityThread.getPackageManager()
6098 .checkUidPermission(permission, uid);
6099 } catch (RemoteException e) {
6100 // Should never happen, but if it does... deny!
6101 Log.e(TAG, "PackageManager is dead?!?", e);
6102 }
6103 return PackageManager.PERMISSION_DENIED;
6104 }
6105
6106 /**
6107 * As the only public entry point for permissions checking, this method
6108 * can enforce the semantic that requesting a check on a null global
6109 * permission is automatically denied. (Internally a null permission
6110 * string is used when calling {@link #checkComponentPermission} in cases
6111 * when only uid-based security is needed.)
6112 *
6113 * This can be called with or without the global lock held.
6114 */
6115 public int checkPermission(String permission, int pid, int uid) {
6116 if (permission == null) {
6117 return PackageManager.PERMISSION_DENIED;
6118 }
6119 return checkComponentPermission(permission, pid, uid, -1);
6120 }
6121
6122 /**
6123 * Binder IPC calls go through the public entry point.
6124 * This can be called with or without the global lock held.
6125 */
6126 int checkCallingPermission(String permission) {
6127 return checkPermission(permission,
6128 Binder.getCallingPid(),
6129 Binder.getCallingUid());
6130 }
6131
6132 /**
6133 * This can be called with or without the global lock held.
6134 */
6135 void enforceCallingPermission(String permission, String func) {
6136 if (checkCallingPermission(permission)
6137 == PackageManager.PERMISSION_GRANTED) {
6138 return;
6139 }
6140
6141 String msg = "Permission Denial: " + func + " from pid="
6142 + Binder.getCallingPid()
6143 + ", uid=" + Binder.getCallingUid()
6144 + " requires " + permission;
6145 Log.w(TAG, msg);
6146 throw new SecurityException(msg);
6147 }
6148
6149 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6150 ProviderInfo pi, int uid, int modeFlags) {
6151 try {
6152 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6153 if ((pi.readPermission != null) &&
6154 (pm.checkUidPermission(pi.readPermission, uid)
6155 != PackageManager.PERMISSION_GRANTED)) {
6156 return false;
6157 }
6158 }
6159 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6160 if ((pi.writePermission != null) &&
6161 (pm.checkUidPermission(pi.writePermission, uid)
6162 != PackageManager.PERMISSION_GRANTED)) {
6163 return false;
6164 }
6165 }
6166 return true;
6167 } catch (RemoteException e) {
6168 return false;
6169 }
6170 }
6171
6172 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6173 int modeFlags) {
6174 // Root gets to do everything.
6175 if (uid == 0 || !Process.supportsProcesses()) {
6176 return true;
6177 }
6178 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6179 if (perms == null) return false;
6180 UriPermission perm = perms.get(uri);
6181 if (perm == null) return false;
6182 return (modeFlags&perm.modeFlags) == modeFlags;
6183 }
6184
6185 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6186 // Another redirected-binder-call permissions check as in
6187 // {@link checkComponentPermission}.
6188 Identity tlsIdentity = sCallerIdentity.get();
6189 if (tlsIdentity != null) {
6190 uid = tlsIdentity.uid;
6191 pid = tlsIdentity.pid;
6192 }
6193
6194 // Our own process gets to do everything.
6195 if (pid == MY_PID) {
6196 return PackageManager.PERMISSION_GRANTED;
6197 }
6198 synchronized(this) {
6199 return checkUriPermissionLocked(uri, uid, modeFlags)
6200 ? PackageManager.PERMISSION_GRANTED
6201 : PackageManager.PERMISSION_DENIED;
6202 }
6203 }
6204
6205 private void grantUriPermissionLocked(int callingUid,
6206 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6207 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6208 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6209 if (modeFlags == 0) {
6210 return;
6211 }
6212
6213 final IPackageManager pm = ActivityThread.getPackageManager();
6214
6215 // If this is not a content: uri, we can't do anything with it.
6216 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6217 return;
6218 }
6219
6220 String name = uri.getAuthority();
6221 ProviderInfo pi = null;
6222 ContentProviderRecord cpr
6223 = (ContentProviderRecord)mProvidersByName.get(name);
6224 if (cpr != null) {
6225 pi = cpr.info;
6226 } else {
6227 try {
6228 pi = pm.resolveContentProvider(name,
6229 PackageManager.GET_URI_PERMISSION_PATTERNS);
6230 } catch (RemoteException ex) {
6231 }
6232 }
6233 if (pi == null) {
6234 Log.w(TAG, "No content provider found for: " + name);
6235 return;
6236 }
6237
6238 int targetUid;
6239 try {
6240 targetUid = pm.getPackageUid(targetPkg);
6241 if (targetUid < 0) {
6242 return;
6243 }
6244 } catch (RemoteException ex) {
6245 return;
6246 }
6247
6248 // First... does the target actually need this permission?
6249 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6250 // No need to grant the target this permission.
6251 return;
6252 }
6253
6254 // Second... maybe someone else has already granted the
6255 // permission?
6256 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6257 // No need to grant the target this permission.
6258 return;
6259 }
6260
6261 // Third... is the provider allowing granting of URI permissions?
6262 if (!pi.grantUriPermissions) {
6263 throw new SecurityException("Provider " + pi.packageName
6264 + "/" + pi.name
6265 + " does not allow granting of Uri permissions (uri "
6266 + uri + ")");
6267 }
6268 if (pi.uriPermissionPatterns != null) {
6269 final int N = pi.uriPermissionPatterns.length;
6270 boolean allowed = false;
6271 for (int i=0; i<N; i++) {
6272 if (pi.uriPermissionPatterns[i] != null
6273 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6274 allowed = true;
6275 break;
6276 }
6277 }
6278 if (!allowed) {
6279 throw new SecurityException("Provider " + pi.packageName
6280 + "/" + pi.name
6281 + " does not allow granting of permission to path of Uri "
6282 + uri);
6283 }
6284 }
6285
6286 // Fourth... does the caller itself have permission to access
6287 // this uri?
6288 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6289 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6290 throw new SecurityException("Uid " + callingUid
6291 + " does not have permission to uri " + uri);
6292 }
6293 }
6294
6295 // Okay! So here we are: the caller has the assumed permission
6296 // to the uri, and the target doesn't. Let's now give this to
6297 // the target.
6298
6299 HashMap<Uri, UriPermission> targetUris
6300 = mGrantedUriPermissions.get(targetUid);
6301 if (targetUris == null) {
6302 targetUris = new HashMap<Uri, UriPermission>();
6303 mGrantedUriPermissions.put(targetUid, targetUris);
6304 }
6305
6306 UriPermission perm = targetUris.get(uri);
6307 if (perm == null) {
6308 perm = new UriPermission(targetUid, uri);
6309 targetUris.put(uri, perm);
6310
6311 }
6312 perm.modeFlags |= modeFlags;
6313 if (activity == null) {
6314 perm.globalModeFlags |= modeFlags;
6315 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6316 perm.readActivities.add(activity);
6317 if (activity.readUriPermissions == null) {
6318 activity.readUriPermissions = new HashSet<UriPermission>();
6319 }
6320 activity.readUriPermissions.add(perm);
6321 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6322 perm.writeActivities.add(activity);
6323 if (activity.writeUriPermissions == null) {
6324 activity.writeUriPermissions = new HashSet<UriPermission>();
6325 }
6326 activity.writeUriPermissions.add(perm);
6327 }
6328 }
6329
6330 private void grantUriPermissionFromIntentLocked(int callingUid,
6331 String targetPkg, Intent intent, HistoryRecord activity) {
6332 if (intent == null) {
6333 return;
6334 }
6335 Uri data = intent.getData();
6336 if (data == null) {
6337 return;
6338 }
6339 grantUriPermissionLocked(callingUid, targetPkg, data,
6340 intent.getFlags(), activity);
6341 }
6342
6343 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6344 Uri uri, int modeFlags) {
6345 synchronized(this) {
6346 final ProcessRecord r = getRecordForAppLocked(caller);
6347 if (r == null) {
6348 throw new SecurityException("Unable to find app for caller "
6349 + caller
6350 + " when granting permission to uri " + uri);
6351 }
6352 if (targetPkg == null) {
6353 Log.w(TAG, "grantUriPermission: null target");
6354 return;
6355 }
6356 if (uri == null) {
6357 Log.w(TAG, "grantUriPermission: null uri");
6358 return;
6359 }
6360
6361 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6362 null);
6363 }
6364 }
6365
6366 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6367 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6368 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6369 HashMap<Uri, UriPermission> perms
6370 = mGrantedUriPermissions.get(perm.uid);
6371 if (perms != null) {
6372 perms.remove(perm.uri);
6373 if (perms.size() == 0) {
6374 mGrantedUriPermissions.remove(perm.uid);
6375 }
6376 }
6377 }
6378 }
6379
6380 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6381 if (activity.readUriPermissions != null) {
6382 for (UriPermission perm : activity.readUriPermissions) {
6383 perm.readActivities.remove(activity);
6384 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6385 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6386 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6387 removeUriPermissionIfNeededLocked(perm);
6388 }
6389 }
6390 }
6391 if (activity.writeUriPermissions != null) {
6392 for (UriPermission perm : activity.writeUriPermissions) {
6393 perm.writeActivities.remove(activity);
6394 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6395 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6396 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6397 removeUriPermissionIfNeededLocked(perm);
6398 }
6399 }
6400 }
6401 }
6402
6403 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6404 int modeFlags) {
6405 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6406 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6407 if (modeFlags == 0) {
6408 return;
6409 }
6410
6411 final IPackageManager pm = ActivityThread.getPackageManager();
6412
6413 final String authority = uri.getAuthority();
6414 ProviderInfo pi = null;
6415 ContentProviderRecord cpr
6416 = (ContentProviderRecord)mProvidersByName.get(authority);
6417 if (cpr != null) {
6418 pi = cpr.info;
6419 } else {
6420 try {
6421 pi = pm.resolveContentProvider(authority,
6422 PackageManager.GET_URI_PERMISSION_PATTERNS);
6423 } catch (RemoteException ex) {
6424 }
6425 }
6426 if (pi == null) {
6427 Log.w(TAG, "No content provider found for: " + authority);
6428 return;
6429 }
6430
6431 // Does the caller have this permission on the URI?
6432 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6433 // Right now, if you are not the original owner of the permission,
6434 // you are not allowed to revoke it.
6435 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6436 throw new SecurityException("Uid " + callingUid
6437 + " does not have permission to uri " + uri);
6438 //}
6439 }
6440
6441 // Go through all of the permissions and remove any that match.
6442 final List<String> SEGMENTS = uri.getPathSegments();
6443 if (SEGMENTS != null) {
6444 final int NS = SEGMENTS.size();
6445 int N = mGrantedUriPermissions.size();
6446 for (int i=0; i<N; i++) {
6447 HashMap<Uri, UriPermission> perms
6448 = mGrantedUriPermissions.valueAt(i);
6449 Iterator<UriPermission> it = perms.values().iterator();
6450 toploop:
6451 while (it.hasNext()) {
6452 UriPermission perm = it.next();
6453 Uri targetUri = perm.uri;
6454 if (!authority.equals(targetUri.getAuthority())) {
6455 continue;
6456 }
6457 List<String> targetSegments = targetUri.getPathSegments();
6458 if (targetSegments == null) {
6459 continue;
6460 }
6461 if (targetSegments.size() < NS) {
6462 continue;
6463 }
6464 for (int j=0; j<NS; j++) {
6465 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6466 continue toploop;
6467 }
6468 }
6469 perm.clearModes(modeFlags);
6470 if (perm.modeFlags == 0) {
6471 it.remove();
6472 }
6473 }
6474 if (perms.size() == 0) {
6475 mGrantedUriPermissions.remove(
6476 mGrantedUriPermissions.keyAt(i));
6477 N--;
6478 i--;
6479 }
6480 }
6481 }
6482 }
6483
6484 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6485 int modeFlags) {
6486 synchronized(this) {
6487 final ProcessRecord r = getRecordForAppLocked(caller);
6488 if (r == null) {
6489 throw new SecurityException("Unable to find app for caller "
6490 + caller
6491 + " when revoking permission to uri " + uri);
6492 }
6493 if (uri == null) {
6494 Log.w(TAG, "revokeUriPermission: null uri");
6495 return;
6496 }
6497
6498 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6499 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6500 if (modeFlags == 0) {
6501 return;
6502 }
6503
6504 final IPackageManager pm = ActivityThread.getPackageManager();
6505
6506 final String authority = uri.getAuthority();
6507 ProviderInfo pi = null;
6508 ContentProviderRecord cpr
6509 = (ContentProviderRecord)mProvidersByName.get(authority);
6510 if (cpr != null) {
6511 pi = cpr.info;
6512 } else {
6513 try {
6514 pi = pm.resolveContentProvider(authority,
6515 PackageManager.GET_URI_PERMISSION_PATTERNS);
6516 } catch (RemoteException ex) {
6517 }
6518 }
6519 if (pi == null) {
6520 Log.w(TAG, "No content provider found for: " + authority);
6521 return;
6522 }
6523
6524 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6525 }
6526 }
6527
6528 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6529 synchronized (this) {
6530 ProcessRecord app =
6531 who != null ? getRecordForAppLocked(who) : null;
6532 if (app == null) return;
6533
6534 Message msg = Message.obtain();
6535 msg.what = WAIT_FOR_DEBUGGER_MSG;
6536 msg.obj = app;
6537 msg.arg1 = waiting ? 1 : 0;
6538 mHandler.sendMessage(msg);
6539 }
6540 }
6541
6542 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6543 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006544 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006545 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006546 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006547 }
6548
6549 // =========================================================
6550 // TASK MANAGEMENT
6551 // =========================================================
6552
6553 public List getTasks(int maxNum, int flags,
6554 IThumbnailReceiver receiver) {
6555 ArrayList list = new ArrayList();
6556
6557 PendingThumbnailsRecord pending = null;
6558 IApplicationThread topThumbnail = null;
6559 HistoryRecord topRecord = null;
6560
6561 synchronized(this) {
6562 if (localLOGV) Log.v(
6563 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6564 + ", receiver=" + receiver);
6565
6566 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6567 != PackageManager.PERMISSION_GRANTED) {
6568 if (receiver != null) {
6569 // If the caller wants to wait for pending thumbnails,
6570 // it ain't gonna get them.
6571 try {
6572 receiver.finished();
6573 } catch (RemoteException ex) {
6574 }
6575 }
6576 String msg = "Permission Denial: getTasks() from pid="
6577 + Binder.getCallingPid()
6578 + ", uid=" + Binder.getCallingUid()
6579 + " requires " + android.Manifest.permission.GET_TASKS;
6580 Log.w(TAG, msg);
6581 throw new SecurityException(msg);
6582 }
6583
6584 int pos = mHistory.size()-1;
6585 HistoryRecord next =
6586 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6587 HistoryRecord top = null;
6588 CharSequence topDescription = null;
6589 TaskRecord curTask = null;
6590 int numActivities = 0;
6591 int numRunning = 0;
6592 while (pos >= 0 && maxNum > 0) {
6593 final HistoryRecord r = next;
6594 pos--;
6595 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6596
6597 // Initialize state for next task if needed.
6598 if (top == null ||
6599 (top.state == ActivityState.INITIALIZING
6600 && top.task == r.task)) {
6601 top = r;
6602 topDescription = r.description;
6603 curTask = r.task;
6604 numActivities = numRunning = 0;
6605 }
6606
6607 // Add 'r' into the current task.
6608 numActivities++;
6609 if (r.app != null && r.app.thread != null) {
6610 numRunning++;
6611 }
6612 if (topDescription == null) {
6613 topDescription = r.description;
6614 }
6615
6616 if (localLOGV) Log.v(
6617 TAG, r.intent.getComponent().flattenToShortString()
6618 + ": task=" + r.task);
6619
6620 // If the next one is a different task, generate a new
6621 // TaskInfo entry for what we have.
6622 if (next == null || next.task != curTask) {
6623 ActivityManager.RunningTaskInfo ci
6624 = new ActivityManager.RunningTaskInfo();
6625 ci.id = curTask.taskId;
6626 ci.baseActivity = r.intent.getComponent();
6627 ci.topActivity = top.intent.getComponent();
6628 ci.thumbnail = top.thumbnail;
6629 ci.description = topDescription;
6630 ci.numActivities = numActivities;
6631 ci.numRunning = numRunning;
6632 //System.out.println(
6633 // "#" + maxNum + ": " + " descr=" + ci.description);
6634 if (ci.thumbnail == null && receiver != null) {
6635 if (localLOGV) Log.v(
6636 TAG, "State=" + top.state + "Idle=" + top.idle
6637 + " app=" + top.app
6638 + " thr=" + (top.app != null ? top.app.thread : null));
6639 if (top.state == ActivityState.RESUMED
6640 || top.state == ActivityState.PAUSING) {
6641 if (top.idle && top.app != null
6642 && top.app.thread != null) {
6643 topRecord = top;
6644 topThumbnail = top.app.thread;
6645 } else {
6646 top.thumbnailNeeded = true;
6647 }
6648 }
6649 if (pending == null) {
6650 pending = new PendingThumbnailsRecord(receiver);
6651 }
6652 pending.pendingRecords.add(top);
6653 }
6654 list.add(ci);
6655 maxNum--;
6656 top = null;
6657 }
6658 }
6659
6660 if (pending != null) {
6661 mPendingThumbnails.add(pending);
6662 }
6663 }
6664
6665 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6666
6667 if (topThumbnail != null) {
6668 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6669 try {
6670 topThumbnail.requestThumbnail(topRecord);
6671 } catch (Exception e) {
6672 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6673 sendPendingThumbnail(null, topRecord, null, null, true);
6674 }
6675 }
6676
6677 if (pending == null && receiver != null) {
6678 // In this case all thumbnails were available and the client
6679 // is being asked to be told when the remaining ones come in...
6680 // which is unusually, since the top-most currently running
6681 // activity should never have a canned thumbnail! Oh well.
6682 try {
6683 receiver.finished();
6684 } catch (RemoteException ex) {
6685 }
6686 }
6687
6688 return list;
6689 }
6690
6691 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6692 int flags) {
6693 synchronized (this) {
6694 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6695 "getRecentTasks()");
6696
6697 final int N = mRecentTasks.size();
6698 ArrayList<ActivityManager.RecentTaskInfo> res
6699 = new ArrayList<ActivityManager.RecentTaskInfo>(
6700 maxNum < N ? maxNum : N);
6701 for (int i=0; i<N && maxNum > 0; i++) {
6702 TaskRecord tr = mRecentTasks.get(i);
6703 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6704 || (tr.intent == null)
6705 || ((tr.intent.getFlags()
6706 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6707 ActivityManager.RecentTaskInfo rti
6708 = new ActivityManager.RecentTaskInfo();
6709 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6710 rti.baseIntent = new Intent(
6711 tr.intent != null ? tr.intent : tr.affinityIntent);
6712 rti.origActivity = tr.origActivity;
6713 res.add(rti);
6714 maxNum--;
6715 }
6716 }
6717 return res;
6718 }
6719 }
6720
6721 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6722 int j;
6723 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6724 TaskRecord jt = startTask;
6725
6726 // First look backwards
6727 for (j=startIndex-1; j>=0; j--) {
6728 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6729 if (r.task != jt) {
6730 jt = r.task;
6731 if (affinity.equals(jt.affinity)) {
6732 return j;
6733 }
6734 }
6735 }
6736
6737 // Now look forwards
6738 final int N = mHistory.size();
6739 jt = startTask;
6740 for (j=startIndex+1; j<N; j++) {
6741 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6742 if (r.task != jt) {
6743 if (affinity.equals(jt.affinity)) {
6744 return j;
6745 }
6746 jt = r.task;
6747 }
6748 }
6749
6750 // Might it be at the top?
6751 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6752 return N-1;
6753 }
6754
6755 return -1;
6756 }
6757
6758 /**
6759 * Perform a reset of the given task, if needed as part of launching it.
6760 * Returns the new HistoryRecord at the top of the task.
6761 */
6762 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6763 HistoryRecord newActivity) {
6764 boolean forceReset = (newActivity.info.flags
6765 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6766 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6767 if ((newActivity.info.flags
6768 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6769 forceReset = true;
6770 }
6771 }
6772
6773 final TaskRecord task = taskTop.task;
6774
6775 // We are going to move through the history list so that we can look
6776 // at each activity 'target' with 'below' either the interesting
6777 // activity immediately below it in the stack or null.
6778 HistoryRecord target = null;
6779 int targetI = 0;
6780 int taskTopI = -1;
6781 int replyChainEnd = -1;
6782 int lastReparentPos = -1;
6783 for (int i=mHistory.size()-1; i>=-1; i--) {
6784 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6785
6786 if (below != null && below.finishing) {
6787 continue;
6788 }
6789 if (target == null) {
6790 target = below;
6791 targetI = i;
6792 // If we were in the middle of a reply chain before this
6793 // task, it doesn't appear like the root of the chain wants
6794 // anything interesting, so drop it.
6795 replyChainEnd = -1;
6796 continue;
6797 }
6798
6799 final int flags = target.info.flags;
6800
6801 final boolean finishOnTaskLaunch =
6802 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6803 final boolean allowTaskReparenting =
6804 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6805
6806 if (target.task == task) {
6807 // We are inside of the task being reset... we'll either
6808 // finish this activity, push it out for another task,
6809 // or leave it as-is. We only do this
6810 // for activities that are not the root of the task (since
6811 // if we finish the root, we may no longer have the task!).
6812 if (taskTopI < 0) {
6813 taskTopI = targetI;
6814 }
6815 if (below != null && below.task == task) {
6816 final boolean clearWhenTaskReset =
6817 (target.intent.getFlags()
6818 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006819 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006820 // If this activity is sending a reply to a previous
6821 // activity, we can't do anything with it now until
6822 // we reach the start of the reply chain.
6823 // XXX note that we are assuming the result is always
6824 // to the previous activity, which is almost always
6825 // the case but we really shouldn't count on.
6826 if (replyChainEnd < 0) {
6827 replyChainEnd = targetI;
6828 }
Ed Heyl73798232009-03-24 21:32:21 -07006829 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006830 && target.taskAffinity != null
6831 && !target.taskAffinity.equals(task.affinity)) {
6832 // If this activity has an affinity for another
6833 // task, then we need to move it out of here. We will
6834 // move it as far out of the way as possible, to the
6835 // bottom of the activity stack. This also keeps it
6836 // correctly ordered with any activities we previously
6837 // moved.
6838 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6839 if (target.taskAffinity != null
6840 && target.taskAffinity.equals(p.task.affinity)) {
6841 // If the activity currently at the bottom has the
6842 // same task affinity as the one we are moving,
6843 // then merge it into the same task.
6844 target.task = p.task;
6845 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6846 + " out to bottom task " + p.task);
6847 } else {
6848 mCurTask++;
6849 if (mCurTask <= 0) {
6850 mCurTask = 1;
6851 }
6852 target.task = new TaskRecord(mCurTask, target.info, null,
6853 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6854 target.task.affinityIntent = target.intent;
6855 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6856 + " out to new task " + target.task);
6857 }
6858 mWindowManager.setAppGroupId(target, task.taskId);
6859 if (replyChainEnd < 0) {
6860 replyChainEnd = targetI;
6861 }
6862 int dstPos = 0;
6863 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6864 p = (HistoryRecord)mHistory.get(srcPos);
6865 if (p.finishing) {
6866 continue;
6867 }
6868 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6869 + " out to target's task " + target.task);
6870 task.numActivities--;
6871 p.task = target.task;
6872 target.task.numActivities++;
6873 mHistory.remove(srcPos);
6874 mHistory.add(dstPos, p);
6875 mWindowManager.moveAppToken(dstPos, p);
6876 mWindowManager.setAppGroupId(p, p.task.taskId);
6877 dstPos++;
6878 if (VALIDATE_TOKENS) {
6879 mWindowManager.validateAppTokens(mHistory);
6880 }
6881 i++;
6882 }
6883 if (taskTop == p) {
6884 taskTop = below;
6885 }
6886 if (taskTopI == replyChainEnd) {
6887 taskTopI = -1;
6888 }
6889 replyChainEnd = -1;
Josh Bartel7f208742010-02-25 11:01:44 -06006890 addRecentTaskLocked(target.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006891 } else if (forceReset || finishOnTaskLaunch
6892 || clearWhenTaskReset) {
6893 // If the activity should just be removed -- either
6894 // because it asks for it, or the task should be
6895 // cleared -- then finish it and anything that is
6896 // part of its reply chain.
6897 if (clearWhenTaskReset) {
6898 // In this case, we want to finish this activity
6899 // and everything above it, so be sneaky and pretend
6900 // like these are all in the reply chain.
6901 replyChainEnd = targetI+1;
6902 while (replyChainEnd < mHistory.size() &&
6903 ((HistoryRecord)mHistory.get(
6904 replyChainEnd)).task == task) {
6905 replyChainEnd++;
6906 }
6907 replyChainEnd--;
6908 } else if (replyChainEnd < 0) {
6909 replyChainEnd = targetI;
6910 }
6911 HistoryRecord p = null;
6912 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6913 p = (HistoryRecord)mHistory.get(srcPos);
6914 if (p.finishing) {
6915 continue;
6916 }
6917 if (finishActivityLocked(p, srcPos,
6918 Activity.RESULT_CANCELED, null, "reset")) {
6919 replyChainEnd--;
6920 srcPos--;
6921 }
6922 }
6923 if (taskTop == p) {
6924 taskTop = below;
6925 }
6926 if (taskTopI == replyChainEnd) {
6927 taskTopI = -1;
6928 }
6929 replyChainEnd = -1;
6930 } else {
6931 // If we were in the middle of a chain, well the
6932 // activity that started it all doesn't want anything
6933 // special, so leave it all as-is.
6934 replyChainEnd = -1;
6935 }
6936 } else {
6937 // Reached the bottom of the task -- any reply chain
6938 // should be left as-is.
6939 replyChainEnd = -1;
6940 }
6941
6942 } else if (target.resultTo != null) {
6943 // If this activity is sending a reply to a previous
6944 // activity, we can't do anything with it now until
6945 // we reach the start of the reply chain.
6946 // XXX note that we are assuming the result is always
6947 // to the previous activity, which is almost always
6948 // the case but we really shouldn't count on.
6949 if (replyChainEnd < 0) {
6950 replyChainEnd = targetI;
6951 }
6952
6953 } else if (taskTopI >= 0 && allowTaskReparenting
6954 && task.affinity != null
6955 && task.affinity.equals(target.taskAffinity)) {
6956 // We are inside of another task... if this activity has
6957 // an affinity for our task, then either remove it if we are
6958 // clearing or move it over to our task. Note that
6959 // we currently punt on the case where we are resetting a
6960 // task that is not at the top but who has activities above
6961 // with an affinity to it... this is really not a normal
6962 // case, and we will need to later pull that task to the front
6963 // and usually at that point we will do the reset and pick
6964 // up those remaining activities. (This only happens if
6965 // someone starts an activity in a new task from an activity
6966 // in a task that is not currently on top.)
6967 if (forceReset || finishOnTaskLaunch) {
6968 if (replyChainEnd < 0) {
6969 replyChainEnd = targetI;
6970 }
6971 HistoryRecord p = null;
6972 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6973 p = (HistoryRecord)mHistory.get(srcPos);
6974 if (p.finishing) {
6975 continue;
6976 }
6977 if (finishActivityLocked(p, srcPos,
6978 Activity.RESULT_CANCELED, null, "reset")) {
6979 taskTopI--;
6980 lastReparentPos--;
6981 replyChainEnd--;
6982 srcPos--;
6983 }
6984 }
6985 replyChainEnd = -1;
6986 } else {
6987 if (replyChainEnd < 0) {
6988 replyChainEnd = targetI;
6989 }
6990 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6991 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6992 if (p.finishing) {
6993 continue;
6994 }
6995 if (lastReparentPos < 0) {
6996 lastReparentPos = taskTopI;
6997 taskTop = p;
6998 } else {
6999 lastReparentPos--;
7000 }
7001 mHistory.remove(srcPos);
7002 p.task.numActivities--;
7003 p.task = task;
7004 mHistory.add(lastReparentPos, p);
7005 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
7006 + " in to resetting task " + task);
7007 task.numActivities++;
7008 mWindowManager.moveAppToken(lastReparentPos, p);
7009 mWindowManager.setAppGroupId(p, p.task.taskId);
7010 if (VALIDATE_TOKENS) {
7011 mWindowManager.validateAppTokens(mHistory);
7012 }
7013 }
7014 replyChainEnd = -1;
7015
7016 // Now we've moved it in to place... but what if this is
7017 // a singleTop activity and we have put it on top of another
7018 // instance of the same activity? Then we drop the instance
7019 // below so it remains singleTop.
7020 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
7021 for (int j=lastReparentPos-1; j>=0; j--) {
7022 HistoryRecord p = (HistoryRecord)mHistory.get(j);
7023 if (p.finishing) {
7024 continue;
7025 }
7026 if (p.intent.getComponent().equals(target.intent.getComponent())) {
7027 if (finishActivityLocked(p, j,
7028 Activity.RESULT_CANCELED, null, "replace")) {
7029 taskTopI--;
7030 lastReparentPos--;
7031 }
7032 }
7033 }
7034 }
7035 }
7036 }
7037
7038 target = below;
7039 targetI = i;
7040 }
7041
7042 return taskTop;
7043 }
7044
7045 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007046 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007047 */
7048 public void moveTaskToFront(int task) {
7049 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7050 "moveTaskToFront()");
7051
7052 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007053 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7054 Binder.getCallingUid(), "Task to front")) {
7055 return;
7056 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007057 final long origId = Binder.clearCallingIdentity();
7058 try {
7059 int N = mRecentTasks.size();
7060 for (int i=0; i<N; i++) {
7061 TaskRecord tr = mRecentTasks.get(i);
7062 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007063 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007064 return;
7065 }
7066 }
7067 for (int i=mHistory.size()-1; i>=0; i--) {
7068 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7069 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007070 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007071 return;
7072 }
7073 }
7074 } finally {
7075 Binder.restoreCallingIdentity(origId);
7076 }
7077 }
7078 }
7079
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007080 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007081 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7082
7083 final int task = tr.taskId;
7084 int top = mHistory.size()-1;
7085
7086 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7087 // nothing to do!
7088 return;
7089 }
7090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007091 ArrayList moved = new ArrayList();
7092
7093 // Applying the affinities may have removed entries from the history,
7094 // so get the size again.
7095 top = mHistory.size()-1;
7096 int pos = top;
7097
7098 // Shift all activities with this task up to the top
7099 // of the stack, keeping them in the same internal order.
7100 while (pos >= 0) {
7101 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7102 if (localLOGV) Log.v(
7103 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7104 boolean first = true;
7105 if (r.task.taskId == task) {
7106 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7107 mHistory.remove(pos);
7108 mHistory.add(top, r);
7109 moved.add(0, r);
7110 top--;
7111 if (first) {
Josh Bartel7f208742010-02-25 11:01:44 -06007112 addRecentTaskLocked(r.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007113 first = false;
7114 }
7115 }
7116 pos--;
7117 }
7118
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007119 if (DEBUG_TRANSITION) Log.v(TAG,
7120 "Prepare to front transition: task=" + tr);
7121 if (reason != null &&
7122 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7123 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7124 HistoryRecord r = topRunningActivityLocked(null);
7125 if (r != null) {
7126 mNoAnimActivities.add(r);
7127 }
7128 } else {
7129 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7130 }
7131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007132 mWindowManager.moveAppTokensToTop(moved);
7133 if (VALIDATE_TOKENS) {
7134 mWindowManager.validateAppTokens(mHistory);
7135 }
7136
Josh Bartel7f208742010-02-25 11:01:44 -06007137 finishTaskMoveLocked(task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007138 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7139 }
7140
Josh Bartel7f208742010-02-25 11:01:44 -06007141 private final void finishTaskMoveLocked(int task) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007142 resumeTopActivityLocked(null);
7143 }
7144
7145 public void moveTaskToBack(int task) {
7146 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7147 "moveTaskToBack()");
7148
7149 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007150 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7151 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7152 Binder.getCallingUid(), "Task to back")) {
7153 return;
7154 }
7155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007156 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007157 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007158 Binder.restoreCallingIdentity(origId);
7159 }
7160 }
7161
7162 /**
7163 * Moves an activity, and all of the other activities within the same task, to the bottom
7164 * of the history stack. The activity's order within the task is unchanged.
7165 *
7166 * @param token A reference to the activity we wish to move
7167 * @param nonRoot If false then this only works if the activity is the root
7168 * of a task; if true it will work for any activity in a task.
7169 * @return Returns true if the move completed, false if not.
7170 */
7171 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7172 synchronized(this) {
7173 final long origId = Binder.clearCallingIdentity();
7174 int taskId = getTaskForActivityLocked(token, !nonRoot);
7175 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007176 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007177 }
7178 Binder.restoreCallingIdentity(origId);
7179 }
7180 return false;
7181 }
7182
7183 /**
7184 * Worker method for rearranging history stack. Implements the function of moving all
7185 * activities for a specific task (gathering them if disjoint) into a single group at the
7186 * bottom of the stack.
7187 *
7188 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7189 * to premeptively cancel the move.
7190 *
7191 * @param task The taskId to collect and move to the bottom.
7192 * @return Returns true if the move completed, false if not.
7193 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007194 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007195 Log.i(TAG, "moveTaskToBack: " + task);
7196
7197 // If we have a watcher, preflight the move before committing to it. First check
7198 // for *other* available tasks, but if none are available, then try again allowing the
7199 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007200 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007201 HistoryRecord next = topRunningActivityLocked(null, task);
7202 if (next == null) {
7203 next = topRunningActivityLocked(null, 0);
7204 }
7205 if (next != null) {
7206 // ask watcher if this is allowed
7207 boolean moveOK = true;
7208 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007209 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007210 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007211 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007212 }
7213 if (!moveOK) {
7214 return false;
7215 }
7216 }
7217 }
7218
7219 ArrayList moved = new ArrayList();
7220
7221 if (DEBUG_TRANSITION) Log.v(TAG,
7222 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007223
7224 final int N = mHistory.size();
7225 int bottom = 0;
7226 int pos = 0;
7227
7228 // Shift all activities with this task down to the bottom
7229 // of the stack, keeping them in the same internal order.
7230 while (pos < N) {
7231 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7232 if (localLOGV) Log.v(
7233 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7234 if (r.task.taskId == task) {
7235 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7236 mHistory.remove(pos);
7237 mHistory.add(bottom, r);
7238 moved.add(r);
7239 bottom++;
7240 }
7241 pos++;
7242 }
7243
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007244 if (reason != null &&
7245 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7246 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7247 HistoryRecord r = topRunningActivityLocked(null);
7248 if (r != null) {
7249 mNoAnimActivities.add(r);
7250 }
7251 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007252 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007254 mWindowManager.moveAppTokensToBottom(moved);
7255 if (VALIDATE_TOKENS) {
7256 mWindowManager.validateAppTokens(mHistory);
7257 }
7258
Josh Bartel7f208742010-02-25 11:01:44 -06007259 finishTaskMoveLocked(task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007260 return true;
7261 }
7262
7263 public void moveTaskBackwards(int task) {
7264 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7265 "moveTaskBackwards()");
7266
7267 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007268 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7269 Binder.getCallingUid(), "Task backwards")) {
7270 return;
7271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007272 final long origId = Binder.clearCallingIdentity();
7273 moveTaskBackwardsLocked(task);
7274 Binder.restoreCallingIdentity(origId);
7275 }
7276 }
7277
7278 private final void moveTaskBackwardsLocked(int task) {
7279 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7280 }
7281
7282 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7283 synchronized(this) {
7284 return getTaskForActivityLocked(token, onlyRoot);
7285 }
7286 }
7287
7288 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7289 final int N = mHistory.size();
7290 TaskRecord lastTask = null;
7291 for (int i=0; i<N; i++) {
7292 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7293 if (r == token) {
7294 if (!onlyRoot || lastTask != r.task) {
7295 return r.task.taskId;
7296 }
7297 return -1;
7298 }
7299 lastTask = r.task;
7300 }
7301
7302 return -1;
7303 }
7304
7305 /**
7306 * Returns the top activity in any existing task matching the given
7307 * Intent. Returns null if no such task is found.
7308 */
7309 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7310 ComponentName cls = intent.getComponent();
7311 if (info.targetActivity != null) {
7312 cls = new ComponentName(info.packageName, info.targetActivity);
7313 }
7314
7315 TaskRecord cp = null;
7316
7317 final int N = mHistory.size();
7318 for (int i=(N-1); i>=0; i--) {
7319 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7320 if (!r.finishing && r.task != cp
7321 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7322 cp = r.task;
7323 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7324 // + "/aff=" + r.task.affinity + " to new cls="
7325 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7326 if (r.task.affinity != null) {
7327 if (r.task.affinity.equals(info.taskAffinity)) {
7328 //Log.i(TAG, "Found matching affinity!");
7329 return r;
7330 }
7331 } else if (r.task.intent != null
7332 && r.task.intent.getComponent().equals(cls)) {
7333 //Log.i(TAG, "Found matching class!");
7334 //dump();
7335 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7336 return r;
7337 } else if (r.task.affinityIntent != null
7338 && r.task.affinityIntent.getComponent().equals(cls)) {
7339 //Log.i(TAG, "Found matching class!");
7340 //dump();
7341 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7342 return r;
7343 }
7344 }
7345 }
7346
7347 return null;
7348 }
7349
7350 /**
7351 * Returns the first activity (starting from the top of the stack) that
7352 * is the same as the given activity. Returns null if no such activity
7353 * is found.
7354 */
7355 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7356 ComponentName cls = intent.getComponent();
7357 if (info.targetActivity != null) {
7358 cls = new ComponentName(info.packageName, info.targetActivity);
7359 }
7360
7361 final int N = mHistory.size();
7362 for (int i=(N-1); i>=0; i--) {
7363 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7364 if (!r.finishing) {
7365 if (r.intent.getComponent().equals(cls)) {
7366 //Log.i(TAG, "Found matching class!");
7367 //dump();
7368 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7369 return r;
7370 }
7371 }
7372 }
7373
7374 return null;
7375 }
7376
7377 public void finishOtherInstances(IBinder token, ComponentName className) {
7378 synchronized(this) {
7379 final long origId = Binder.clearCallingIdentity();
7380
7381 int N = mHistory.size();
7382 TaskRecord lastTask = null;
7383 for (int i=0; i<N; i++) {
7384 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7385 if (r.realActivity.equals(className)
7386 && r != token && lastTask != r.task) {
7387 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7388 null, "others")) {
7389 i--;
7390 N--;
7391 }
7392 }
7393 lastTask = r.task;
7394 }
7395
7396 Binder.restoreCallingIdentity(origId);
7397 }
7398 }
7399
7400 // =========================================================
7401 // THUMBNAILS
7402 // =========================================================
7403
7404 public void reportThumbnail(IBinder token,
7405 Bitmap thumbnail, CharSequence description) {
7406 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7407 final long origId = Binder.clearCallingIdentity();
7408 sendPendingThumbnail(null, token, thumbnail, description, true);
7409 Binder.restoreCallingIdentity(origId);
7410 }
7411
7412 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7413 Bitmap thumbnail, CharSequence description, boolean always) {
7414 TaskRecord task = null;
7415 ArrayList receivers = null;
7416
7417 //System.out.println("Send pending thumbnail: " + r);
7418
7419 synchronized(this) {
7420 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007421 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007422 if (index < 0) {
7423 return;
7424 }
7425 r = (HistoryRecord)mHistory.get(index);
7426 }
7427 if (thumbnail == null) {
7428 thumbnail = r.thumbnail;
7429 description = r.description;
7430 }
7431 if (thumbnail == null && !always) {
7432 // If there is no thumbnail, and this entry is not actually
7433 // going away, then abort for now and pick up the next
7434 // thumbnail we get.
7435 return;
7436 }
7437 task = r.task;
7438
7439 int N = mPendingThumbnails.size();
7440 int i=0;
7441 while (i<N) {
7442 PendingThumbnailsRecord pr =
7443 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7444 //System.out.println("Looking in " + pr.pendingRecords);
7445 if (pr.pendingRecords.remove(r)) {
7446 if (receivers == null) {
7447 receivers = new ArrayList();
7448 }
7449 receivers.add(pr);
7450 if (pr.pendingRecords.size() == 0) {
7451 pr.finished = true;
7452 mPendingThumbnails.remove(i);
7453 N--;
7454 continue;
7455 }
7456 }
7457 i++;
7458 }
7459 }
7460
7461 if (receivers != null) {
7462 final int N = receivers.size();
7463 for (int i=0; i<N; i++) {
7464 try {
7465 PendingThumbnailsRecord pr =
7466 (PendingThumbnailsRecord)receivers.get(i);
7467 pr.receiver.newThumbnail(
7468 task != null ? task.taskId : -1, thumbnail, description);
7469 if (pr.finished) {
7470 pr.receiver.finished();
7471 }
7472 } catch (Exception e) {
7473 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7474 }
7475 }
7476 }
7477 }
7478
7479 // =========================================================
7480 // CONTENT PROVIDERS
7481 // =========================================================
7482
7483 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7484 List providers = null;
7485 try {
7486 providers = ActivityThread.getPackageManager().
7487 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007488 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007489 } catch (RemoteException ex) {
7490 }
7491 if (providers != null) {
7492 final int N = providers.size();
7493 for (int i=0; i<N; i++) {
7494 ProviderInfo cpi =
7495 (ProviderInfo)providers.get(i);
7496 ContentProviderRecord cpr =
7497 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7498 if (cpr == null) {
7499 cpr = new ContentProviderRecord(cpi, app.info);
7500 mProvidersByClass.put(cpi.name, cpr);
7501 }
7502 app.pubProviders.put(cpi.name, cpr);
7503 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007504 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007505 }
7506 }
7507 return providers;
7508 }
7509
7510 private final String checkContentProviderPermissionLocked(
7511 ProviderInfo cpi, ProcessRecord r, int mode) {
7512 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7513 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7514 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7515 cpi.exported ? -1 : cpi.applicationInfo.uid)
7516 == PackageManager.PERMISSION_GRANTED
7517 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7518 return null;
7519 }
7520 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7521 cpi.exported ? -1 : cpi.applicationInfo.uid)
7522 == PackageManager.PERMISSION_GRANTED) {
7523 return null;
7524 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007525
7526 PathPermission[] pps = cpi.pathPermissions;
7527 if (pps != null) {
7528 int i = pps.length;
7529 while (i > 0) {
7530 i--;
7531 PathPermission pp = pps[i];
7532 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7533 cpi.exported ? -1 : cpi.applicationInfo.uid)
7534 == PackageManager.PERMISSION_GRANTED
7535 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7536 return null;
7537 }
7538 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7539 cpi.exported ? -1 : cpi.applicationInfo.uid)
7540 == PackageManager.PERMISSION_GRANTED) {
7541 return null;
7542 }
7543 }
7544 }
7545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007546 String msg = "Permission Denial: opening provider " + cpi.name
7547 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7548 + ", uid=" + callingUid + ") requires "
7549 + cpi.readPermission + " or " + cpi.writePermission;
7550 Log.w(TAG, msg);
7551 return msg;
7552 }
7553
7554 private final ContentProviderHolder getContentProviderImpl(
7555 IApplicationThread caller, String name) {
7556 ContentProviderRecord cpr;
7557 ProviderInfo cpi = null;
7558
7559 synchronized(this) {
7560 ProcessRecord r = null;
7561 if (caller != null) {
7562 r = getRecordForAppLocked(caller);
7563 if (r == null) {
7564 throw new SecurityException(
7565 "Unable to find app for caller " + caller
7566 + " (pid=" + Binder.getCallingPid()
7567 + ") when getting content provider " + name);
7568 }
7569 }
7570
7571 // First check if this content provider has been published...
7572 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7573 if (cpr != null) {
7574 cpi = cpr.info;
7575 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7576 return new ContentProviderHolder(cpi,
7577 cpi.readPermission != null
7578 ? cpi.readPermission : cpi.writePermission);
7579 }
7580
7581 if (r != null && cpr.canRunHere(r)) {
7582 // This provider has been published or is in the process
7583 // of being published... but it is also allowed to run
7584 // in the caller's process, so don't make a connection
7585 // and just let the caller instantiate its own instance.
7586 if (cpr.provider != null) {
7587 // don't give caller the provider object, it needs
7588 // to make its own.
7589 cpr = new ContentProviderRecord(cpr);
7590 }
7591 return cpr;
7592 }
7593
7594 final long origId = Binder.clearCallingIdentity();
7595
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007596 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007597 // return it right away.
7598 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007599 if (DEBUG_PROVIDER) Log.v(TAG,
7600 "Adding provider requested by "
7601 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007602 + cpr.info.processName);
7603 Integer cnt = r.conProviders.get(cpr);
7604 if (cnt == null) {
7605 r.conProviders.put(cpr, new Integer(1));
7606 } else {
7607 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007609 cpr.clients.add(r);
7610 } else {
7611 cpr.externals++;
7612 }
7613
7614 if (cpr.app != null) {
7615 updateOomAdjLocked(cpr.app);
7616 }
7617
7618 Binder.restoreCallingIdentity(origId);
7619
7620 } else {
7621 try {
7622 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007623 resolveContentProvider(name,
7624 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007625 } catch (RemoteException ex) {
7626 }
7627 if (cpi == null) {
7628 return null;
7629 }
7630
7631 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7632 return new ContentProviderHolder(cpi,
7633 cpi.readPermission != null
7634 ? cpi.readPermission : cpi.writePermission);
7635 }
7636
7637 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7638 final boolean firstClass = cpr == null;
7639 if (firstClass) {
7640 try {
7641 ApplicationInfo ai =
7642 ActivityThread.getPackageManager().
7643 getApplicationInfo(
7644 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007645 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007646 if (ai == null) {
7647 Log.w(TAG, "No package info for content provider "
7648 + cpi.name);
7649 return null;
7650 }
7651 cpr = new ContentProviderRecord(cpi, ai);
7652 } catch (RemoteException ex) {
7653 // pm is in same process, this will never happen.
7654 }
7655 }
7656
7657 if (r != null && cpr.canRunHere(r)) {
7658 // If this is a multiprocess provider, then just return its
7659 // info and allow the caller to instantiate it. Only do
7660 // this if the provider is the same user as the caller's
7661 // process, or can run as root (so can be in any process).
7662 return cpr;
7663 }
7664
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007665 if (DEBUG_PROVIDER) {
7666 RuntimeException e = new RuntimeException("here");
7667 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7668 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007669 }
7670
7671 // This is single process, and our app is now connecting to it.
7672 // See if we are already in the process of launching this
7673 // provider.
7674 final int N = mLaunchingProviders.size();
7675 int i;
7676 for (i=0; i<N; i++) {
7677 if (mLaunchingProviders.get(i) == cpr) {
7678 break;
7679 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007680 }
7681
7682 // If the provider is not already being launched, then get it
7683 // started.
7684 if (i >= N) {
7685 final long origId = Binder.clearCallingIdentity();
7686 ProcessRecord proc = startProcessLocked(cpi.processName,
7687 cpr.appInfo, false, 0, "content provider",
7688 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007689 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007690 if (proc == null) {
7691 Log.w(TAG, "Unable to launch app "
7692 + cpi.applicationInfo.packageName + "/"
7693 + cpi.applicationInfo.uid + " for provider "
7694 + name + ": process is bad");
7695 return null;
7696 }
7697 cpr.launchingApp = proc;
7698 mLaunchingProviders.add(cpr);
7699 Binder.restoreCallingIdentity(origId);
7700 }
7701
7702 // Make sure the provider is published (the same provider class
7703 // may be published under multiple names).
7704 if (firstClass) {
7705 mProvidersByClass.put(cpi.name, cpr);
7706 }
7707 mProvidersByName.put(name, cpr);
7708
7709 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007710 if (DEBUG_PROVIDER) Log.v(TAG,
7711 "Adding provider requested by "
7712 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007713 + cpr.info.processName);
7714 Integer cnt = r.conProviders.get(cpr);
7715 if (cnt == null) {
7716 r.conProviders.put(cpr, new Integer(1));
7717 } else {
7718 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007720 cpr.clients.add(r);
7721 } else {
7722 cpr.externals++;
7723 }
7724 }
7725 }
7726
7727 // Wait for the provider to be published...
7728 synchronized (cpr) {
7729 while (cpr.provider == null) {
7730 if (cpr.launchingApp == null) {
7731 Log.w(TAG, "Unable to launch app "
7732 + cpi.applicationInfo.packageName + "/"
7733 + cpi.applicationInfo.uid + " for provider "
7734 + name + ": launching app became null");
7735 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7736 cpi.applicationInfo.packageName,
7737 cpi.applicationInfo.uid, name);
7738 return null;
7739 }
7740 try {
7741 cpr.wait();
7742 } catch (InterruptedException ex) {
7743 }
7744 }
7745 }
7746 return cpr;
7747 }
7748
7749 public final ContentProviderHolder getContentProvider(
7750 IApplicationThread caller, String name) {
7751 if (caller == null) {
7752 String msg = "null IApplicationThread when getting content provider "
7753 + name;
7754 Log.w(TAG, msg);
7755 throw new SecurityException(msg);
7756 }
7757
7758 return getContentProviderImpl(caller, name);
7759 }
7760
7761 private ContentProviderHolder getContentProviderExternal(String name) {
7762 return getContentProviderImpl(null, name);
7763 }
7764
7765 /**
7766 * Drop a content provider from a ProcessRecord's bookkeeping
7767 * @param cpr
7768 */
7769 public void removeContentProvider(IApplicationThread caller, String name) {
7770 synchronized (this) {
7771 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7772 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007773 // remove from mProvidersByClass
7774 if (DEBUG_PROVIDER) Log.v(TAG, name +
7775 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007776 return;
7777 }
7778 final ProcessRecord r = getRecordForAppLocked(caller);
7779 if (r == null) {
7780 throw new SecurityException(
7781 "Unable to find app for caller " + caller +
7782 " when removing content provider " + name);
7783 }
7784 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007785 ContentProviderRecord localCpr = (ContentProviderRecord)
7786 mProvidersByClass.get(cpr.info.name);
7787 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7788 + r.info.processName + " from process "
7789 + localCpr.appInfo.processName);
7790 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007791 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007792 Log.w(TAG, "removeContentProvider called on local provider: "
7793 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007794 return;
7795 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007796 Integer cnt = r.conProviders.get(localCpr);
7797 if (cnt == null || cnt.intValue() <= 1) {
7798 localCpr.clients.remove(r);
7799 r.conProviders.remove(localCpr);
7800 } else {
7801 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7802 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007803 }
7804 updateOomAdjLocked();
7805 }
7806 }
7807
7808 private void removeContentProviderExternal(String name) {
7809 synchronized (this) {
7810 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7811 if(cpr == null) {
7812 //remove from mProvidersByClass
7813 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7814 return;
7815 }
7816
7817 //update content provider record entry info
7818 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7819 localCpr.externals--;
7820 if (localCpr.externals < 0) {
7821 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7822 }
7823 updateOomAdjLocked();
7824 }
7825 }
7826
7827 public final void publishContentProviders(IApplicationThread caller,
7828 List<ContentProviderHolder> providers) {
7829 if (providers == null) {
7830 return;
7831 }
7832
7833 synchronized(this) {
7834 final ProcessRecord r = getRecordForAppLocked(caller);
7835 if (r == null) {
7836 throw new SecurityException(
7837 "Unable to find app for caller " + caller
7838 + " (pid=" + Binder.getCallingPid()
7839 + ") when publishing content providers");
7840 }
7841
7842 final long origId = Binder.clearCallingIdentity();
7843
7844 final int N = providers.size();
7845 for (int i=0; i<N; i++) {
7846 ContentProviderHolder src = providers.get(i);
7847 if (src == null || src.info == null || src.provider == null) {
7848 continue;
7849 }
7850 ContentProviderRecord dst =
7851 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7852 if (dst != null) {
7853 mProvidersByClass.put(dst.info.name, dst);
7854 String names[] = dst.info.authority.split(";");
7855 for (int j = 0; j < names.length; j++) {
7856 mProvidersByName.put(names[j], dst);
7857 }
7858
7859 int NL = mLaunchingProviders.size();
7860 int j;
7861 for (j=0; j<NL; j++) {
7862 if (mLaunchingProviders.get(j) == dst) {
7863 mLaunchingProviders.remove(j);
7864 j--;
7865 NL--;
7866 }
7867 }
7868 synchronized (dst) {
7869 dst.provider = src.provider;
7870 dst.app = r;
7871 dst.notifyAll();
7872 }
7873 updateOomAdjLocked(r);
7874 }
7875 }
7876
7877 Binder.restoreCallingIdentity(origId);
7878 }
7879 }
7880
7881 public static final void installSystemProviders() {
7882 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7883 List providers = mSelf.generateApplicationProvidersLocked(app);
7884 mSystemThread.installSystemProviders(providers);
7885 }
7886
7887 // =========================================================
7888 // GLOBAL MANAGEMENT
7889 // =========================================================
7890
7891 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7892 ApplicationInfo info, String customProcess) {
7893 String proc = customProcess != null ? customProcess : info.processName;
7894 BatteryStatsImpl.Uid.Proc ps = null;
7895 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7896 synchronized (stats) {
7897 ps = stats.getProcessStatsLocked(info.uid, proc);
7898 }
7899 return new ProcessRecord(ps, thread, info, proc);
7900 }
7901
7902 final ProcessRecord addAppLocked(ApplicationInfo info) {
7903 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7904
7905 if (app == null) {
7906 app = newProcessRecordLocked(null, info, null);
7907 mProcessNames.put(info.processName, info.uid, app);
7908 updateLRUListLocked(app, true);
7909 }
7910
7911 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7912 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7913 app.persistent = true;
7914 app.maxAdj = CORE_SERVER_ADJ;
7915 }
7916 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7917 mPersistentStartingProcesses.add(app);
7918 startProcessLocked(app, "added application", app.processName);
7919 }
7920
7921 return app;
7922 }
7923
7924 public void unhandledBack() {
7925 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7926 "unhandledBack()");
7927
7928 synchronized(this) {
7929 int count = mHistory.size();
7930 if (Config.LOGD) Log.d(
7931 TAG, "Performing unhandledBack(): stack size = " + count);
7932 if (count > 1) {
7933 final long origId = Binder.clearCallingIdentity();
7934 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7935 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7936 Binder.restoreCallingIdentity(origId);
7937 }
7938 }
7939 }
7940
7941 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7942 String name = uri.getAuthority();
7943 ContentProviderHolder cph = getContentProviderExternal(name);
7944 ParcelFileDescriptor pfd = null;
7945 if (cph != null) {
7946 // We record the binder invoker's uid in thread-local storage before
7947 // going to the content provider to open the file. Later, in the code
7948 // that handles all permissions checks, we look for this uid and use
7949 // that rather than the Activity Manager's own uid. The effect is that
7950 // we do the check against the caller's permissions even though it looks
7951 // to the content provider like the Activity Manager itself is making
7952 // the request.
7953 sCallerIdentity.set(new Identity(
7954 Binder.getCallingPid(), Binder.getCallingUid()));
7955 try {
7956 pfd = cph.provider.openFile(uri, "r");
7957 } catch (FileNotFoundException e) {
7958 // do nothing; pfd will be returned null
7959 } finally {
7960 // Ensure that whatever happens, we clean up the identity state
7961 sCallerIdentity.remove();
7962 }
7963
7964 // We've got the fd now, so we're done with the provider.
7965 removeContentProviderExternal(name);
7966 } else {
7967 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7968 }
7969 return pfd;
7970 }
7971
7972 public void goingToSleep() {
7973 synchronized(this) {
7974 mSleeping = true;
7975 mWindowManager.setEventDispatching(false);
7976
7977 if (mResumedActivity != null) {
7978 pauseIfSleepingLocked();
7979 } else {
7980 Log.w(TAG, "goingToSleep with no resumed activity!");
7981 }
7982 }
7983 }
7984
Dianne Hackborn55280a92009-05-07 15:53:46 -07007985 public boolean shutdown(int timeout) {
7986 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7987 != PackageManager.PERMISSION_GRANTED) {
7988 throw new SecurityException("Requires permission "
7989 + android.Manifest.permission.SHUTDOWN);
7990 }
7991
7992 boolean timedout = false;
7993
7994 synchronized(this) {
7995 mShuttingDown = true;
7996 mWindowManager.setEventDispatching(false);
7997
7998 if (mResumedActivity != null) {
7999 pauseIfSleepingLocked();
8000 final long endTime = System.currentTimeMillis() + timeout;
8001 while (mResumedActivity != null || mPausingActivity != null) {
8002 long delay = endTime - System.currentTimeMillis();
8003 if (delay <= 0) {
8004 Log.w(TAG, "Activity manager shutdown timed out");
8005 timedout = true;
8006 break;
8007 }
8008 try {
8009 this.wait();
8010 } catch (InterruptedException e) {
8011 }
8012 }
8013 }
8014 }
8015
8016 mUsageStatsService.shutdown();
8017 mBatteryStatsService.shutdown();
8018
8019 return timedout;
8020 }
8021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008022 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07008023 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008024 if (!mGoingToSleep.isHeld()) {
8025 mGoingToSleep.acquire();
8026 if (mLaunchingActivity.isHeld()) {
8027 mLaunchingActivity.release();
8028 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
8029 }
8030 }
8031
8032 // If we are not currently pausing an activity, get the current
8033 // one to pause. If we are pausing one, we will just let that stuff
8034 // run and release the wake lock when all done.
8035 if (mPausingActivity == null) {
8036 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8037 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8038 startPausingLocked(false, true);
8039 }
8040 }
8041 }
8042
8043 public void wakingUp() {
8044 synchronized(this) {
8045 if (mGoingToSleep.isHeld()) {
8046 mGoingToSleep.release();
8047 }
8048 mWindowManager.setEventDispatching(true);
8049 mSleeping = false;
8050 resumeTopActivityLocked(null);
8051 }
8052 }
8053
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008054 public void stopAppSwitches() {
8055 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8056 != PackageManager.PERMISSION_GRANTED) {
8057 throw new SecurityException("Requires permission "
8058 + android.Manifest.permission.STOP_APP_SWITCHES);
8059 }
8060
8061 synchronized(this) {
8062 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8063 + APP_SWITCH_DELAY_TIME;
8064 mDidAppSwitch = false;
8065 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8066 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8067 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8068 }
8069 }
8070
8071 public void resumeAppSwitches() {
8072 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8073 != PackageManager.PERMISSION_GRANTED) {
8074 throw new SecurityException("Requires permission "
8075 + android.Manifest.permission.STOP_APP_SWITCHES);
8076 }
8077
8078 synchronized(this) {
8079 // Note that we don't execute any pending app switches... we will
8080 // let those wait until either the timeout, or the next start
8081 // activity request.
8082 mAppSwitchesAllowedTime = 0;
8083 }
8084 }
8085
8086 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8087 String name) {
8088 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8089 return true;
8090 }
8091
8092 final int perm = checkComponentPermission(
8093 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8094 callingUid, -1);
8095 if (perm == PackageManager.PERMISSION_GRANTED) {
8096 return true;
8097 }
8098
8099 Log.w(TAG, name + " request from " + callingUid + " stopped");
8100 return false;
8101 }
8102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008103 public void setDebugApp(String packageName, boolean waitForDebugger,
8104 boolean persistent) {
8105 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8106 "setDebugApp()");
8107
8108 // Note that this is not really thread safe if there are multiple
8109 // callers into it at the same time, but that's not a situation we
8110 // care about.
8111 if (persistent) {
8112 final ContentResolver resolver = mContext.getContentResolver();
8113 Settings.System.putString(
8114 resolver, Settings.System.DEBUG_APP,
8115 packageName);
8116 Settings.System.putInt(
8117 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8118 waitForDebugger ? 1 : 0);
8119 }
8120
8121 synchronized (this) {
8122 if (!persistent) {
8123 mOrigDebugApp = mDebugApp;
8124 mOrigWaitForDebugger = mWaitForDebugger;
8125 }
8126 mDebugApp = packageName;
8127 mWaitForDebugger = waitForDebugger;
8128 mDebugTransient = !persistent;
8129 if (packageName != null) {
8130 final long origId = Binder.clearCallingIdentity();
8131 uninstallPackageLocked(packageName, -1, false);
8132 Binder.restoreCallingIdentity(origId);
8133 }
8134 }
8135 }
8136
8137 public void setAlwaysFinish(boolean enabled) {
8138 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8139 "setAlwaysFinish()");
8140
8141 Settings.System.putInt(
8142 mContext.getContentResolver(),
8143 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8144
8145 synchronized (this) {
8146 mAlwaysFinishActivities = enabled;
8147 }
8148 }
8149
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008150 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008151 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008152 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008153 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008154 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008155 }
8156 }
8157
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008158 public void registerActivityWatcher(IActivityWatcher watcher) {
8159 mWatchers.register(watcher);
8160 }
8161
8162 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8163 mWatchers.unregister(watcher);
8164 }
8165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008166 public final void enterSafeMode() {
8167 synchronized(this) {
8168 // It only makes sense to do this before the system is ready
8169 // and started launching other packages.
8170 if (!mSystemReady) {
8171 try {
8172 ActivityThread.getPackageManager().enterSafeMode();
8173 } catch (RemoteException e) {
8174 }
8175
8176 View v = LayoutInflater.from(mContext).inflate(
8177 com.android.internal.R.layout.safe_mode, null);
8178 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8179 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8180 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8181 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8182 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8183 lp.format = v.getBackground().getOpacity();
8184 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8185 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8186 ((WindowManager)mContext.getSystemService(
8187 Context.WINDOW_SERVICE)).addView(v, lp);
8188 }
8189 }
8190 }
8191
8192 public void noteWakeupAlarm(IIntentSender sender) {
8193 if (!(sender instanceof PendingIntentRecord)) {
8194 return;
8195 }
8196 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8197 synchronized (stats) {
8198 if (mBatteryStatsService.isOnBattery()) {
8199 mBatteryStatsService.enforceCallingPermission();
8200 PendingIntentRecord rec = (PendingIntentRecord)sender;
8201 int MY_UID = Binder.getCallingUid();
8202 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8203 BatteryStatsImpl.Uid.Pkg pkg =
8204 stats.getPackageStatsLocked(uid, rec.key.packageName);
8205 pkg.incWakeupsLocked();
8206 }
8207 }
8208 }
8209
8210 public boolean killPidsForMemory(int[] pids) {
8211 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8212 throw new SecurityException("killPidsForMemory only available to the system");
8213 }
8214
8215 // XXX Note: don't acquire main activity lock here, because the window
8216 // manager calls in with its locks held.
8217
8218 boolean killed = false;
8219 synchronized (mPidsSelfLocked) {
8220 int[] types = new int[pids.length];
8221 int worstType = 0;
8222 for (int i=0; i<pids.length; i++) {
8223 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8224 if (proc != null) {
8225 int type = proc.setAdj;
8226 types[i] = type;
8227 if (type > worstType) {
8228 worstType = type;
8229 }
8230 }
8231 }
8232
8233 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8234 // then constrain it so we will kill all hidden procs.
8235 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8236 worstType = HIDDEN_APP_MIN_ADJ;
8237 }
8238 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8239 for (int i=0; i<pids.length; i++) {
8240 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8241 if (proc == null) {
8242 continue;
8243 }
8244 int adj = proc.setAdj;
8245 if (adj >= worstType) {
8246 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8247 + adj + ")");
8248 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8249 proc.processName, adj);
8250 killed = true;
8251 Process.killProcess(pids[i]);
8252 }
8253 }
8254 }
8255 return killed;
8256 }
8257
8258 public void reportPss(IApplicationThread caller, int pss) {
8259 Watchdog.PssRequestor req;
8260 String name;
8261 ProcessRecord callerApp;
8262 synchronized (this) {
8263 if (caller == null) {
8264 return;
8265 }
8266 callerApp = getRecordForAppLocked(caller);
8267 if (callerApp == null) {
8268 return;
8269 }
8270 callerApp.lastPss = pss;
8271 req = callerApp;
8272 name = callerApp.processName;
8273 }
8274 Watchdog.getInstance().reportPss(req, name, pss);
8275 if (!callerApp.persistent) {
8276 removeRequestedPss(callerApp);
8277 }
8278 }
8279
8280 public void requestPss(Runnable completeCallback) {
8281 ArrayList<ProcessRecord> procs;
8282 synchronized (this) {
8283 mRequestPssCallback = completeCallback;
8284 mRequestPssList.clear();
8285 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8286 ProcessRecord proc = mLRUProcesses.get(i);
8287 if (!proc.persistent) {
8288 mRequestPssList.add(proc);
8289 }
8290 }
8291 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8292 }
8293
8294 int oldPri = Process.getThreadPriority(Process.myTid());
8295 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8296 for (int i=procs.size()-1; i>=0; i--) {
8297 ProcessRecord proc = procs.get(i);
8298 proc.lastPss = 0;
8299 proc.requestPss();
8300 }
8301 Process.setThreadPriority(oldPri);
8302 }
8303
8304 void removeRequestedPss(ProcessRecord proc) {
8305 Runnable callback = null;
8306 synchronized (this) {
8307 if (mRequestPssList.remove(proc)) {
8308 if (mRequestPssList.size() == 0) {
8309 callback = mRequestPssCallback;
8310 mRequestPssCallback = null;
8311 }
8312 }
8313 }
8314
8315 if (callback != null) {
8316 callback.run();
8317 }
8318 }
8319
8320 public void collectPss(Watchdog.PssStats stats) {
8321 stats.mEmptyPss = 0;
8322 stats.mEmptyCount = 0;
8323 stats.mBackgroundPss = 0;
8324 stats.mBackgroundCount = 0;
8325 stats.mServicePss = 0;
8326 stats.mServiceCount = 0;
8327 stats.mVisiblePss = 0;
8328 stats.mVisibleCount = 0;
8329 stats.mForegroundPss = 0;
8330 stats.mForegroundCount = 0;
8331 stats.mNoPssCount = 0;
8332 synchronized (this) {
8333 int i;
8334 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8335 ? mProcDeaths.length : stats.mProcDeaths.length;
8336 int aggr = 0;
8337 for (i=0; i<NPD; i++) {
8338 aggr += mProcDeaths[i];
8339 stats.mProcDeaths[i] = aggr;
8340 }
8341 while (i<stats.mProcDeaths.length) {
8342 stats.mProcDeaths[i] = 0;
8343 i++;
8344 }
8345
8346 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8347 ProcessRecord proc = mLRUProcesses.get(i);
8348 if (proc.persistent) {
8349 continue;
8350 }
8351 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8352 if (proc.lastPss == 0) {
8353 stats.mNoPssCount++;
8354 continue;
8355 }
8356 if (proc.setAdj == EMPTY_APP_ADJ) {
8357 stats.mEmptyPss += proc.lastPss;
8358 stats.mEmptyCount++;
8359 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8360 stats.mEmptyPss += proc.lastPss;
8361 stats.mEmptyCount++;
8362 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8363 stats.mBackgroundPss += proc.lastPss;
8364 stats.mBackgroundCount++;
8365 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8366 stats.mVisiblePss += proc.lastPss;
8367 stats.mVisibleCount++;
8368 } else {
8369 stats.mForegroundPss += proc.lastPss;
8370 stats.mForegroundCount++;
8371 }
8372 }
8373 }
8374 }
8375
8376 public final void startRunning(String pkg, String cls, String action,
8377 String data) {
8378 synchronized(this) {
8379 if (mStartRunning) {
8380 return;
8381 }
8382 mStartRunning = true;
8383 mTopComponent = pkg != null && cls != null
8384 ? new ComponentName(pkg, cls) : null;
8385 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8386 mTopData = data;
8387 if (!mSystemReady) {
8388 return;
8389 }
8390 }
8391
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008392 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008393 }
8394
8395 private void retrieveSettings() {
8396 final ContentResolver resolver = mContext.getContentResolver();
8397 String debugApp = Settings.System.getString(
8398 resolver, Settings.System.DEBUG_APP);
8399 boolean waitForDebugger = Settings.System.getInt(
8400 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8401 boolean alwaysFinishActivities = Settings.System.getInt(
8402 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8403
8404 Configuration configuration = new Configuration();
8405 Settings.System.getConfiguration(resolver, configuration);
8406
8407 synchronized (this) {
8408 mDebugApp = mOrigDebugApp = debugApp;
8409 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8410 mAlwaysFinishActivities = alwaysFinishActivities;
8411 // This happens before any activities are started, so we can
8412 // change mConfiguration in-place.
8413 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008414 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008415 }
8416 }
8417
8418 public boolean testIsSystemReady() {
8419 // no need to synchronize(this) just to read & return the value
8420 return mSystemReady;
8421 }
8422
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008423 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008424 // In the simulator, startRunning will never have been called, which
8425 // normally sets a few crucial variables. Do it here instead.
8426 if (!Process.supportsProcesses()) {
8427 mStartRunning = true;
8428 mTopAction = Intent.ACTION_MAIN;
8429 }
8430
8431 synchronized(this) {
8432 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008433 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008434 return;
8435 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008436
8437 // Check to see if there are any update receivers to run.
8438 if (!mDidUpdate) {
8439 if (mWaitingUpdate) {
8440 return;
8441 }
8442 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8443 List<ResolveInfo> ris = null;
8444 try {
8445 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8446 intent, null, 0);
8447 } catch (RemoteException e) {
8448 }
8449 if (ris != null) {
8450 for (int i=ris.size()-1; i>=0; i--) {
8451 if ((ris.get(i).activityInfo.applicationInfo.flags
8452 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8453 ris.remove(i);
8454 }
8455 }
8456 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8457 for (int i=0; i<ris.size(); i++) {
8458 ActivityInfo ai = ris.get(i).activityInfo;
8459 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8460 IIntentReceiver finisher = null;
8461 if (i == 0) {
8462 finisher = new IIntentReceiver.Stub() {
8463 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008464 String data, Bundle extras, boolean ordered,
8465 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008466 throws RemoteException {
8467 synchronized (ActivityManagerService.this) {
8468 mDidUpdate = true;
8469 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008470 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008471 }
8472 };
8473 }
8474 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8475 broadcastIntentLocked(null, null, intent, null, finisher,
8476 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8477 if (i == 0) {
8478 mWaitingUpdate = true;
8479 }
8480 }
8481 }
8482 if (mWaitingUpdate) {
8483 return;
8484 }
8485 mDidUpdate = true;
8486 }
8487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008488 mSystemReady = true;
8489 if (!mStartRunning) {
8490 return;
8491 }
8492 }
8493
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008494 ArrayList<ProcessRecord> procsToKill = null;
8495 synchronized(mPidsSelfLocked) {
8496 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8497 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8498 if (!isAllowedWhileBooting(proc.info)){
8499 if (procsToKill == null) {
8500 procsToKill = new ArrayList<ProcessRecord>();
8501 }
8502 procsToKill.add(proc);
8503 }
8504 }
8505 }
8506
8507 if (procsToKill != null) {
8508 synchronized(this) {
8509 for (int i=procsToKill.size()-1; i>=0; i--) {
8510 ProcessRecord proc = procsToKill.get(i);
8511 Log.i(TAG, "Removing system update proc: " + proc);
8512 removeProcessLocked(proc, true);
8513 }
8514 }
8515 }
8516
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008517 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008518 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8519 SystemClock.uptimeMillis());
8520
8521 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008522 // Make sure we have no pre-ready processes sitting around.
8523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008524 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8525 ResolveInfo ri = mContext.getPackageManager()
8526 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008527 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008528 CharSequence errorMsg = null;
8529 if (ri != null) {
8530 ActivityInfo ai = ri.activityInfo;
8531 ApplicationInfo app = ai.applicationInfo;
8532 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8533 mTopAction = Intent.ACTION_FACTORY_TEST;
8534 mTopData = null;
8535 mTopComponent = new ComponentName(app.packageName,
8536 ai.name);
8537 } else {
8538 errorMsg = mContext.getResources().getText(
8539 com.android.internal.R.string.factorytest_not_system);
8540 }
8541 } else {
8542 errorMsg = mContext.getResources().getText(
8543 com.android.internal.R.string.factorytest_no_action);
8544 }
8545 if (errorMsg != null) {
8546 mTopAction = null;
8547 mTopData = null;
8548 mTopComponent = null;
8549 Message msg = Message.obtain();
8550 msg.what = SHOW_FACTORY_ERROR_MSG;
8551 msg.getData().putCharSequence("msg", errorMsg);
8552 mHandler.sendMessage(msg);
8553 }
8554 }
8555 }
8556
8557 retrieveSettings();
8558
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008559 if (goingCallback != null) goingCallback.run();
8560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008561 synchronized (this) {
8562 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8563 try {
8564 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008565 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008566 if (apps != null) {
8567 int N = apps.size();
8568 int i;
8569 for (i=0; i<N; i++) {
8570 ApplicationInfo info
8571 = (ApplicationInfo)apps.get(i);
8572 if (info != null &&
8573 !info.packageName.equals("android")) {
8574 addAppLocked(info);
8575 }
8576 }
8577 }
8578 } catch (RemoteException ex) {
8579 // pm is in same process, this will never happen.
8580 }
8581 }
8582
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008583 // Start up initial activity.
8584 mBooting = true;
8585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008586 try {
8587 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8588 Message msg = Message.obtain();
8589 msg.what = SHOW_UID_ERROR_MSG;
8590 mHandler.sendMessage(msg);
8591 }
8592 } catch (RemoteException e) {
8593 }
8594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008595 resumeTopActivityLocked(null);
8596 }
8597 }
8598
8599 boolean makeAppCrashingLocked(ProcessRecord app,
8600 String tag, String shortMsg, String longMsg, byte[] crashData) {
8601 app.crashing = true;
8602 app.crashingReport = generateProcessError(app,
8603 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8604 startAppProblemLocked(app);
8605 app.stopFreezingAllLocked();
8606 return handleAppCrashLocked(app);
8607 }
8608
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008609 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008610 // check if error reporting is enabled in Gservices
8611 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8612 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8613 if (enabled == 0) {
8614 return null;
8615 }
8616
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008617 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008618
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008619 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008620 // look for receiver in the installer package
8621 String candidate = pm.getInstallerPackageName(app.info.packageName);
8622 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8623 if (result != null) {
8624 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008625 }
8626
Jacek Surazski82a73df2009-06-17 14:33:18 +02008627 // if the error app is on the system image, look for system apps
8628 // error receiver
8629 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8630 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8631 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8632 if (result != null) {
8633 return result;
8634 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008635 }
8636
Jacek Surazski82a73df2009-06-17 14:33:18 +02008637 // if there is a default receiver, try that
8638 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8639 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008640 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008641 // should not happen
8642 Log.e(TAG, "error talking to PackageManager", e);
8643 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008644 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008645 }
8646
8647 /**
8648 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8649 *
8650 * @param pm PackageManager isntance
8651 * @param errorPackage package which caused the error
8652 * @param receiverPackage candidate package to receive the error
8653 * @return activity component within receiverPackage which handles
8654 * ACTION_APP_ERROR, or null if not found
8655 */
8656 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8657 String receiverPackage) throws RemoteException {
8658 if (receiverPackage == null || receiverPackage.length() == 0) {
8659 return null;
8660 }
8661
8662 // break the loop if it's the error report receiver package that crashed
8663 if (receiverPackage.equals(errorPackage)) {
8664 return null;
8665 }
8666
8667 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8668 intent.setPackage(receiverPackage);
8669 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8670 if (info == null || info.activityInfo == null) {
8671 return null;
8672 }
8673 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008674 }
8675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008676 void makeAppNotRespondingLocked(ProcessRecord app,
8677 String tag, String shortMsg, String longMsg, byte[] crashData) {
8678 app.notResponding = true;
8679 app.notRespondingReport = generateProcessError(app,
8680 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8681 crashData);
8682 startAppProblemLocked(app);
8683 app.stopFreezingAllLocked();
8684 }
8685
8686 /**
8687 * Generate a process error record, suitable for attachment to a ProcessRecord.
8688 *
8689 * @param app The ProcessRecord in which the error occurred.
8690 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8691 * ActivityManager.AppErrorStateInfo
8692 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8693 * @param shortMsg Short message describing the crash.
8694 * @param longMsg Long message describing the crash.
8695 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8696 *
8697 * @return Returns a fully-formed AppErrorStateInfo record.
8698 */
8699 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8700 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8701 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8702
8703 report.condition = condition;
8704 report.processName = app.processName;
8705 report.pid = app.pid;
8706 report.uid = app.info.uid;
8707 report.tag = tag;
8708 report.shortMsg = shortMsg;
8709 report.longMsg = longMsg;
8710 report.crashData = crashData;
8711
8712 return report;
8713 }
8714
8715 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8716 boolean crashed) {
8717 synchronized (this) {
8718 app.crashing = false;
8719 app.crashingReport = null;
8720 app.notResponding = false;
8721 app.notRespondingReport = null;
8722 if (app.anrDialog == fromDialog) {
8723 app.anrDialog = null;
8724 }
8725 if (app.waitDialog == fromDialog) {
8726 app.waitDialog = null;
8727 }
8728 if (app.pid > 0 && app.pid != MY_PID) {
8729 if (crashed) {
8730 handleAppCrashLocked(app);
8731 }
8732 Log.i(ActivityManagerService.TAG, "Killing process "
8733 + app.processName
8734 + " (pid=" + app.pid + ") at user's request");
8735 Process.killProcess(app.pid);
8736 }
8737
8738 }
8739 }
8740
8741 boolean handleAppCrashLocked(ProcessRecord app) {
8742 long now = SystemClock.uptimeMillis();
8743
8744 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8745 app.info.uid);
8746 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8747 // This process loses!
8748 Log.w(TAG, "Process " + app.info.processName
8749 + " has crashed too many times: killing!");
8750 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8751 app.info.processName, app.info.uid);
8752 killServicesLocked(app, false);
8753 for (int i=mHistory.size()-1; i>=0; i--) {
8754 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8755 if (r.app == app) {
8756 if (Config.LOGD) Log.d(
8757 TAG, " Force finishing activity "
8758 + r.intent.getComponent().flattenToShortString());
8759 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8760 }
8761 }
8762 if (!app.persistent) {
8763 // We don't want to start this process again until the user
8764 // explicitly does so... but for persistent process, we really
8765 // need to keep it running. If a persistent process is actually
8766 // repeatedly crashing, then badness for everyone.
8767 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8768 app.info.processName);
8769 mBadProcesses.put(app.info.processName, app.info.uid, now);
8770 app.bad = true;
8771 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8772 app.removed = true;
8773 removeProcessLocked(app, false);
8774 return false;
8775 }
8776 }
8777
8778 // Bump up the crash count of any services currently running in the proc.
8779 if (app.services.size() != 0) {
8780 // Any services running in the application need to be placed
8781 // back in the pending list.
8782 Iterator it = app.services.iterator();
8783 while (it.hasNext()) {
8784 ServiceRecord sr = (ServiceRecord)it.next();
8785 sr.crashCount++;
8786 }
8787 }
8788
8789 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8790 return true;
8791 }
8792
8793 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008794 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008795 skipCurrentReceiverLocked(app);
8796 }
8797
8798 void skipCurrentReceiverLocked(ProcessRecord app) {
8799 boolean reschedule = false;
8800 BroadcastRecord r = app.curReceiver;
8801 if (r != null) {
8802 // The current broadcast is waiting for this app's receiver
8803 // to be finished. Looks like that's not going to happen, so
8804 // let the broadcast continue.
8805 logBroadcastReceiverDiscard(r);
8806 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8807 r.resultExtras, r.resultAbort, true);
8808 reschedule = true;
8809 }
8810 r = mPendingBroadcast;
8811 if (r != null && r.curApp == app) {
8812 if (DEBUG_BROADCAST) Log.v(TAG,
8813 "skip & discard pending app " + r);
8814 logBroadcastReceiverDiscard(r);
8815 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8816 r.resultExtras, r.resultAbort, true);
8817 reschedule = true;
8818 }
8819 if (reschedule) {
8820 scheduleBroadcastsLocked();
8821 }
8822 }
8823
8824 public int handleApplicationError(IBinder app, int flags,
8825 String tag, String shortMsg, String longMsg, byte[] crashData) {
8826 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008827 ProcessRecord r = null;
8828 synchronized (this) {
8829 if (app != null) {
8830 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8831 final int NA = apps.size();
8832 for (int ia=0; ia<NA; ia++) {
8833 ProcessRecord p = apps.valueAt(ia);
8834 if (p.thread != null && p.thread.asBinder() == app) {
8835 r = p;
8836 break;
8837 }
8838 }
8839 }
8840 }
8841
8842 if (r != null) {
8843 // The application has crashed. Send the SIGQUIT to the process so
8844 // that it can dump its state.
8845 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8846 //Log.i(TAG, "Current system threads:");
8847 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8848 }
8849
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008850 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008851 try {
8852 String name = r != null ? r.processName : null;
8853 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008854 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008855 shortMsg, longMsg, crashData)) {
8856 Log.w(TAG, "Force-killing crashed app " + name
8857 + " at watcher's request");
8858 Process.killProcess(pid);
8859 return 0;
8860 }
8861 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008862 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008863 }
8864 }
8865
8866 final long origId = Binder.clearCallingIdentity();
8867
8868 // If this process is running instrumentation, finish it.
8869 if (r != null && r.instrumentationClass != null) {
8870 Log.w(TAG, "Error in app " + r.processName
8871 + " running instrumentation " + r.instrumentationClass + ":");
8872 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8873 if (longMsg != null) Log.w(TAG, " " + longMsg);
8874 Bundle info = new Bundle();
8875 info.putString("shortMsg", shortMsg);
8876 info.putString("longMsg", longMsg);
8877 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8878 Binder.restoreCallingIdentity(origId);
8879 return 0;
8880 }
8881
8882 if (r != null) {
8883 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8884 return 0;
8885 }
8886 } else {
8887 Log.w(TAG, "Some application object " + app + " tag " + tag
8888 + " has crashed, but I don't know who it is.");
8889 Log.w(TAG, "ShortMsg:" + shortMsg);
8890 Log.w(TAG, "LongMsg:" + longMsg);
8891 Binder.restoreCallingIdentity(origId);
8892 return 0;
8893 }
8894
8895 Message msg = Message.obtain();
8896 msg.what = SHOW_ERROR_MSG;
8897 HashMap data = new HashMap();
8898 data.put("result", result);
8899 data.put("app", r);
8900 data.put("flags", flags);
8901 data.put("shortMsg", shortMsg);
8902 data.put("longMsg", longMsg);
8903 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8904 // For system processes, submit crash data to the server.
8905 data.put("crashData", crashData);
8906 }
8907 msg.obj = data;
8908 mHandler.sendMessage(msg);
8909
8910 Binder.restoreCallingIdentity(origId);
8911 }
8912
8913 int res = result.get();
8914
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008915 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008916 synchronized (this) {
8917 if (r != null) {
8918 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8919 SystemClock.uptimeMillis());
8920 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008921 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8922 appErrorIntent = createAppErrorIntentLocked(r);
8923 res = AppErrorDialog.FORCE_QUIT;
8924 }
8925 }
8926
8927 if (appErrorIntent != null) {
8928 try {
8929 mContext.startActivity(appErrorIntent);
8930 } catch (ActivityNotFoundException e) {
8931 Log.w(TAG, "bug report receiver dissappeared", e);
8932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008933 }
8934
8935 return res;
8936 }
8937
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008938 Intent createAppErrorIntentLocked(ProcessRecord r) {
8939 ApplicationErrorReport report = createAppErrorReportLocked(r);
8940 if (report == null) {
8941 return null;
8942 }
8943 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8944 result.setComponent(r.errorReportReceiver);
8945 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8946 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8947 return result;
8948 }
8949
8950 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8951 if (r.errorReportReceiver == null) {
8952 return null;
8953 }
8954
8955 if (!r.crashing && !r.notResponding) {
8956 return null;
8957 }
8958
8959 try {
8960 ApplicationErrorReport report = new ApplicationErrorReport();
8961 report.packageName = r.info.packageName;
8962 report.installerPackageName = r.errorReportReceiver.getPackageName();
8963 report.processName = r.processName;
8964
8965 if (r.crashing) {
8966 report.type = ApplicationErrorReport.TYPE_CRASH;
8967 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8968
8969 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8970 r.crashingReport.crashData);
8971 DataInputStream dataStream = new DataInputStream(byteStream);
8972 CrashData crashData = new CrashData(dataStream);
8973 ThrowableData throwData = crashData.getThrowableData();
8974
8975 report.time = crashData.getTime();
8976 report.crashInfo.stackTrace = throwData.toString();
8977
Jacek Surazskif829a782009-06-11 22:47:02 +02008978 // Extract the source of the exception, useful for report
8979 // clustering. Also extract the "deepest" non-null exception
8980 // message.
8981 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008982 while (throwData.getCause() != null) {
8983 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008984 String msg = throwData.getMessage();
8985 if (msg != null && msg.length() > 0) {
8986 exceptionMessage = msg;
8987 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008988 }
8989 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008990 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008991 report.crashInfo.exceptionClassName = throwData.getType();
8992 report.crashInfo.throwFileName = trace.getFileName();
8993 report.crashInfo.throwClassName = trace.getClassName();
8994 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008995 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008996 } else if (r.notResponding) {
8997 report.type = ApplicationErrorReport.TYPE_ANR;
8998 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8999
9000 report.anrInfo.activity = r.notRespondingReport.tag;
9001 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9002 report.anrInfo.info = r.notRespondingReport.longMsg;
9003 }
9004
9005 return report;
9006 } catch (IOException e) {
9007 // we don't send it
9008 }
9009
9010 return null;
9011 }
9012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009013 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9014 // assume our apps are happy - lazy create the list
9015 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9016
9017 synchronized (this) {
9018
9019 // iterate across all processes
9020 final int N = mLRUProcesses.size();
9021 for (int i = 0; i < N; i++) {
9022 ProcessRecord app = mLRUProcesses.get(i);
9023 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9024 // This one's in trouble, so we'll generate a report for it
9025 // crashes are higher priority (in case there's a crash *and* an anr)
9026 ActivityManager.ProcessErrorStateInfo report = null;
9027 if (app.crashing) {
9028 report = app.crashingReport;
9029 } else if (app.notResponding) {
9030 report = app.notRespondingReport;
9031 }
9032
9033 if (report != null) {
9034 if (errList == null) {
9035 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9036 }
9037 errList.add(report);
9038 } else {
9039 Log.w(TAG, "Missing app error report, app = " + app.processName +
9040 " crashing = " + app.crashing +
9041 " notResponding = " + app.notResponding);
9042 }
9043 }
9044 }
9045 }
9046
9047 return errList;
9048 }
9049
9050 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9051 // Lazy instantiation of list
9052 List<ActivityManager.RunningAppProcessInfo> runList = null;
9053 synchronized (this) {
9054 // Iterate across all processes
9055 final int N = mLRUProcesses.size();
9056 for (int i = 0; i < N; i++) {
9057 ProcessRecord app = mLRUProcesses.get(i);
9058 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9059 // Generate process state info for running application
9060 ActivityManager.RunningAppProcessInfo currApp =
9061 new ActivityManager.RunningAppProcessInfo(app.processName,
9062 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009063 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009064 int adj = app.curAdj;
9065 if (adj >= CONTENT_PROVIDER_ADJ) {
9066 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9067 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9068 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009069 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9070 } else if (adj >= HOME_APP_ADJ) {
9071 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9072 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009073 } else if (adj >= SECONDARY_SERVER_ADJ) {
9074 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9075 } else if (adj >= VISIBLE_APP_ADJ) {
9076 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9077 } else {
9078 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9079 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009080 currApp.importanceReasonCode = app.adjTypeCode;
9081 if (app.adjSource instanceof ProcessRecord) {
9082 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9083 } else if (app.adjSource instanceof HistoryRecord) {
9084 HistoryRecord r = (HistoryRecord)app.adjSource;
9085 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9086 }
9087 if (app.adjTarget instanceof ComponentName) {
9088 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9089 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009090 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9091 // + " lru=" + currApp.lru);
9092 if (runList == null) {
9093 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9094 }
9095 runList.add(currApp);
9096 }
9097 }
9098 }
9099 return runList;
9100 }
9101
9102 @Override
9103 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9104 synchronized (this) {
9105 if (checkCallingPermission(android.Manifest.permission.DUMP)
9106 != PackageManager.PERMISSION_GRANTED) {
9107 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9108 + Binder.getCallingPid()
9109 + ", uid=" + Binder.getCallingUid()
9110 + " without permission "
9111 + android.Manifest.permission.DUMP);
9112 return;
9113 }
9114 if (args.length != 0 && "service".equals(args[0])) {
9115 dumpService(fd, pw, args);
9116 return;
9117 }
9118 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009119 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009120 pw.println(" ");
9121 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009122 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009123 if (mWaitingVisibleActivities.size() > 0) {
9124 pw.println(" ");
9125 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009126 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009127 }
9128 if (mStoppingActivities.size() > 0) {
9129 pw.println(" ");
9130 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009131 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009132 }
9133 if (mFinishingActivities.size() > 0) {
9134 pw.println(" ");
9135 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009136 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009137 }
9138
9139 pw.println(" ");
9140 pw.println(" mPausingActivity: " + mPausingActivity);
9141 pw.println(" mResumedActivity: " + mResumedActivity);
9142 pw.println(" mFocusedActivity: " + mFocusedActivity);
9143 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9144
9145 if (mRecentTasks.size() > 0) {
9146 pw.println(" ");
9147 pw.println("Recent tasks in Current Activity Manager State:");
9148
9149 final int N = mRecentTasks.size();
9150 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009151 TaskRecord tr = mRecentTasks.get(i);
9152 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9153 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009154 mRecentTasks.get(i).dump(pw, " ");
9155 }
9156 }
9157
9158 pw.println(" ");
9159 pw.println(" mCurTask: " + mCurTask);
9160
9161 pw.println(" ");
9162 pw.println("Processes in Current Activity Manager State:");
9163
9164 boolean needSep = false;
9165 int numPers = 0;
9166
9167 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9168 final int NA = procs.size();
9169 for (int ia=0; ia<NA; ia++) {
9170 if (!needSep) {
9171 pw.println(" All known processes:");
9172 needSep = true;
9173 }
9174 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009175 pw.print(r.persistent ? " *PERS*" : " *APP*");
9176 pw.print(" UID "); pw.print(procs.keyAt(ia));
9177 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009178 r.dump(pw, " ");
9179 if (r.persistent) {
9180 numPers++;
9181 }
9182 }
9183 }
9184
9185 if (mLRUProcesses.size() > 0) {
9186 if (needSep) pw.println(" ");
9187 needSep = true;
9188 pw.println(" Running processes (most recent first):");
9189 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009190 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009191 needSep = true;
9192 }
9193
9194 synchronized (mPidsSelfLocked) {
9195 if (mPidsSelfLocked.size() > 0) {
9196 if (needSep) pw.println(" ");
9197 needSep = true;
9198 pw.println(" PID mappings:");
9199 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009200 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9201 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009202 }
9203 }
9204 }
9205
9206 if (mForegroundProcesses.size() > 0) {
9207 if (needSep) pw.println(" ");
9208 needSep = true;
9209 pw.println(" Foreground Processes:");
9210 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009211 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9212 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009213 }
9214 }
9215
9216 if (mPersistentStartingProcesses.size() > 0) {
9217 if (needSep) pw.println(" ");
9218 needSep = true;
9219 pw.println(" Persisent processes that are starting:");
9220 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009221 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009222 }
9223
9224 if (mStartingProcesses.size() > 0) {
9225 if (needSep) pw.println(" ");
9226 needSep = true;
9227 pw.println(" Processes that are starting:");
9228 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009229 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009230 }
9231
9232 if (mRemovedProcesses.size() > 0) {
9233 if (needSep) pw.println(" ");
9234 needSep = true;
9235 pw.println(" Processes that are being removed:");
9236 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009237 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009238 }
9239
9240 if (mProcessesOnHold.size() > 0) {
9241 if (needSep) pw.println(" ");
9242 needSep = true;
9243 pw.println(" Processes that are on old until the system is ready:");
9244 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009245 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009246 }
9247
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009248 if (mProcessesToGc.size() > 0) {
9249 if (needSep) pw.println(" ");
9250 needSep = true;
9251 pw.println(" Processes that are waiting to GC:");
9252 long now = SystemClock.uptimeMillis();
9253 for (int i=0; i<mProcessesToGc.size(); i++) {
9254 ProcessRecord proc = mProcessesToGc.get(i);
9255 pw.print(" Process "); pw.println(proc);
9256 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9257 pw.print(", last gced=");
9258 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009259 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009260 pw.print(now-proc.lastLowMemory);
9261 pw.println(" ms ago");
9262
9263 }
9264 }
9265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009266 if (mProcessCrashTimes.getMap().size() > 0) {
9267 if (needSep) pw.println(" ");
9268 needSep = true;
9269 pw.println(" Time since processes crashed:");
9270 long now = SystemClock.uptimeMillis();
9271 for (Map.Entry<String, SparseArray<Long>> procs
9272 : mProcessCrashTimes.getMap().entrySet()) {
9273 SparseArray<Long> uids = procs.getValue();
9274 final int N = uids.size();
9275 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009276 pw.print(" Process "); pw.print(procs.getKey());
9277 pw.print(" uid "); pw.print(uids.keyAt(i));
9278 pw.print(": last crashed ");
9279 pw.print((now-uids.valueAt(i)));
9280 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009281 }
9282 }
9283 }
9284
9285 if (mBadProcesses.getMap().size() > 0) {
9286 if (needSep) pw.println(" ");
9287 needSep = true;
9288 pw.println(" Bad processes:");
9289 for (Map.Entry<String, SparseArray<Long>> procs
9290 : mBadProcesses.getMap().entrySet()) {
9291 SparseArray<Long> uids = procs.getValue();
9292 final int N = uids.size();
9293 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009294 pw.print(" Bad process "); pw.print(procs.getKey());
9295 pw.print(" uid "); pw.print(uids.keyAt(i));
9296 pw.print(": crashed at time ");
9297 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009298 }
9299 }
9300 }
9301
9302 pw.println(" ");
9303 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009304 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009305 pw.println(" mConfiguration: " + mConfiguration);
9306 pw.println(" mStartRunning=" + mStartRunning
9307 + " mSystemReady=" + mSystemReady
9308 + " mBooting=" + mBooting
9309 + " mBooted=" + mBooted
9310 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009311 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009312 pw.println(" mGoingToSleep=" + mGoingToSleep);
9313 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9314 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9315 + " mDebugTransient=" + mDebugTransient
9316 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9317 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009318 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009319 }
9320 }
9321
9322 /**
9323 * There are three ways to call this:
9324 * - no service specified: dump all the services
9325 * - a flattened component name that matched an existing service was specified as the
9326 * first arg: dump that one service
9327 * - the first arg isn't the flattened component name of an existing service:
9328 * dump all services whose component contains the first arg as a substring
9329 */
9330 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9331 String[] newArgs;
9332 String componentNameString;
9333 ServiceRecord r;
9334 if (args.length == 1) {
9335 componentNameString = null;
9336 newArgs = EMPTY_STRING_ARRAY;
9337 r = null;
9338 } else {
9339 componentNameString = args[1];
9340 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9341 r = componentName != null ? mServices.get(componentName) : null;
9342 newArgs = new String[args.length - 2];
9343 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9344 }
9345
9346 if (r != null) {
9347 dumpService(fd, pw, r, newArgs);
9348 } else {
9349 for (ServiceRecord r1 : mServices.values()) {
9350 if (componentNameString == null
9351 || r1.name.flattenToString().contains(componentNameString)) {
9352 dumpService(fd, pw, r1, newArgs);
9353 }
9354 }
9355 }
9356 }
9357
9358 /**
9359 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9360 * there is a thread associated with the service.
9361 */
9362 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9363 pw.println(" Service " + r.name.flattenToString());
9364 if (r.app != null && r.app.thread != null) {
9365 try {
9366 // flush anything that is already in the PrintWriter since the thread is going
9367 // to write to the file descriptor directly
9368 pw.flush();
9369 r.app.thread.dumpService(fd, r, args);
9370 pw.print("\n");
9371 } catch (RemoteException e) {
9372 pw.println("got a RemoteException while dumping the service");
9373 }
9374 }
9375 }
9376
9377 void dumpBroadcasts(PrintWriter pw) {
9378 synchronized (this) {
9379 if (checkCallingPermission(android.Manifest.permission.DUMP)
9380 != PackageManager.PERMISSION_GRANTED) {
9381 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9382 + Binder.getCallingPid()
9383 + ", uid=" + Binder.getCallingUid()
9384 + " without permission "
9385 + android.Manifest.permission.DUMP);
9386 return;
9387 }
9388 pw.println("Broadcasts in Current Activity Manager State:");
9389
9390 if (mRegisteredReceivers.size() > 0) {
9391 pw.println(" ");
9392 pw.println(" Registered Receivers:");
9393 Iterator it = mRegisteredReceivers.values().iterator();
9394 while (it.hasNext()) {
9395 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009396 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009397 r.dump(pw, " ");
9398 }
9399 }
9400
9401 pw.println(" ");
9402 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009403 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009404
9405 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9406 || mPendingBroadcast != null) {
9407 if (mParallelBroadcasts.size() > 0) {
9408 pw.println(" ");
9409 pw.println(" Active broadcasts:");
9410 }
9411 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9412 pw.println(" Broadcast #" + i + ":");
9413 mParallelBroadcasts.get(i).dump(pw, " ");
9414 }
9415 if (mOrderedBroadcasts.size() > 0) {
9416 pw.println(" ");
9417 pw.println(" Active serialized broadcasts:");
9418 }
9419 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9420 pw.println(" Serialized Broadcast #" + i + ":");
9421 mOrderedBroadcasts.get(i).dump(pw, " ");
9422 }
9423 pw.println(" ");
9424 pw.println(" Pending broadcast:");
9425 if (mPendingBroadcast != null) {
9426 mPendingBroadcast.dump(pw, " ");
9427 } else {
9428 pw.println(" (null)");
9429 }
9430 }
9431
9432 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009433 pw.println(" Historical broadcasts:");
9434 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9435 BroadcastRecord r = mBroadcastHistory[i];
9436 if (r == null) {
9437 break;
9438 }
9439 pw.println(" Historical Broadcast #" + i + ":");
9440 r.dump(pw, " ");
9441 }
9442
9443 pw.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009444 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9445 if (mStickyBroadcasts != null) {
9446 pw.println(" ");
9447 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009448 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009449 for (Map.Entry<String, ArrayList<Intent>> ent
9450 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009451 pw.print(" * Sticky action "); pw.print(ent.getKey());
9452 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009453 ArrayList<Intent> intents = ent.getValue();
9454 final int N = intents.size();
9455 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009456 sb.setLength(0);
9457 sb.append(" Intent: ");
9458 intents.get(i).toShortString(sb, true, false);
9459 pw.println(sb.toString());
9460 Bundle bundle = intents.get(i).getExtras();
9461 if (bundle != null) {
9462 pw.print(" ");
9463 pw.println(bundle.toString());
9464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009465 }
9466 }
9467 }
9468
9469 pw.println(" ");
9470 pw.println(" mHandler:");
9471 mHandler.dump(new PrintWriterPrinter(pw), " ");
9472 }
9473 }
9474
9475 void dumpServices(PrintWriter pw) {
9476 synchronized (this) {
9477 if (checkCallingPermission(android.Manifest.permission.DUMP)
9478 != PackageManager.PERMISSION_GRANTED) {
9479 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9480 + Binder.getCallingPid()
9481 + ", uid=" + Binder.getCallingUid()
9482 + " without permission "
9483 + android.Manifest.permission.DUMP);
9484 return;
9485 }
9486 pw.println("Services in Current Activity Manager State:");
9487
9488 boolean needSep = false;
9489
9490 if (mServices.size() > 0) {
9491 pw.println(" Active services:");
9492 Iterator<ServiceRecord> it = mServices.values().iterator();
9493 while (it.hasNext()) {
9494 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009495 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009496 r.dump(pw, " ");
9497 }
9498 needSep = true;
9499 }
9500
9501 if (mPendingServices.size() > 0) {
9502 if (needSep) pw.println(" ");
9503 pw.println(" Pending services:");
9504 for (int i=0; i<mPendingServices.size(); i++) {
9505 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009506 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009507 r.dump(pw, " ");
9508 }
9509 needSep = true;
9510 }
9511
9512 if (mRestartingServices.size() > 0) {
9513 if (needSep) pw.println(" ");
9514 pw.println(" Restarting services:");
9515 for (int i=0; i<mRestartingServices.size(); i++) {
9516 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009517 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009518 r.dump(pw, " ");
9519 }
9520 needSep = true;
9521 }
9522
9523 if (mStoppingServices.size() > 0) {
9524 if (needSep) pw.println(" ");
9525 pw.println(" Stopping services:");
9526 for (int i=0; i<mStoppingServices.size(); i++) {
9527 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009528 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009529 r.dump(pw, " ");
9530 }
9531 needSep = true;
9532 }
9533
9534 if (mServiceConnections.size() > 0) {
9535 if (needSep) pw.println(" ");
9536 pw.println(" Connection bindings to services:");
9537 Iterator<ConnectionRecord> it
9538 = mServiceConnections.values().iterator();
9539 while (it.hasNext()) {
9540 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009541 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009542 r.dump(pw, " ");
9543 }
9544 }
9545 }
9546 }
9547
9548 void dumpProviders(PrintWriter pw) {
9549 synchronized (this) {
9550 if (checkCallingPermission(android.Manifest.permission.DUMP)
9551 != PackageManager.PERMISSION_GRANTED) {
9552 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9553 + Binder.getCallingPid()
9554 + ", uid=" + Binder.getCallingUid()
9555 + " without permission "
9556 + android.Manifest.permission.DUMP);
9557 return;
9558 }
9559
9560 pw.println("Content Providers in Current Activity Manager State:");
9561
9562 boolean needSep = false;
9563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009564 if (mProvidersByClass.size() > 0) {
9565 if (needSep) pw.println(" ");
9566 pw.println(" Published content providers (by class):");
9567 Iterator it = mProvidersByClass.entrySet().iterator();
9568 while (it.hasNext()) {
9569 Map.Entry e = (Map.Entry)it.next();
9570 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009571 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009572 r.dump(pw, " ");
9573 }
9574 needSep = true;
9575 }
9576
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009577 if (mProvidersByName.size() > 0) {
9578 pw.println(" ");
9579 pw.println(" Authority to provider mappings:");
9580 Iterator it = mProvidersByName.entrySet().iterator();
9581 while (it.hasNext()) {
9582 Map.Entry e = (Map.Entry)it.next();
9583 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9584 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9585 pw.println(r);
9586 }
9587 needSep = true;
9588 }
9589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009590 if (mLaunchingProviders.size() > 0) {
9591 if (needSep) pw.println(" ");
9592 pw.println(" Launching content providers:");
9593 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009594 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9595 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009596 }
9597 needSep = true;
9598 }
9599
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009600 if (mGrantedUriPermissions.size() > 0) {
9601 pw.println();
9602 pw.println("Granted Uri Permissions:");
9603 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9604 int uid = mGrantedUriPermissions.keyAt(i);
9605 HashMap<Uri, UriPermission> perms
9606 = mGrantedUriPermissions.valueAt(i);
9607 pw.print(" * UID "); pw.print(uid);
9608 pw.println(" holds:");
9609 for (UriPermission perm : perms.values()) {
9610 pw.print(" "); pw.println(perm);
9611 perm.dump(pw, " ");
9612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009613 }
9614 }
9615 }
9616 }
9617
9618 void dumpSenders(PrintWriter pw) {
9619 synchronized (this) {
9620 if (checkCallingPermission(android.Manifest.permission.DUMP)
9621 != PackageManager.PERMISSION_GRANTED) {
9622 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9623 + Binder.getCallingPid()
9624 + ", uid=" + Binder.getCallingUid()
9625 + " without permission "
9626 + android.Manifest.permission.DUMP);
9627 return;
9628 }
9629
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009630 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009631
9632 if (this.mIntentSenderRecords.size() > 0) {
9633 Iterator<WeakReference<PendingIntentRecord>> it
9634 = mIntentSenderRecords.values().iterator();
9635 while (it.hasNext()) {
9636 WeakReference<PendingIntentRecord> ref = it.next();
9637 PendingIntentRecord rec = ref != null ? ref.get(): null;
9638 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009639 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009640 rec.dump(pw, " ");
9641 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009642 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009643 }
9644 }
9645 }
9646 }
9647 }
9648
9649 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009650 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009651 TaskRecord lastTask = null;
9652 for (int i=list.size()-1; i>=0; i--) {
9653 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009654 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009655 if (lastTask != r.task) {
9656 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009657 pw.print(prefix);
9658 pw.print(full ? "* " : " ");
9659 pw.println(lastTask);
9660 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009661 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009663 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009664 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9665 pw.print(" #"); pw.print(i); pw.print(": ");
9666 pw.println(r);
9667 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009668 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009669 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009670 }
9671 }
9672
9673 private static final int dumpProcessList(PrintWriter pw, List list,
9674 String prefix, String normalLabel, String persistentLabel,
9675 boolean inclOomAdj) {
9676 int numPers = 0;
9677 for (int i=list.size()-1; i>=0; i--) {
9678 ProcessRecord r = (ProcessRecord)list.get(i);
9679 if (false) {
9680 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9681 + " #" + i + ":");
9682 r.dump(pw, prefix + " ");
9683 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009684 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009685 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009686 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9687 if (r.adjSource != null || r.adjTarget != null) {
9688 pw.println(prefix + " " + r.adjTarget
9689 + " used by " + r.adjSource);
9690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009691 } else {
9692 pw.println(String.format("%s%s #%2d: %s",
9693 prefix, (r.persistent ? persistentLabel : normalLabel),
9694 i, r.toString()));
9695 }
9696 if (r.persistent) {
9697 numPers++;
9698 }
9699 }
9700 return numPers;
9701 }
9702
9703 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9704 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009705 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009706 long uptime = SystemClock.uptimeMillis();
9707 long realtime = SystemClock.elapsedRealtime();
9708
9709 if (isCheckinRequest) {
9710 // short checkin version
9711 pw.println(uptime + "," + realtime);
9712 pw.flush();
9713 } else {
9714 pw.println("Applications Memory Usage (kB):");
9715 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9716 }
9717 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9718 ProcessRecord r = (ProcessRecord)list.get(i);
9719 if (r.thread != null) {
9720 if (!isCheckinRequest) {
9721 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9722 pw.flush();
9723 }
9724 try {
9725 r.thread.asBinder().dump(fd, args);
9726 } catch (RemoteException e) {
9727 if (!isCheckinRequest) {
9728 pw.println("Got RemoteException!");
9729 pw.flush();
9730 }
9731 }
9732 }
9733 }
9734 }
9735
9736 /**
9737 * Searches array of arguments for the specified string
9738 * @param args array of argument strings
9739 * @param value value to search for
9740 * @return true if the value is contained in the array
9741 */
9742 private static boolean scanArgs(String[] args, String value) {
9743 if (args != null) {
9744 for (String arg : args) {
9745 if (value.equals(arg)) {
9746 return true;
9747 }
9748 }
9749 }
9750 return false;
9751 }
9752
Dianne Hackborn75b03852009-06-12 15:43:26 -07009753 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009754 int count = mHistory.size();
9755
9756 // convert the token to an entry in the history.
9757 HistoryRecord r = null;
9758 int index = -1;
9759 for (int i=count-1; i>=0; i--) {
9760 Object o = mHistory.get(i);
9761 if (o == token) {
9762 r = (HistoryRecord)o;
9763 index = i;
9764 break;
9765 }
9766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009767
9768 return index;
9769 }
9770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009771 private final void killServicesLocked(ProcessRecord app,
9772 boolean allowRestart) {
9773 // Report disconnected services.
9774 if (false) {
9775 // XXX we are letting the client link to the service for
9776 // death notifications.
9777 if (app.services.size() > 0) {
9778 Iterator it = app.services.iterator();
9779 while (it.hasNext()) {
9780 ServiceRecord r = (ServiceRecord)it.next();
9781 if (r.connections.size() > 0) {
9782 Iterator<ConnectionRecord> jt
9783 = r.connections.values().iterator();
9784 while (jt.hasNext()) {
9785 ConnectionRecord c = jt.next();
9786 if (c.binding.client != app) {
9787 try {
9788 //c.conn.connected(r.className, null);
9789 } catch (Exception e) {
9790 // todo: this should be asynchronous!
9791 Log.w(TAG, "Exception thrown disconnected servce "
9792 + r.shortName
9793 + " from app " + app.processName, e);
9794 }
9795 }
9796 }
9797 }
9798 }
9799 }
9800 }
9801
9802 // Clean up any connections this application has to other services.
9803 if (app.connections.size() > 0) {
9804 Iterator<ConnectionRecord> it = app.connections.iterator();
9805 while (it.hasNext()) {
9806 ConnectionRecord r = it.next();
9807 removeConnectionLocked(r, app, null);
9808 }
9809 }
9810 app.connections.clear();
9811
9812 if (app.services.size() != 0) {
9813 // Any services running in the application need to be placed
9814 // back in the pending list.
9815 Iterator it = app.services.iterator();
9816 while (it.hasNext()) {
9817 ServiceRecord sr = (ServiceRecord)it.next();
9818 synchronized (sr.stats.getBatteryStats()) {
9819 sr.stats.stopLaunchedLocked();
9820 }
9821 sr.app = null;
9822 sr.executeNesting = 0;
9823 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009824
9825 boolean hasClients = sr.bindings.size() > 0;
9826 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009827 Iterator<IntentBindRecord> bindings
9828 = sr.bindings.values().iterator();
9829 while (bindings.hasNext()) {
9830 IntentBindRecord b = bindings.next();
9831 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9832 + ": shouldUnbind=" + b.hasBound);
9833 b.binder = null;
9834 b.requested = b.received = b.hasBound = false;
9835 }
9836 }
9837
9838 if (sr.crashCount >= 2) {
9839 Log.w(TAG, "Service crashed " + sr.crashCount
9840 + " times, stopping: " + sr);
9841 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9842 sr.crashCount, sr.shortName, app.pid);
9843 bringDownServiceLocked(sr, true);
9844 } else if (!allowRestart) {
9845 bringDownServiceLocked(sr, true);
9846 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009847 boolean canceled = scheduleServiceRestartLocked(sr, true);
9848
9849 // Should the service remain running? Note that in the
9850 // extreme case of so many attempts to deliver a command
9851 // that it failed, that we also will stop it here.
9852 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9853 if (sr.pendingStarts.size() == 0) {
9854 sr.startRequested = false;
9855 if (!hasClients) {
9856 // Whoops, no reason to restart!
9857 bringDownServiceLocked(sr, true);
9858 }
9859 }
9860 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009861 }
9862 }
9863
9864 if (!allowRestart) {
9865 app.services.clear();
9866 }
9867 }
9868
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009869 // Make sure we have no more records on the stopping list.
9870 int i = mStoppingServices.size();
9871 while (i > 0) {
9872 i--;
9873 ServiceRecord sr = mStoppingServices.get(i);
9874 if (sr.app == app) {
9875 mStoppingServices.remove(i);
9876 }
9877 }
9878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009879 app.executingServices.clear();
9880 }
9881
9882 private final void removeDyingProviderLocked(ProcessRecord proc,
9883 ContentProviderRecord cpr) {
9884 synchronized (cpr) {
9885 cpr.launchingApp = null;
9886 cpr.notifyAll();
9887 }
9888
9889 mProvidersByClass.remove(cpr.info.name);
9890 String names[] = cpr.info.authority.split(";");
9891 for (int j = 0; j < names.length; j++) {
9892 mProvidersByName.remove(names[j]);
9893 }
9894
9895 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9896 while (cit.hasNext()) {
9897 ProcessRecord capp = cit.next();
9898 if (!capp.persistent && capp.thread != null
9899 && capp.pid != 0
9900 && capp.pid != MY_PID) {
9901 Log.i(TAG, "Killing app " + capp.processName
9902 + " (pid " + capp.pid
9903 + ") because provider " + cpr.info.name
9904 + " is in dying process " + proc.processName);
9905 Process.killProcess(capp.pid);
9906 }
9907 }
9908
9909 mLaunchingProviders.remove(cpr);
9910 }
9911
9912 /**
9913 * Main code for cleaning up a process when it has gone away. This is
9914 * called both as a result of the process dying, or directly when stopping
9915 * a process when running in single process mode.
9916 */
9917 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9918 boolean restarting, int index) {
9919 if (index >= 0) {
9920 mLRUProcesses.remove(index);
9921 }
9922
Dianne Hackborn36124872009-10-08 16:22:03 -07009923 mProcessesToGc.remove(app);
9924
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009925 // Dismiss any open dialogs.
9926 if (app.crashDialog != null) {
9927 app.crashDialog.dismiss();
9928 app.crashDialog = null;
9929 }
9930 if (app.anrDialog != null) {
9931 app.anrDialog.dismiss();
9932 app.anrDialog = null;
9933 }
9934 if (app.waitDialog != null) {
9935 app.waitDialog.dismiss();
9936 app.waitDialog = null;
9937 }
9938
9939 app.crashing = false;
9940 app.notResponding = false;
9941
9942 app.resetPackageList();
9943 app.thread = null;
9944 app.forcingToForeground = null;
9945 app.foregroundServices = false;
9946
9947 killServicesLocked(app, true);
9948
9949 boolean restart = false;
9950
9951 int NL = mLaunchingProviders.size();
9952
9953 // Remove published content providers.
9954 if (!app.pubProviders.isEmpty()) {
9955 Iterator it = app.pubProviders.values().iterator();
9956 while (it.hasNext()) {
9957 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9958 cpr.provider = null;
9959 cpr.app = null;
9960
9961 // See if someone is waiting for this provider... in which
9962 // case we don't remove it, but just let it restart.
9963 int i = 0;
9964 if (!app.bad) {
9965 for (; i<NL; i++) {
9966 if (mLaunchingProviders.get(i) == cpr) {
9967 restart = true;
9968 break;
9969 }
9970 }
9971 } else {
9972 i = NL;
9973 }
9974
9975 if (i >= NL) {
9976 removeDyingProviderLocked(app, cpr);
9977 NL = mLaunchingProviders.size();
9978 }
9979 }
9980 app.pubProviders.clear();
9981 }
9982
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009983 // Take care of any launching providers waiting for this process.
9984 if (checkAppInLaunchingProvidersLocked(app, false)) {
9985 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009986 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009988 // Unregister from connected content providers.
9989 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07009990 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009991 while (it.hasNext()) {
9992 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9993 cpr.clients.remove(app);
9994 }
9995 app.conProviders.clear();
9996 }
9997
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009998 // At this point there may be remaining entries in mLaunchingProviders
9999 // where we were the only one waiting, so they are no longer of use.
10000 // Look for these and clean up if found.
10001 // XXX Commented out for now. Trying to figure out a way to reproduce
10002 // the actual situation to identify what is actually going on.
10003 if (false) {
10004 for (int i=0; i<NL; i++) {
10005 ContentProviderRecord cpr = (ContentProviderRecord)
10006 mLaunchingProviders.get(i);
10007 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10008 synchronized (cpr) {
10009 cpr.launchingApp = null;
10010 cpr.notifyAll();
10011 }
10012 }
10013 }
10014 }
10015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010016 skipCurrentReceiverLocked(app);
10017
10018 // Unregister any receivers.
10019 if (app.receivers.size() > 0) {
10020 Iterator<ReceiverList> it = app.receivers.iterator();
10021 while (it.hasNext()) {
10022 removeReceiverLocked(it.next());
10023 }
10024 app.receivers.clear();
10025 }
10026
Christopher Tate181fafa2009-05-14 11:12:14 -070010027 // If the app is undergoing backup, tell the backup manager about it
10028 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10029 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10030 try {
10031 IBackupManager bm = IBackupManager.Stub.asInterface(
10032 ServiceManager.getService(Context.BACKUP_SERVICE));
10033 bm.agentDisconnected(app.info.packageName);
10034 } catch (RemoteException e) {
10035 // can't happen; backup manager is local
10036 }
10037 }
10038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010039 // If the caller is restarting this app, then leave it in its
10040 // current lists and let the caller take care of it.
10041 if (restarting) {
10042 return;
10043 }
10044
10045 if (!app.persistent) {
10046 if (DEBUG_PROCESSES) Log.v(TAG,
10047 "Removing non-persistent process during cleanup: " + app);
10048 mProcessNames.remove(app.processName, app.info.uid);
10049 } else if (!app.removed) {
10050 // This app is persistent, so we need to keep its record around.
10051 // If it is not already on the pending app list, add it there
10052 // and start a new process for it.
10053 app.thread = null;
10054 app.forcingToForeground = null;
10055 app.foregroundServices = false;
10056 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10057 mPersistentStartingProcesses.add(app);
10058 restart = true;
10059 }
10060 }
10061 mProcessesOnHold.remove(app);
10062
The Android Open Source Project4df24232009-03-05 14:34:35 -080010063 if (app == mHomeProcess) {
10064 mHomeProcess = null;
10065 }
10066
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010067 if (restart) {
10068 // We have components that still need to be running in the
10069 // process, so re-launch it.
10070 mProcessNames.put(app.processName, app.info.uid, app);
10071 startProcessLocked(app, "restart", app.processName);
10072 } else if (app.pid > 0 && app.pid != MY_PID) {
10073 // Goodbye!
10074 synchronized (mPidsSelfLocked) {
10075 mPidsSelfLocked.remove(app.pid);
10076 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10077 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010078 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010079 }
10080 }
10081
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010082 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10083 // Look through the content providers we are waiting to have launched,
10084 // and if any run in this process then either schedule a restart of
10085 // the process or kill the client waiting for it if this process has
10086 // gone bad.
10087 int NL = mLaunchingProviders.size();
10088 boolean restart = false;
10089 for (int i=0; i<NL; i++) {
10090 ContentProviderRecord cpr = (ContentProviderRecord)
10091 mLaunchingProviders.get(i);
10092 if (cpr.launchingApp == app) {
10093 if (!alwaysBad && !app.bad) {
10094 restart = true;
10095 } else {
10096 removeDyingProviderLocked(app, cpr);
10097 NL = mLaunchingProviders.size();
10098 }
10099 }
10100 }
10101 return restart;
10102 }
10103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010104 // =========================================================
10105 // SERVICES
10106 // =========================================================
10107
10108 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10109 ActivityManager.RunningServiceInfo info =
10110 new ActivityManager.RunningServiceInfo();
10111 info.service = r.name;
10112 if (r.app != null) {
10113 info.pid = r.app.pid;
10114 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010115 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010116 info.process = r.processName;
10117 info.foreground = r.isForeground;
10118 info.activeSince = r.createTime;
10119 info.started = r.startRequested;
10120 info.clientCount = r.connections.size();
10121 info.crashCount = r.crashCount;
10122 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010123 if (r.isForeground) {
10124 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10125 }
10126 if (r.startRequested) {
10127 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10128 }
10129 if (r.app != null && r.app.pid == Process.myPid()) {
10130 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10131 }
10132 if (r.app != null && r.app.persistent) {
10133 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10134 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010135 for (ConnectionRecord conn : r.connections.values()) {
10136 if (conn.clientLabel != 0) {
10137 info.clientPackage = conn.binding.client.info.packageName;
10138 info.clientLabel = conn.clientLabel;
10139 break;
10140 }
10141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010142 return info;
10143 }
10144
10145 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10146 int flags) {
10147 synchronized (this) {
10148 ArrayList<ActivityManager.RunningServiceInfo> res
10149 = new ArrayList<ActivityManager.RunningServiceInfo>();
10150
10151 if (mServices.size() > 0) {
10152 Iterator<ServiceRecord> it = mServices.values().iterator();
10153 while (it.hasNext() && res.size() < maxNum) {
10154 res.add(makeRunningServiceInfoLocked(it.next()));
10155 }
10156 }
10157
10158 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10159 ServiceRecord r = mRestartingServices.get(i);
10160 ActivityManager.RunningServiceInfo info =
10161 makeRunningServiceInfoLocked(r);
10162 info.restarting = r.nextRestartTime;
10163 res.add(info);
10164 }
10165
10166 return res;
10167 }
10168 }
10169
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010170 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10171 synchronized (this) {
10172 ServiceRecord r = mServices.get(name);
10173 if (r != null) {
10174 for (ConnectionRecord conn : r.connections.values()) {
10175 if (conn.clientIntent != null) {
10176 return conn.clientIntent;
10177 }
10178 }
10179 }
10180 }
10181 return null;
10182 }
10183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010184 private final ServiceRecord findServiceLocked(ComponentName name,
10185 IBinder token) {
10186 ServiceRecord r = mServices.get(name);
10187 return r == token ? r : null;
10188 }
10189
10190 private final class ServiceLookupResult {
10191 final ServiceRecord record;
10192 final String permission;
10193
10194 ServiceLookupResult(ServiceRecord _record, String _permission) {
10195 record = _record;
10196 permission = _permission;
10197 }
10198 };
10199
10200 private ServiceLookupResult findServiceLocked(Intent service,
10201 String resolvedType) {
10202 ServiceRecord r = null;
10203 if (service.getComponent() != null) {
10204 r = mServices.get(service.getComponent());
10205 }
10206 if (r == null) {
10207 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10208 r = mServicesByIntent.get(filter);
10209 }
10210
10211 if (r == null) {
10212 try {
10213 ResolveInfo rInfo =
10214 ActivityThread.getPackageManager().resolveService(
10215 service, resolvedType, 0);
10216 ServiceInfo sInfo =
10217 rInfo != null ? rInfo.serviceInfo : null;
10218 if (sInfo == null) {
10219 return null;
10220 }
10221
10222 ComponentName name = new ComponentName(
10223 sInfo.applicationInfo.packageName, sInfo.name);
10224 r = mServices.get(name);
10225 } catch (RemoteException ex) {
10226 // pm is in same process, this will never happen.
10227 }
10228 }
10229 if (r != null) {
10230 int callingPid = Binder.getCallingPid();
10231 int callingUid = Binder.getCallingUid();
10232 if (checkComponentPermission(r.permission,
10233 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10234 != PackageManager.PERMISSION_GRANTED) {
10235 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10236 + " from pid=" + callingPid
10237 + ", uid=" + callingUid
10238 + " requires " + r.permission);
10239 return new ServiceLookupResult(null, r.permission);
10240 }
10241 return new ServiceLookupResult(r, null);
10242 }
10243 return null;
10244 }
10245
10246 private class ServiceRestarter implements Runnable {
10247 private ServiceRecord mService;
10248
10249 void setService(ServiceRecord service) {
10250 mService = service;
10251 }
10252
10253 public void run() {
10254 synchronized(ActivityManagerService.this) {
10255 performServiceRestartLocked(mService);
10256 }
10257 }
10258 }
10259
10260 private ServiceLookupResult retrieveServiceLocked(Intent service,
10261 String resolvedType, int callingPid, int callingUid) {
10262 ServiceRecord r = null;
10263 if (service.getComponent() != null) {
10264 r = mServices.get(service.getComponent());
10265 }
10266 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10267 r = mServicesByIntent.get(filter);
10268 if (r == null) {
10269 try {
10270 ResolveInfo rInfo =
10271 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010272 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010273 ServiceInfo sInfo =
10274 rInfo != null ? rInfo.serviceInfo : null;
10275 if (sInfo == null) {
10276 Log.w(TAG, "Unable to start service " + service +
10277 ": not found");
10278 return null;
10279 }
10280
10281 ComponentName name = new ComponentName(
10282 sInfo.applicationInfo.packageName, sInfo.name);
10283 r = mServices.get(name);
10284 if (r == null) {
10285 filter = new Intent.FilterComparison(service.cloneFilter());
10286 ServiceRestarter res = new ServiceRestarter();
10287 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10288 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10289 synchronized (stats) {
10290 ss = stats.getServiceStatsLocked(
10291 sInfo.applicationInfo.uid, sInfo.packageName,
10292 sInfo.name);
10293 }
Dianne Hackbornb1c4a2a2010-01-19 15:36:42 -080010294 r = new ServiceRecord(this, ss, name, filter, sInfo, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010295 res.setService(r);
10296 mServices.put(name, r);
10297 mServicesByIntent.put(filter, r);
10298
10299 // Make sure this component isn't in the pending list.
10300 int N = mPendingServices.size();
10301 for (int i=0; i<N; i++) {
10302 ServiceRecord pr = mPendingServices.get(i);
10303 if (pr.name.equals(name)) {
10304 mPendingServices.remove(i);
10305 i--;
10306 N--;
10307 }
10308 }
10309 }
10310 } catch (RemoteException ex) {
10311 // pm is in same process, this will never happen.
10312 }
10313 }
10314 if (r != null) {
10315 if (checkComponentPermission(r.permission,
10316 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10317 != PackageManager.PERMISSION_GRANTED) {
10318 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10319 + " from pid=" + Binder.getCallingPid()
10320 + ", uid=" + Binder.getCallingUid()
10321 + " requires " + r.permission);
10322 return new ServiceLookupResult(null, r.permission);
10323 }
10324 return new ServiceLookupResult(r, null);
10325 }
10326 return null;
10327 }
10328
10329 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10330 long now = SystemClock.uptimeMillis();
10331 if (r.executeNesting == 0 && r.app != null) {
10332 if (r.app.executingServices.size() == 0) {
10333 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10334 msg.obj = r.app;
10335 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10336 }
10337 r.app.executingServices.add(r);
10338 }
10339 r.executeNesting++;
10340 r.executingStart = now;
10341 }
10342
10343 private final void sendServiceArgsLocked(ServiceRecord r,
10344 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010345 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010346 if (N == 0) {
10347 return;
10348 }
10349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010350 int i = 0;
10351 while (i < N) {
10352 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010353 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010354 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010355 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010356 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010357 // If somehow we got a dummy start at the front, then
10358 // just drop it here.
10359 i++;
10360 continue;
10361 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010362 bumpServiceExecutingLocked(r);
10363 if (!oomAdjusted) {
10364 oomAdjusted = true;
10365 updateOomAdjLocked(r.app);
10366 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010367 int flags = 0;
10368 if (si.deliveryCount > 0) {
10369 flags |= Service.START_FLAG_RETRY;
10370 }
10371 if (si.doneExecutingCount > 0) {
10372 flags |= Service.START_FLAG_REDELIVERY;
10373 }
10374 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10375 si.deliveredTime = SystemClock.uptimeMillis();
10376 r.deliveredStarts.add(si);
10377 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010378 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010379 } catch (RemoteException e) {
10380 // Remote process gone... we'll let the normal cleanup take
10381 // care of this.
10382 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010383 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010384 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010385 break;
10386 }
10387 }
10388 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010389 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010390 } else {
10391 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010392 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010393 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010394 }
10395 }
10396 }
10397
10398 private final boolean requestServiceBindingLocked(ServiceRecord r,
10399 IntentBindRecord i, boolean rebind) {
10400 if (r.app == null || r.app.thread == null) {
10401 // If service is not currently running, can't yet bind.
10402 return false;
10403 }
10404 if ((!i.requested || rebind) && i.apps.size() > 0) {
10405 try {
10406 bumpServiceExecutingLocked(r);
10407 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10408 + ": shouldUnbind=" + i.hasBound);
10409 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10410 if (!rebind) {
10411 i.requested = true;
10412 }
10413 i.hasBound = true;
10414 i.doRebind = false;
10415 } catch (RemoteException e) {
10416 return false;
10417 }
10418 }
10419 return true;
10420 }
10421
10422 private final void requestServiceBindingsLocked(ServiceRecord r) {
10423 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10424 while (bindings.hasNext()) {
10425 IntentBindRecord i = bindings.next();
10426 if (!requestServiceBindingLocked(r, i, false)) {
10427 break;
10428 }
10429 }
10430 }
10431
10432 private final void realStartServiceLocked(ServiceRecord r,
10433 ProcessRecord app) throws RemoteException {
10434 if (app.thread == null) {
10435 throw new RemoteException();
10436 }
10437
10438 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010439 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010440
10441 app.services.add(r);
10442 bumpServiceExecutingLocked(r);
10443 updateLRUListLocked(app, true);
10444
10445 boolean created = false;
10446 try {
10447 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10448 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010449 mStringBuilder.setLength(0);
10450 r.intent.getIntent().toShortString(mStringBuilder, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010451 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10452 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010453 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010454 synchronized (r.stats.getBatteryStats()) {
10455 r.stats.startLaunchedLocked();
10456 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010457 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010458 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010459 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010460 created = true;
10461 } finally {
10462 if (!created) {
10463 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010464 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010465 }
10466 }
10467
10468 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010469
10470 // If the service is in the started state, and there are no
10471 // pending arguments, then fake up one so its onStartCommand() will
10472 // be called.
10473 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10474 r.lastStartId++;
10475 if (r.lastStartId < 1) {
10476 r.lastStartId = 1;
10477 }
10478 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10479 }
10480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010481 sendServiceArgsLocked(r, true);
10482 }
10483
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010484 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10485 boolean allowCancel) {
10486 boolean canceled = false;
10487
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010488 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010489 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010490 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010491
10492 // Any delivered but not yet finished starts should be put back
10493 // on the pending list.
10494 final int N = r.deliveredStarts.size();
10495 if (N > 0) {
10496 for (int i=N-1; i>=0; i--) {
10497 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10498 if (si.intent == null) {
10499 // We'll generate this again if needed.
10500 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10501 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10502 r.pendingStarts.add(0, si);
10503 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10504 dur *= 2;
10505 if (minDuration < dur) minDuration = dur;
10506 if (resetTime < dur) resetTime = dur;
10507 } else {
10508 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10509 + r.name);
10510 canceled = true;
10511 }
10512 }
10513 r.deliveredStarts.clear();
10514 }
10515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010516 r.totalRestartCount++;
10517 if (r.restartDelay == 0) {
10518 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010519 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010520 } else {
10521 // If it has been a "reasonably long time" since the service
10522 // was started, then reset our restart duration back to
10523 // the beginning, so we don't infinitely increase the duration
10524 // on a service that just occasionally gets killed (which is
10525 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010526 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010527 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010528 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010529 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010530 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010531 if (r.restartDelay < minDuration) {
10532 r.restartDelay = minDuration;
10533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010534 }
10535 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010536
10537 r.nextRestartTime = now + r.restartDelay;
10538
10539 // Make sure that we don't end up restarting a bunch of services
10540 // all at the same time.
10541 boolean repeat;
10542 do {
10543 repeat = false;
10544 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10545 ServiceRecord r2 = mRestartingServices.get(i);
10546 if (r2 != r && r.nextRestartTime
10547 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10548 && r.nextRestartTime
10549 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10550 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10551 r.restartDelay = r.nextRestartTime - now;
10552 repeat = true;
10553 break;
10554 }
10555 }
10556 } while (repeat);
10557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010558 if (!mRestartingServices.contains(r)) {
10559 mRestartingServices.add(r);
10560 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010561
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010562 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010564 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010565 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010566 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10567 Log.w(TAG, "Scheduling restart of crashed service "
10568 + r.shortName + " in " + r.restartDelay + "ms");
10569 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10570 r.shortName, r.restartDelay);
10571
10572 Message msg = Message.obtain();
10573 msg.what = SERVICE_ERROR_MSG;
10574 msg.obj = r;
10575 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010576
10577 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010578 }
10579
10580 final void performServiceRestartLocked(ServiceRecord r) {
10581 if (!mRestartingServices.contains(r)) {
10582 return;
10583 }
10584 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10585 }
10586
10587 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10588 if (r.restartDelay == 0) {
10589 return false;
10590 }
10591 r.resetRestartCounter();
10592 mRestartingServices.remove(r);
10593 mHandler.removeCallbacks(r.restarter);
10594 return true;
10595 }
10596
10597 private final boolean bringUpServiceLocked(ServiceRecord r,
10598 int intentFlags, boolean whileRestarting) {
10599 //Log.i(TAG, "Bring up service:");
10600 //r.dump(" ");
10601
Dianne Hackborn36124872009-10-08 16:22:03 -070010602 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010603 sendServiceArgsLocked(r, false);
10604 return true;
10605 }
10606
10607 if (!whileRestarting && r.restartDelay > 0) {
10608 // If waiting for a restart, then do nothing.
10609 return true;
10610 }
10611
10612 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10613 + " " + r.intent);
10614
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010615 // We are now bringing the service up, so no longer in the
10616 // restarting state.
10617 mRestartingServices.remove(r);
10618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010619 final String appName = r.processName;
10620 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10621 if (app != null && app.thread != null) {
10622 try {
10623 realStartServiceLocked(r, app);
10624 return true;
10625 } catch (RemoteException e) {
10626 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10627 }
10628
10629 // If a dead object exception was thrown -- fall through to
10630 // restart the application.
10631 }
10632
Dianne Hackborn36124872009-10-08 16:22:03 -070010633 // Not running -- get it started, and enqueue this service record
10634 // to be executed when the app comes up.
10635 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10636 "service", r.name, false) == null) {
10637 Log.w(TAG, "Unable to launch app "
10638 + r.appInfo.packageName + "/"
10639 + r.appInfo.uid + " for service "
10640 + r.intent.getIntent() + ": process is bad");
10641 bringDownServiceLocked(r, true);
10642 return false;
10643 }
10644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010645 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010646 mPendingServices.add(r);
10647 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010648
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010649 return true;
10650 }
10651
10652 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10653 //Log.i(TAG, "Bring down service:");
10654 //r.dump(" ");
10655
10656 // Does it still need to run?
10657 if (!force && r.startRequested) {
10658 return;
10659 }
10660 if (r.connections.size() > 0) {
10661 if (!force) {
10662 // XXX should probably keep a count of the number of auto-create
10663 // connections directly in the service.
10664 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10665 while (it.hasNext()) {
10666 ConnectionRecord cr = it.next();
10667 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10668 return;
10669 }
10670 }
10671 }
10672
10673 // Report to all of the connections that the service is no longer
10674 // available.
10675 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10676 while (it.hasNext()) {
10677 ConnectionRecord c = it.next();
10678 try {
10679 // todo: shouldn't be a synchronous call!
10680 c.conn.connected(r.name, null);
10681 } catch (Exception e) {
10682 Log.w(TAG, "Failure disconnecting service " + r.name +
10683 " to connection " + c.conn.asBinder() +
10684 " (in " + c.binding.client.processName + ")", e);
10685 }
10686 }
10687 }
10688
10689 // Tell the service that it has been unbound.
10690 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10691 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10692 while (it.hasNext()) {
10693 IntentBindRecord ibr = it.next();
10694 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10695 + ": hasBound=" + ibr.hasBound);
10696 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10697 try {
10698 bumpServiceExecutingLocked(r);
10699 updateOomAdjLocked(r.app);
10700 ibr.hasBound = false;
10701 r.app.thread.scheduleUnbindService(r,
10702 ibr.intent.getIntent());
10703 } catch (Exception e) {
10704 Log.w(TAG, "Exception when unbinding service "
10705 + r.shortName, e);
10706 serviceDoneExecutingLocked(r, true);
10707 }
10708 }
10709 }
10710 }
10711
10712 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10713 + " " + r.intent);
10714 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10715 System.identityHashCode(r), r.shortName,
10716 (r.app != null) ? r.app.pid : -1);
10717
10718 mServices.remove(r.name);
10719 mServicesByIntent.remove(r.intent);
10720 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10721 r.totalRestartCount = 0;
10722 unscheduleServiceRestartLocked(r);
10723
10724 // Also make sure it is not on the pending list.
10725 int N = mPendingServices.size();
10726 for (int i=0; i<N; i++) {
10727 if (mPendingServices.get(i) == r) {
10728 mPendingServices.remove(i);
10729 if (DEBUG_SERVICE) Log.v(
10730 TAG, "Removed pending service: " + r.shortName);
10731 i--;
10732 N--;
10733 }
10734 }
10735
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010736 r.cancelNotification();
10737 r.isForeground = false;
10738 r.foregroundId = 0;
10739 r.foregroundNoti = null;
10740
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010741 // Clear start entries.
10742 r.deliveredStarts.clear();
10743 r.pendingStarts.clear();
10744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010745 if (r.app != null) {
10746 synchronized (r.stats.getBatteryStats()) {
10747 r.stats.stopLaunchedLocked();
10748 }
10749 r.app.services.remove(r);
10750 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010751 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010752 if (DEBUG_SERVICE) Log.v(TAG,
10753 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010754 bumpServiceExecutingLocked(r);
10755 mStoppingServices.add(r);
10756 updateOomAdjLocked(r.app);
10757 r.app.thread.scheduleStopService(r);
10758 } catch (Exception e) {
10759 Log.w(TAG, "Exception when stopping service "
10760 + r.shortName, e);
10761 serviceDoneExecutingLocked(r, true);
10762 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010763 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010764 } else {
10765 if (DEBUG_SERVICE) Log.v(
10766 TAG, "Removed service that has no process: " + r.shortName);
10767 }
10768 } else {
10769 if (DEBUG_SERVICE) Log.v(
10770 TAG, "Removed service that is not running: " + r.shortName);
10771 }
10772 }
10773
10774 ComponentName startServiceLocked(IApplicationThread caller,
10775 Intent service, String resolvedType,
10776 int callingPid, int callingUid) {
10777 synchronized(this) {
10778 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10779 + " type=" + resolvedType + " args=" + service.getExtras());
10780
10781 if (caller != null) {
10782 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10783 if (callerApp == null) {
10784 throw new SecurityException(
10785 "Unable to find app for caller " + caller
10786 + " (pid=" + Binder.getCallingPid()
10787 + ") when starting service " + service);
10788 }
10789 }
10790
10791 ServiceLookupResult res =
10792 retrieveServiceLocked(service, resolvedType,
10793 callingPid, callingUid);
10794 if (res == null) {
10795 return null;
10796 }
10797 if (res.record == null) {
10798 return new ComponentName("!", res.permission != null
10799 ? res.permission : "private to package");
10800 }
10801 ServiceRecord r = res.record;
10802 if (unscheduleServiceRestartLocked(r)) {
10803 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10804 + r.shortName);
10805 }
10806 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010807 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010808 r.lastStartId++;
10809 if (r.lastStartId < 1) {
10810 r.lastStartId = 1;
10811 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010812 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010813 r.lastActivity = SystemClock.uptimeMillis();
10814 synchronized (r.stats.getBatteryStats()) {
10815 r.stats.startRunningLocked();
10816 }
10817 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10818 return new ComponentName("!", "Service process is bad");
10819 }
10820 return r.name;
10821 }
10822 }
10823
10824 public ComponentName startService(IApplicationThread caller, Intent service,
10825 String resolvedType) {
10826 // Refuse possible leaked file descriptors
10827 if (service != null && service.hasFileDescriptors() == true) {
10828 throw new IllegalArgumentException("File descriptors passed in Intent");
10829 }
10830
10831 synchronized(this) {
10832 final int callingPid = Binder.getCallingPid();
10833 final int callingUid = Binder.getCallingUid();
10834 final long origId = Binder.clearCallingIdentity();
10835 ComponentName res = startServiceLocked(caller, service,
10836 resolvedType, callingPid, callingUid);
10837 Binder.restoreCallingIdentity(origId);
10838 return res;
10839 }
10840 }
10841
10842 ComponentName startServiceInPackage(int uid,
10843 Intent service, String resolvedType) {
10844 synchronized(this) {
10845 final long origId = Binder.clearCallingIdentity();
10846 ComponentName res = startServiceLocked(null, service,
10847 resolvedType, -1, uid);
10848 Binder.restoreCallingIdentity(origId);
10849 return res;
10850 }
10851 }
10852
10853 public int stopService(IApplicationThread caller, Intent service,
10854 String resolvedType) {
10855 // Refuse possible leaked file descriptors
10856 if (service != null && service.hasFileDescriptors() == true) {
10857 throw new IllegalArgumentException("File descriptors passed in Intent");
10858 }
10859
10860 synchronized(this) {
10861 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10862 + " type=" + resolvedType);
10863
10864 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10865 if (caller != null && callerApp == null) {
10866 throw new SecurityException(
10867 "Unable to find app for caller " + caller
10868 + " (pid=" + Binder.getCallingPid()
10869 + ") when stopping service " + service);
10870 }
10871
10872 // If this service is active, make sure it is stopped.
10873 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10874 if (r != null) {
10875 if (r.record != null) {
10876 synchronized (r.record.stats.getBatteryStats()) {
10877 r.record.stats.stopRunningLocked();
10878 }
10879 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010880 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010881 final long origId = Binder.clearCallingIdentity();
10882 bringDownServiceLocked(r.record, false);
10883 Binder.restoreCallingIdentity(origId);
10884 return 1;
10885 }
10886 return -1;
10887 }
10888 }
10889
10890 return 0;
10891 }
10892
10893 public IBinder peekService(Intent service, String resolvedType) {
10894 // Refuse possible leaked file descriptors
10895 if (service != null && service.hasFileDescriptors() == true) {
10896 throw new IllegalArgumentException("File descriptors passed in Intent");
10897 }
10898
10899 IBinder ret = null;
10900
10901 synchronized(this) {
10902 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10903
10904 if (r != null) {
10905 // r.record is null if findServiceLocked() failed the caller permission check
10906 if (r.record == null) {
10907 throw new SecurityException(
10908 "Permission Denial: Accessing service " + r.record.name
10909 + " from pid=" + Binder.getCallingPid()
10910 + ", uid=" + Binder.getCallingUid()
10911 + " requires " + r.permission);
10912 }
10913 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10914 if (ib != null) {
10915 ret = ib.binder;
10916 }
10917 }
10918 }
10919
10920 return ret;
10921 }
10922
10923 public boolean stopServiceToken(ComponentName className, IBinder token,
10924 int startId) {
10925 synchronized(this) {
10926 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10927 + " " + token + " startId=" + startId);
10928 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010929 if (r != null) {
10930 if (startId >= 0) {
10931 // Asked to only stop if done with all work. Note that
10932 // to avoid leaks, we will take this as dropping all
10933 // start items up to and including this one.
10934 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10935 if (si != null) {
10936 while (r.deliveredStarts.size() > 0) {
10937 if (r.deliveredStarts.remove(0) == si) {
10938 break;
10939 }
10940 }
10941 }
10942
10943 if (r.lastStartId != startId) {
10944 return false;
10945 }
10946
10947 if (r.deliveredStarts.size() > 0) {
10948 Log.w(TAG, "stopServiceToken startId " + startId
10949 + " is last, but have " + r.deliveredStarts.size()
10950 + " remaining args");
10951 }
10952 }
10953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010954 synchronized (r.stats.getBatteryStats()) {
10955 r.stats.stopRunningLocked();
10956 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010957 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010958 }
10959 final long origId = Binder.clearCallingIdentity();
10960 bringDownServiceLocked(r, false);
10961 Binder.restoreCallingIdentity(origId);
10962 return true;
10963 }
10964 }
10965 return false;
10966 }
10967
10968 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010969 int id, Notification notification, boolean removeNotification) {
10970 final long origId = Binder.clearCallingIdentity();
10971 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010972 synchronized(this) {
10973 ServiceRecord r = findServiceLocked(className, token);
10974 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010975 if (id != 0) {
10976 if (notification == null) {
10977 throw new IllegalArgumentException("null notification");
10978 }
10979 if (r.foregroundId != id) {
10980 r.cancelNotification();
10981 r.foregroundId = id;
10982 }
10983 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10984 r.foregroundNoti = notification;
10985 r.isForeground = true;
10986 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010987 if (r.app != null) {
10988 updateServiceForegroundLocked(r.app, true);
10989 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010990 } else {
10991 if (r.isForeground) {
10992 r.isForeground = false;
10993 if (r.app != null) {
10994 updateServiceForegroundLocked(r.app, true);
10995 }
10996 }
10997 if (removeNotification) {
10998 r.cancelNotification();
10999 r.foregroundId = 0;
11000 r.foregroundNoti = null;
11001 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011002 }
11003 }
11004 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011005 } finally {
11006 Binder.restoreCallingIdentity(origId);
11007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011008 }
11009
11010 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11011 boolean anyForeground = false;
11012 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11013 if (sr.isForeground) {
11014 anyForeground = true;
11015 break;
11016 }
11017 }
11018 if (anyForeground != proc.foregroundServices) {
11019 proc.foregroundServices = anyForeground;
11020 if (oomAdj) {
11021 updateOomAdjLocked();
11022 }
11023 }
11024 }
11025
11026 public int bindService(IApplicationThread caller, IBinder token,
11027 Intent service, String resolvedType,
11028 IServiceConnection connection, int flags) {
11029 // Refuse possible leaked file descriptors
11030 if (service != null && service.hasFileDescriptors() == true) {
11031 throw new IllegalArgumentException("File descriptors passed in Intent");
11032 }
11033
11034 synchronized(this) {
11035 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11036 + " type=" + resolvedType + " conn=" + connection.asBinder()
11037 + " flags=0x" + Integer.toHexString(flags));
11038 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11039 if (callerApp == null) {
11040 throw new SecurityException(
11041 "Unable to find app for caller " + caller
11042 + " (pid=" + Binder.getCallingPid()
11043 + ") when binding service " + service);
11044 }
11045
11046 HistoryRecord activity = null;
11047 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011048 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011049 if (aindex < 0) {
11050 Log.w(TAG, "Binding with unknown activity: " + token);
11051 return 0;
11052 }
11053 activity = (HistoryRecord)mHistory.get(aindex);
11054 }
11055
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011056 int clientLabel = 0;
11057 PendingIntent clientIntent = null;
11058
11059 if (callerApp.info.uid == Process.SYSTEM_UID) {
11060 // Hacky kind of thing -- allow system stuff to tell us
11061 // what they are, so we can report this elsewhere for
11062 // others to know why certain services are running.
11063 try {
11064 clientIntent = (PendingIntent)service.getParcelableExtra(
11065 Intent.EXTRA_CLIENT_INTENT);
11066 } catch (RuntimeException e) {
11067 }
11068 if (clientIntent != null) {
11069 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11070 if (clientLabel != 0) {
11071 // There are no useful extras in the intent, trash them.
11072 // System code calling with this stuff just needs to know
11073 // this will happen.
11074 service = service.cloneFilter();
11075 }
11076 }
11077 }
11078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011079 ServiceLookupResult res =
11080 retrieveServiceLocked(service, resolvedType,
11081 Binder.getCallingPid(), Binder.getCallingUid());
11082 if (res == null) {
11083 return 0;
11084 }
11085 if (res.record == null) {
11086 return -1;
11087 }
11088 ServiceRecord s = res.record;
11089
11090 final long origId = Binder.clearCallingIdentity();
11091
11092 if (unscheduleServiceRestartLocked(s)) {
11093 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11094 + s.shortName);
11095 }
11096
11097 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11098 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011099 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011100
11101 IBinder binder = connection.asBinder();
11102 s.connections.put(binder, c);
11103 b.connections.add(c);
11104 if (activity != null) {
11105 if (activity.connections == null) {
11106 activity.connections = new HashSet<ConnectionRecord>();
11107 }
11108 activity.connections.add(c);
11109 }
11110 b.client.connections.add(c);
11111 mServiceConnections.put(binder, c);
11112
11113 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11114 s.lastActivity = SystemClock.uptimeMillis();
11115 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11116 return 0;
11117 }
11118 }
11119
11120 if (s.app != null) {
11121 // This could have made the service more important.
11122 updateOomAdjLocked(s.app);
11123 }
11124
11125 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11126 + ": received=" + b.intent.received
11127 + " apps=" + b.intent.apps.size()
11128 + " doRebind=" + b.intent.doRebind);
11129
11130 if (s.app != null && b.intent.received) {
11131 // Service is already running, so we can immediately
11132 // publish the connection.
11133 try {
11134 c.conn.connected(s.name, b.intent.binder);
11135 } catch (Exception e) {
11136 Log.w(TAG, "Failure sending service " + s.shortName
11137 + " to connection " + c.conn.asBinder()
11138 + " (in " + c.binding.client.processName + ")", e);
11139 }
11140
11141 // If this is the first app connected back to this binding,
11142 // and the service had previously asked to be told when
11143 // rebound, then do so.
11144 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11145 requestServiceBindingLocked(s, b.intent, true);
11146 }
11147 } else if (!b.intent.requested) {
11148 requestServiceBindingLocked(s, b.intent, false);
11149 }
11150
11151 Binder.restoreCallingIdentity(origId);
11152 }
11153
11154 return 1;
11155 }
11156
11157 private void removeConnectionLocked(
11158 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11159 IBinder binder = c.conn.asBinder();
11160 AppBindRecord b = c.binding;
11161 ServiceRecord s = b.service;
11162 s.connections.remove(binder);
11163 b.connections.remove(c);
11164 if (c.activity != null && c.activity != skipAct) {
11165 if (c.activity.connections != null) {
11166 c.activity.connections.remove(c);
11167 }
11168 }
11169 if (b.client != skipApp) {
11170 b.client.connections.remove(c);
11171 }
11172 mServiceConnections.remove(binder);
11173
11174 if (b.connections.size() == 0) {
11175 b.intent.apps.remove(b.client);
11176 }
11177
11178 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11179 + ": shouldUnbind=" + b.intent.hasBound);
11180 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11181 && b.intent.hasBound) {
11182 try {
11183 bumpServiceExecutingLocked(s);
11184 updateOomAdjLocked(s.app);
11185 b.intent.hasBound = false;
11186 // Assume the client doesn't want to know about a rebind;
11187 // we will deal with that later if it asks for one.
11188 b.intent.doRebind = false;
11189 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11190 } catch (Exception e) {
11191 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11192 serviceDoneExecutingLocked(s, true);
11193 }
11194 }
11195
11196 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11197 bringDownServiceLocked(s, false);
11198 }
11199 }
11200
11201 public boolean unbindService(IServiceConnection connection) {
11202 synchronized (this) {
11203 IBinder binder = connection.asBinder();
11204 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11205 ConnectionRecord r = mServiceConnections.get(binder);
11206 if (r == null) {
11207 Log.w(TAG, "Unbind failed: could not find connection for "
11208 + connection.asBinder());
11209 return false;
11210 }
11211
11212 final long origId = Binder.clearCallingIdentity();
11213
11214 removeConnectionLocked(r, null, null);
11215
11216 if (r.binding.service.app != null) {
11217 // This could have made the service less important.
11218 updateOomAdjLocked(r.binding.service.app);
11219 }
11220
11221 Binder.restoreCallingIdentity(origId);
11222 }
11223
11224 return true;
11225 }
11226
11227 public void publishService(IBinder token, Intent intent, IBinder service) {
11228 // Refuse possible leaked file descriptors
11229 if (intent != null && intent.hasFileDescriptors() == true) {
11230 throw new IllegalArgumentException("File descriptors passed in Intent");
11231 }
11232
11233 synchronized(this) {
11234 if (!(token instanceof ServiceRecord)) {
11235 throw new IllegalArgumentException("Invalid service token");
11236 }
11237 ServiceRecord r = (ServiceRecord)token;
11238
11239 final long origId = Binder.clearCallingIdentity();
11240
11241 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11242 + " " + intent + ": " + service);
11243 if (r != null) {
11244 Intent.FilterComparison filter
11245 = new Intent.FilterComparison(intent);
11246 IntentBindRecord b = r.bindings.get(filter);
11247 if (b != null && !b.received) {
11248 b.binder = service;
11249 b.requested = true;
11250 b.received = true;
11251 if (r.connections.size() > 0) {
11252 Iterator<ConnectionRecord> it
11253 = r.connections.values().iterator();
11254 while (it.hasNext()) {
11255 ConnectionRecord c = it.next();
11256 if (!filter.equals(c.binding.intent.intent)) {
11257 if (DEBUG_SERVICE) Log.v(
11258 TAG, "Not publishing to: " + c);
11259 if (DEBUG_SERVICE) Log.v(
11260 TAG, "Bound intent: " + c.binding.intent.intent);
11261 if (DEBUG_SERVICE) Log.v(
11262 TAG, "Published intent: " + intent);
11263 continue;
11264 }
11265 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11266 try {
11267 c.conn.connected(r.name, service);
11268 } catch (Exception e) {
11269 Log.w(TAG, "Failure sending service " + r.name +
11270 " to connection " + c.conn.asBinder() +
11271 " (in " + c.binding.client.processName + ")", e);
11272 }
11273 }
11274 }
11275 }
11276
11277 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11278
11279 Binder.restoreCallingIdentity(origId);
11280 }
11281 }
11282 }
11283
11284 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11285 // Refuse possible leaked file descriptors
11286 if (intent != null && intent.hasFileDescriptors() == true) {
11287 throw new IllegalArgumentException("File descriptors passed in Intent");
11288 }
11289
11290 synchronized(this) {
11291 if (!(token instanceof ServiceRecord)) {
11292 throw new IllegalArgumentException("Invalid service token");
11293 }
11294 ServiceRecord r = (ServiceRecord)token;
11295
11296 final long origId = Binder.clearCallingIdentity();
11297
11298 if (r != null) {
11299 Intent.FilterComparison filter
11300 = new Intent.FilterComparison(intent);
11301 IntentBindRecord b = r.bindings.get(filter);
11302 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11303 + " at " + b + ": apps="
11304 + (b != null ? b.apps.size() : 0));
11305 if (b != null) {
11306 if (b.apps.size() > 0) {
11307 // Applications have already bound since the last
11308 // unbind, so just rebind right here.
11309 requestServiceBindingLocked(r, b, true);
11310 } else {
11311 // Note to tell the service the next time there is
11312 // a new client.
11313 b.doRebind = true;
11314 }
11315 }
11316
11317 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11318
11319 Binder.restoreCallingIdentity(origId);
11320 }
11321 }
11322 }
11323
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011324 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011325 synchronized(this) {
11326 if (!(token instanceof ServiceRecord)) {
11327 throw new IllegalArgumentException("Invalid service token");
11328 }
11329 ServiceRecord r = (ServiceRecord)token;
11330 boolean inStopping = mStoppingServices.contains(token);
11331 if (r != null) {
11332 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11333 + ": nesting=" + r.executeNesting
11334 + ", inStopping=" + inStopping);
11335 if (r != token) {
11336 Log.w(TAG, "Done executing service " + r.name
11337 + " with incorrect token: given " + token
11338 + ", expected " + r);
11339 return;
11340 }
11341
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011342 if (type == 1) {
11343 // This is a call from a service start... take care of
11344 // book-keeping.
11345 r.callStart = true;
11346 switch (res) {
11347 case Service.START_STICKY_COMPATIBILITY:
11348 case Service.START_STICKY: {
11349 // We are done with the associated start arguments.
11350 r.findDeliveredStart(startId, true);
11351 // Don't stop if killed.
11352 r.stopIfKilled = false;
11353 break;
11354 }
11355 case Service.START_NOT_STICKY: {
11356 // We are done with the associated start arguments.
11357 r.findDeliveredStart(startId, true);
11358 if (r.lastStartId == startId) {
11359 // There is no more work, and this service
11360 // doesn't want to hang around if killed.
11361 r.stopIfKilled = true;
11362 }
11363 break;
11364 }
11365 case Service.START_REDELIVER_INTENT: {
11366 // We'll keep this item until they explicitly
11367 // call stop for it, but keep track of the fact
11368 // that it was delivered.
11369 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11370 if (si != null) {
11371 si.deliveryCount = 0;
11372 si.doneExecutingCount++;
11373 // Don't stop if killed.
11374 r.stopIfKilled = true;
11375 }
11376 break;
11377 }
11378 default:
11379 throw new IllegalArgumentException(
11380 "Unknown service start result: " + res);
11381 }
11382 if (res == Service.START_STICKY_COMPATIBILITY) {
11383 r.callStart = false;
11384 }
11385 }
11386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011387 final long origId = Binder.clearCallingIdentity();
11388 serviceDoneExecutingLocked(r, inStopping);
11389 Binder.restoreCallingIdentity(origId);
11390 } else {
11391 Log.w(TAG, "Done executing unknown service " + r.name
11392 + " with token " + token);
11393 }
11394 }
11395 }
11396
11397 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11398 r.executeNesting--;
11399 if (r.executeNesting <= 0 && r.app != null) {
11400 r.app.executingServices.remove(r);
11401 if (r.app.executingServices.size() == 0) {
11402 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11403 }
11404 if (inStopping) {
11405 mStoppingServices.remove(r);
11406 }
11407 updateOomAdjLocked(r.app);
11408 }
11409 }
11410
11411 void serviceTimeout(ProcessRecord proc) {
11412 synchronized(this) {
11413 if (proc.executingServices.size() == 0 || proc.thread == null) {
11414 return;
11415 }
11416 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11417 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11418 ServiceRecord timeout = null;
11419 long nextTime = 0;
11420 while (it.hasNext()) {
11421 ServiceRecord sr = it.next();
11422 if (sr.executingStart < maxTime) {
11423 timeout = sr;
11424 break;
11425 }
11426 if (sr.executingStart > nextTime) {
11427 nextTime = sr.executingStart;
11428 }
11429 }
11430 if (timeout != null && mLRUProcesses.contains(proc)) {
11431 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011432 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011433 + timeout.name);
11434 } else {
11435 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11436 msg.obj = proc;
11437 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11438 }
11439 }
11440 }
11441
11442 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011443 // BACKUP AND RESTORE
11444 // =========================================================
11445
11446 // Cause the target app to be launched if necessary and its backup agent
11447 // instantiated. The backup agent will invoke backupAgentCreated() on the
11448 // activity manager to announce its creation.
11449 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11450 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11451 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11452
11453 synchronized(this) {
11454 // !!! TODO: currently no check here that we're already bound
11455 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11456 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11457 synchronized (stats) {
11458 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11459 }
11460
11461 BackupRecord r = new BackupRecord(ss, app, backupMode);
11462 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11463 // startProcessLocked() returns existing proc's record if it's already running
11464 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011465 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011466 if (proc == null) {
11467 Log.e(TAG, "Unable to start backup agent process " + r);
11468 return false;
11469 }
11470
11471 r.app = proc;
11472 mBackupTarget = r;
11473 mBackupAppName = app.packageName;
11474
Christopher Tate6fa95972009-06-05 18:43:55 -070011475 // Try not to kill the process during backup
11476 updateOomAdjLocked(proc);
11477
Christopher Tate181fafa2009-05-14 11:12:14 -070011478 // If the process is already attached, schedule the creation of the backup agent now.
11479 // If it is not yet live, this will be done when it attaches to the framework.
11480 if (proc.thread != null) {
11481 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11482 try {
11483 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11484 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011485 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011486 }
11487 } else {
11488 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11489 }
11490 // Invariants: at this point, the target app process exists and the application
11491 // is either already running or in the process of coming up. mBackupTarget and
11492 // mBackupAppName describe the app, so that when it binds back to the AM we
11493 // know that it's scheduled for a backup-agent operation.
11494 }
11495
11496 return true;
11497 }
11498
11499 // A backup agent has just come up
11500 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11501 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11502 + " = " + agent);
11503
11504 synchronized(this) {
11505 if (!agentPackageName.equals(mBackupAppName)) {
11506 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11507 return;
11508 }
11509
Christopher Tate043dadc2009-06-02 16:11:00 -070011510 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011511 try {
11512 IBackupManager bm = IBackupManager.Stub.asInterface(
11513 ServiceManager.getService(Context.BACKUP_SERVICE));
11514 bm.agentConnected(agentPackageName, agent);
11515 } catch (RemoteException e) {
11516 // can't happen; the backup manager service is local
11517 } catch (Exception e) {
11518 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11519 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011520 } finally {
11521 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011522 }
11523 }
11524 }
11525
11526 // done with this agent
11527 public void unbindBackupAgent(ApplicationInfo appInfo) {
11528 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011529 if (appInfo == null) {
11530 Log.w(TAG, "unbind backup agent for null app");
11531 return;
11532 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011533
11534 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011535 if (mBackupAppName == null) {
11536 Log.w(TAG, "Unbinding backup agent with no active backup");
11537 return;
11538 }
11539
Christopher Tate181fafa2009-05-14 11:12:14 -070011540 if (!mBackupAppName.equals(appInfo.packageName)) {
11541 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11542 return;
11543 }
11544
Christopher Tate6fa95972009-06-05 18:43:55 -070011545 ProcessRecord proc = mBackupTarget.app;
11546 mBackupTarget = null;
11547 mBackupAppName = null;
11548
11549 // Not backing this app up any more; reset its OOM adjustment
11550 updateOomAdjLocked(proc);
11551
Christopher Tatec7b31e32009-06-10 15:49:30 -070011552 // If the app crashed during backup, 'thread' will be null here
11553 if (proc.thread != null) {
11554 try {
11555 proc.thread.scheduleDestroyBackupAgent(appInfo);
11556 } catch (Exception e) {
11557 Log.e(TAG, "Exception when unbinding backup agent:");
11558 e.printStackTrace();
11559 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011560 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011561 }
11562 }
11563 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011564 // BROADCASTS
11565 // =========================================================
11566
Josh Bartel7f208742010-02-25 11:01:44 -060011567 private final List getStickiesLocked(String action, IntentFilter filter,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011568 List cur) {
11569 final ContentResolver resolver = mContext.getContentResolver();
11570 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11571 if (list == null) {
11572 return cur;
11573 }
11574 int N = list.size();
11575 for (int i=0; i<N; i++) {
11576 Intent intent = list.get(i);
11577 if (filter.match(resolver, intent, true, TAG) >= 0) {
11578 if (cur == null) {
11579 cur = new ArrayList<Intent>();
11580 }
11581 cur.add(intent);
11582 }
11583 }
11584 return cur;
11585 }
11586
11587 private final void scheduleBroadcastsLocked() {
11588 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11589 + mBroadcastsScheduled);
11590
11591 if (mBroadcastsScheduled) {
11592 return;
11593 }
11594 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11595 mBroadcastsScheduled = true;
11596 }
11597
11598 public Intent registerReceiver(IApplicationThread caller,
11599 IIntentReceiver receiver, IntentFilter filter, String permission) {
11600 synchronized(this) {
11601 ProcessRecord callerApp = null;
11602 if (caller != null) {
11603 callerApp = getRecordForAppLocked(caller);
11604 if (callerApp == null) {
11605 throw new SecurityException(
11606 "Unable to find app for caller " + caller
11607 + " (pid=" + Binder.getCallingPid()
11608 + ") when registering receiver " + receiver);
11609 }
11610 }
11611
11612 List allSticky = null;
11613
11614 // Look for any matching sticky broadcasts...
11615 Iterator actions = filter.actionsIterator();
11616 if (actions != null) {
11617 while (actions.hasNext()) {
11618 String action = (String)actions.next();
Josh Bartel7f208742010-02-25 11:01:44 -060011619 allSticky = getStickiesLocked(action, filter, allSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011620 }
11621 } else {
Josh Bartel7f208742010-02-25 11:01:44 -060011622 allSticky = getStickiesLocked(null, filter, allSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011623 }
11624
11625 // The first sticky in the list is returned directly back to
11626 // the client.
11627 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11628
11629 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11630 + ": " + sticky);
11631
11632 if (receiver == null) {
11633 return sticky;
11634 }
11635
11636 ReceiverList rl
11637 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11638 if (rl == null) {
11639 rl = new ReceiverList(this, callerApp,
11640 Binder.getCallingPid(),
11641 Binder.getCallingUid(), receiver);
11642 if (rl.app != null) {
11643 rl.app.receivers.add(rl);
11644 } else {
11645 try {
11646 receiver.asBinder().linkToDeath(rl, 0);
11647 } catch (RemoteException e) {
11648 return sticky;
11649 }
11650 rl.linkedToDeath = true;
11651 }
11652 mRegisteredReceivers.put(receiver.asBinder(), rl);
11653 }
11654 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11655 rl.add(bf);
11656 if (!bf.debugCheck()) {
11657 Log.w(TAG, "==> For Dynamic broadast");
11658 }
11659 mReceiverResolver.addFilter(bf);
11660
11661 // Enqueue broadcasts for all existing stickies that match
11662 // this filter.
11663 if (allSticky != null) {
11664 ArrayList receivers = new ArrayList();
11665 receivers.add(bf);
11666
11667 int N = allSticky.size();
11668 for (int i=0; i<N; i++) {
11669 Intent intent = (Intent)allSticky.get(i);
11670 BroadcastRecord r = new BroadcastRecord(intent, null,
11671 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011672 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011673 if (mParallelBroadcasts.size() == 0) {
11674 scheduleBroadcastsLocked();
11675 }
11676 mParallelBroadcasts.add(r);
11677 }
11678 }
11679
11680 return sticky;
11681 }
11682 }
11683
11684 public void unregisterReceiver(IIntentReceiver receiver) {
11685 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11686
11687 boolean doNext = false;
11688
11689 synchronized(this) {
11690 ReceiverList rl
11691 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11692 if (rl != null) {
11693 if (rl.curBroadcast != null) {
11694 BroadcastRecord r = rl.curBroadcast;
11695 doNext = finishReceiverLocked(
11696 receiver.asBinder(), r.resultCode, r.resultData,
11697 r.resultExtras, r.resultAbort, true);
11698 }
11699
11700 if (rl.app != null) {
11701 rl.app.receivers.remove(rl);
11702 }
11703 removeReceiverLocked(rl);
11704 if (rl.linkedToDeath) {
11705 rl.linkedToDeath = false;
11706 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11707 }
11708 }
11709 }
11710
11711 if (!doNext) {
11712 return;
11713 }
11714
11715 final long origId = Binder.clearCallingIdentity();
11716 processNextBroadcast(false);
11717 trimApplications();
11718 Binder.restoreCallingIdentity(origId);
11719 }
11720
11721 void removeReceiverLocked(ReceiverList rl) {
11722 mRegisteredReceivers.remove(rl.receiver.asBinder());
11723 int N = rl.size();
11724 for (int i=0; i<N; i++) {
11725 mReceiverResolver.removeFilter(rl.get(i));
11726 }
11727 }
11728
11729 private final int broadcastIntentLocked(ProcessRecord callerApp,
11730 String callerPackage, Intent intent, String resolvedType,
11731 IIntentReceiver resultTo, int resultCode, String resultData,
11732 Bundle map, String requiredPermission,
11733 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11734 intent = new Intent(intent);
11735
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011736 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011737 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11738 + " ordered=" + ordered);
11739 if ((resultTo != null) && !ordered) {
11740 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11741 }
11742
11743 // Handle special intents: if this broadcast is from the package
11744 // manager about a package being removed, we need to remove all of
11745 // its activities from the history stack.
11746 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11747 intent.getAction());
11748 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11749 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11750 || uidRemoved) {
11751 if (checkComponentPermission(
11752 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11753 callingPid, callingUid, -1)
11754 == PackageManager.PERMISSION_GRANTED) {
11755 if (uidRemoved) {
11756 final Bundle intentExtras = intent.getExtras();
11757 final int uid = intentExtras != null
11758 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11759 if (uid >= 0) {
11760 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11761 synchronized (bs) {
11762 bs.removeUidStatsLocked(uid);
11763 }
11764 }
11765 } else {
11766 Uri data = intent.getData();
11767 String ssp;
11768 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11769 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11770 uninstallPackageLocked(ssp,
11771 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011772 AttributeCache ac = AttributeCache.instance();
11773 if (ac != null) {
11774 ac.removePackage(ssp);
11775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011776 }
11777 }
11778 }
11779 } else {
11780 String msg = "Permission Denial: " + intent.getAction()
11781 + " broadcast from " + callerPackage + " (pid=" + callingPid
11782 + ", uid=" + callingUid + ")"
11783 + " requires "
11784 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11785 Log.w(TAG, msg);
11786 throw new SecurityException(msg);
11787 }
11788 }
11789
11790 /*
11791 * If this is the time zone changed action, queue up a message that will reset the timezone
11792 * of all currently running processes. This message will get queued up before the broadcast
11793 * happens.
11794 */
11795 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11796 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11797 }
11798
Dianne Hackborn854060af2009-07-09 18:14:31 -070011799 /*
11800 * Prevent non-system code (defined here to be non-persistent
11801 * processes) from sending protected broadcasts.
11802 */
11803 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11804 || callingUid == Process.SHELL_UID || callingUid == 0) {
11805 // Always okay.
11806 } else if (callerApp == null || !callerApp.persistent) {
11807 try {
11808 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11809 intent.getAction())) {
11810 String msg = "Permission Denial: not allowed to send broadcast "
11811 + intent.getAction() + " from pid="
11812 + callingPid + ", uid=" + callingUid;
11813 Log.w(TAG, msg);
11814 throw new SecurityException(msg);
11815 }
11816 } catch (RemoteException e) {
11817 Log.w(TAG, "Remote exception", e);
11818 return BROADCAST_SUCCESS;
11819 }
11820 }
11821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011822 // Add to the sticky list if requested.
11823 if (sticky) {
11824 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11825 callingPid, callingUid)
11826 != PackageManager.PERMISSION_GRANTED) {
11827 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11828 + callingPid + ", uid=" + callingUid
11829 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11830 Log.w(TAG, msg);
11831 throw new SecurityException(msg);
11832 }
11833 if (requiredPermission != null) {
11834 Log.w(TAG, "Can't broadcast sticky intent " + intent
11835 + " and enforce permission " + requiredPermission);
11836 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11837 }
11838 if (intent.getComponent() != null) {
11839 throw new SecurityException(
11840 "Sticky broadcasts can't target a specific component");
11841 }
11842 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11843 if (list == null) {
11844 list = new ArrayList<Intent>();
11845 mStickyBroadcasts.put(intent.getAction(), list);
11846 }
11847 int N = list.size();
11848 int i;
11849 for (i=0; i<N; i++) {
11850 if (intent.filterEquals(list.get(i))) {
11851 // This sticky already exists, replace it.
11852 list.set(i, new Intent(intent));
11853 break;
11854 }
11855 }
11856 if (i >= N) {
11857 list.add(new Intent(intent));
11858 }
11859 }
11860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011861 // Figure out who all will receive this broadcast.
11862 List receivers = null;
11863 List<BroadcastFilter> registeredReceivers = null;
11864 try {
11865 if (intent.getComponent() != null) {
11866 // Broadcast is going to one specific receiver class...
11867 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011868 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011869 if (ai != null) {
11870 receivers = new ArrayList();
11871 ResolveInfo ri = new ResolveInfo();
11872 ri.activityInfo = ai;
11873 receivers.add(ri);
11874 }
11875 } else {
11876 // Need to resolve the intent to interested receivers...
11877 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11878 == 0) {
11879 receivers =
11880 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011881 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011882 }
Mihai Preda074edef2009-05-18 17:13:31 +020011883 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011884 }
11885 } catch (RemoteException ex) {
11886 // pm is in same process, this will never happen.
11887 }
11888
11889 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11890 if (!ordered && NR > 0) {
11891 // If we are not serializing this broadcast, then send the
11892 // registered receivers separately so they don't wait for the
11893 // components to be launched.
11894 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11895 callerPackage, callingPid, callingUid, requiredPermission,
11896 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011897 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011898 if (DEBUG_BROADCAST) Log.v(
11899 TAG, "Enqueueing parallel broadcast " + r
11900 + ": prev had " + mParallelBroadcasts.size());
11901 mParallelBroadcasts.add(r);
11902 scheduleBroadcastsLocked();
11903 registeredReceivers = null;
11904 NR = 0;
11905 }
11906
11907 // Merge into one list.
11908 int ir = 0;
11909 if (receivers != null) {
11910 // A special case for PACKAGE_ADDED: do not allow the package
11911 // being added to see this broadcast. This prevents them from
11912 // using this as a back door to get run as soon as they are
11913 // installed. Maybe in the future we want to have a special install
11914 // broadcast or such for apps, but we'd like to deliberately make
11915 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011916 boolean skip = false;
11917 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011918 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011919 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11920 skip = true;
11921 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11922 skip = true;
11923 }
11924 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011925 ? intent.getData().getSchemeSpecificPart()
11926 : null;
11927 if (skipPackage != null && receivers != null) {
11928 int NT = receivers.size();
11929 for (int it=0; it<NT; it++) {
11930 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11931 if (curt.activityInfo.packageName.equals(skipPackage)) {
11932 receivers.remove(it);
11933 it--;
11934 NT--;
11935 }
11936 }
11937 }
11938
11939 int NT = receivers != null ? receivers.size() : 0;
11940 int it = 0;
11941 ResolveInfo curt = null;
11942 BroadcastFilter curr = null;
11943 while (it < NT && ir < NR) {
11944 if (curt == null) {
11945 curt = (ResolveInfo)receivers.get(it);
11946 }
11947 if (curr == null) {
11948 curr = registeredReceivers.get(ir);
11949 }
11950 if (curr.getPriority() >= curt.priority) {
11951 // Insert this broadcast record into the final list.
11952 receivers.add(it, curr);
11953 ir++;
11954 curr = null;
11955 it++;
11956 NT++;
11957 } else {
11958 // Skip to the next ResolveInfo in the final list.
11959 it++;
11960 curt = null;
11961 }
11962 }
11963 }
11964 while (ir < NR) {
11965 if (receivers == null) {
11966 receivers = new ArrayList();
11967 }
11968 receivers.add(registeredReceivers.get(ir));
11969 ir++;
11970 }
11971
11972 if ((receivers != null && receivers.size() > 0)
11973 || resultTo != null) {
11974 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11975 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011976 receivers, resultTo, resultCode, resultData, map, ordered,
11977 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011978 if (DEBUG_BROADCAST) Log.v(
11979 TAG, "Enqueueing ordered broadcast " + r
11980 + ": prev had " + mOrderedBroadcasts.size());
11981 if (DEBUG_BROADCAST) {
11982 int seq = r.intent.getIntExtra("seq", -1);
11983 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11984 }
11985 mOrderedBroadcasts.add(r);
11986 scheduleBroadcastsLocked();
11987 }
11988
11989 return BROADCAST_SUCCESS;
11990 }
11991
11992 public final int broadcastIntent(IApplicationThread caller,
11993 Intent intent, String resolvedType, IIntentReceiver resultTo,
11994 int resultCode, String resultData, Bundle map,
11995 String requiredPermission, boolean serialized, boolean sticky) {
11996 // Refuse possible leaked file descriptors
11997 if (intent != null && intent.hasFileDescriptors() == true) {
11998 throw new IllegalArgumentException("File descriptors passed in Intent");
11999 }
12000
12001 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012002 int flags = intent.getFlags();
12003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012004 if (!mSystemReady) {
12005 // if the caller really truly claims to know what they're doing, go
12006 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012007 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12008 intent = new Intent(intent);
12009 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12010 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12011 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12012 + " before boot completion");
12013 throw new IllegalStateException("Cannot broadcast before boot completed");
12014 }
12015 }
12016
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012017 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12018 throw new IllegalArgumentException(
12019 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12020 }
12021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012022 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12023 final int callingPid = Binder.getCallingPid();
12024 final int callingUid = Binder.getCallingUid();
12025 final long origId = Binder.clearCallingIdentity();
12026 int res = broadcastIntentLocked(callerApp,
12027 callerApp != null ? callerApp.info.packageName : null,
12028 intent, resolvedType, resultTo,
12029 resultCode, resultData, map, requiredPermission, serialized,
12030 sticky, callingPid, callingUid);
12031 Binder.restoreCallingIdentity(origId);
12032 return res;
12033 }
12034 }
12035
12036 int broadcastIntentInPackage(String packageName, int uid,
12037 Intent intent, String resolvedType, IIntentReceiver resultTo,
12038 int resultCode, String resultData, Bundle map,
12039 String requiredPermission, boolean serialized, boolean sticky) {
12040 synchronized(this) {
12041 final long origId = Binder.clearCallingIdentity();
12042 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12043 resultTo, resultCode, resultData, map, requiredPermission,
12044 serialized, sticky, -1, uid);
12045 Binder.restoreCallingIdentity(origId);
12046 return res;
12047 }
12048 }
12049
12050 public final void unbroadcastIntent(IApplicationThread caller,
12051 Intent intent) {
12052 // Refuse possible leaked file descriptors
12053 if (intent != null && intent.hasFileDescriptors() == true) {
12054 throw new IllegalArgumentException("File descriptors passed in Intent");
12055 }
12056
12057 synchronized(this) {
12058 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12059 != PackageManager.PERMISSION_GRANTED) {
12060 String msg = "Permission Denial: unbroadcastIntent() from pid="
12061 + Binder.getCallingPid()
12062 + ", uid=" + Binder.getCallingUid()
12063 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12064 Log.w(TAG, msg);
12065 throw new SecurityException(msg);
12066 }
12067 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12068 if (list != null) {
12069 int N = list.size();
12070 int i;
12071 for (i=0; i<N; i++) {
12072 if (intent.filterEquals(list.get(i))) {
12073 list.remove(i);
12074 break;
12075 }
12076 }
12077 }
12078 }
12079 }
12080
12081 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12082 String resultData, Bundle resultExtras, boolean resultAbort,
12083 boolean explicit) {
12084 if (mOrderedBroadcasts.size() == 0) {
12085 if (explicit) {
12086 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12087 }
12088 return false;
12089 }
12090 BroadcastRecord r = mOrderedBroadcasts.get(0);
12091 if (r.receiver == null) {
12092 if (explicit) {
12093 Log.w(TAG, "finishReceiver called but none active");
12094 }
12095 return false;
12096 }
12097 if (r.receiver != receiver) {
12098 Log.w(TAG, "finishReceiver called but active receiver is different");
12099 return false;
12100 }
12101 int state = r.state;
12102 r.state = r.IDLE;
12103 if (state == r.IDLE) {
12104 if (explicit) {
12105 Log.w(TAG, "finishReceiver called but state is IDLE");
12106 }
12107 }
12108 r.receiver = null;
12109 r.intent.setComponent(null);
12110 if (r.curApp != null) {
12111 r.curApp.curReceiver = null;
12112 }
12113 if (r.curFilter != null) {
12114 r.curFilter.receiverList.curBroadcast = null;
12115 }
12116 r.curFilter = null;
12117 r.curApp = null;
12118 r.curComponent = null;
12119 r.curReceiver = null;
12120 mPendingBroadcast = null;
12121
12122 r.resultCode = resultCode;
12123 r.resultData = resultData;
12124 r.resultExtras = resultExtras;
12125 r.resultAbort = resultAbort;
12126
12127 // We will process the next receiver right now if this is finishing
12128 // an app receiver (which is always asynchronous) or after we have
12129 // come back from calling a receiver.
12130 return state == BroadcastRecord.APP_RECEIVE
12131 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12132 }
12133
12134 public void finishReceiver(IBinder who, int resultCode, String resultData,
12135 Bundle resultExtras, boolean resultAbort) {
12136 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12137
12138 // Refuse possible leaked file descriptors
12139 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12140 throw new IllegalArgumentException("File descriptors passed in Bundle");
12141 }
12142
12143 boolean doNext;
12144
12145 final long origId = Binder.clearCallingIdentity();
12146
12147 synchronized(this) {
12148 doNext = finishReceiverLocked(
12149 who, resultCode, resultData, resultExtras, resultAbort, true);
12150 }
12151
12152 if (doNext) {
12153 processNextBroadcast(false);
12154 }
12155 trimApplications();
12156
12157 Binder.restoreCallingIdentity(origId);
12158 }
12159
12160 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12161 if (r.nextReceiver > 0) {
12162 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12163 if (curReceiver instanceof BroadcastFilter) {
12164 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12165 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12166 System.identityHashCode(r),
12167 r.intent.getAction(),
12168 r.nextReceiver - 1,
12169 System.identityHashCode(bf));
12170 } else {
12171 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12172 System.identityHashCode(r),
12173 r.intent.getAction(),
12174 r.nextReceiver - 1,
12175 ((ResolveInfo)curReceiver).toString());
12176 }
12177 } else {
12178 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12179 + r);
12180 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12181 System.identityHashCode(r),
12182 r.intent.getAction(),
12183 r.nextReceiver,
12184 "NONE");
12185 }
12186 }
12187
12188 private final void broadcastTimeout() {
12189 synchronized (this) {
12190 if (mOrderedBroadcasts.size() == 0) {
12191 return;
12192 }
12193 long now = SystemClock.uptimeMillis();
12194 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012195 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012196 if (DEBUG_BROADCAST) Log.v(TAG,
12197 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012198 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012199 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012200 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012201 return;
12202 }
12203
12204 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012205 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012206 r.anrCount++;
12207
12208 // Current receiver has passed its expiration date.
12209 if (r.nextReceiver <= 0) {
12210 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12211 return;
12212 }
12213
12214 ProcessRecord app = null;
12215
12216 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12217 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12218 logBroadcastReceiverDiscard(r);
12219 if (curReceiver instanceof BroadcastFilter) {
12220 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12221 if (bf.receiverList.pid != 0
12222 && bf.receiverList.pid != MY_PID) {
12223 synchronized (this.mPidsSelfLocked) {
12224 app = this.mPidsSelfLocked.get(
12225 bf.receiverList.pid);
12226 }
12227 }
12228 } else {
12229 app = r.curApp;
12230 }
12231
12232 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012233 appNotRespondingLocked(app, null, null,
12234 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012235 }
12236
12237 if (mPendingBroadcast == r) {
12238 mPendingBroadcast = null;
12239 }
12240
12241 // Move on to the next receiver.
12242 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12243 r.resultExtras, r.resultAbort, true);
12244 scheduleBroadcastsLocked();
12245 }
12246 }
12247
12248 private final void processCurBroadcastLocked(BroadcastRecord r,
12249 ProcessRecord app) throws RemoteException {
12250 if (app.thread == null) {
12251 throw new RemoteException();
12252 }
12253 r.receiver = app.thread.asBinder();
12254 r.curApp = app;
12255 app.curReceiver = r;
12256 updateLRUListLocked(app, true);
12257
12258 // Tell the application to launch this receiver.
12259 r.intent.setComponent(r.curComponent);
12260
12261 boolean started = false;
12262 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012263 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012264 "Delivering to component " + r.curComponent
12265 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012266 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012267 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12268 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12269 started = true;
12270 } finally {
12271 if (!started) {
12272 r.receiver = null;
12273 r.curApp = null;
12274 app.curReceiver = null;
12275 }
12276 }
12277
12278 }
12279
12280 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012281 Intent intent, int resultCode, String data, Bundle extras,
12282 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012283 if (app != null && app.thread != null) {
12284 // If we have an app thread, do the call through that so it is
12285 // correctly ordered with other one-way calls.
12286 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012287 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012288 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012289 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012290 }
12291 }
12292
12293 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12294 BroadcastFilter filter, boolean ordered) {
12295 boolean skip = false;
12296 if (filter.requiredPermission != null) {
12297 int perm = checkComponentPermission(filter.requiredPermission,
12298 r.callingPid, r.callingUid, -1);
12299 if (perm != PackageManager.PERMISSION_GRANTED) {
12300 Log.w(TAG, "Permission Denial: broadcasting "
12301 + r.intent.toString()
12302 + " from " + r.callerPackage + " (pid="
12303 + r.callingPid + ", uid=" + r.callingUid + ")"
12304 + " requires " + filter.requiredPermission
12305 + " due to registered receiver " + filter);
12306 skip = true;
12307 }
12308 }
12309 if (r.requiredPermission != null) {
12310 int perm = checkComponentPermission(r.requiredPermission,
12311 filter.receiverList.pid, filter.receiverList.uid, -1);
12312 if (perm != PackageManager.PERMISSION_GRANTED) {
12313 Log.w(TAG, "Permission Denial: receiving "
12314 + r.intent.toString()
12315 + " to " + filter.receiverList.app
12316 + " (pid=" + filter.receiverList.pid
12317 + ", uid=" + filter.receiverList.uid + ")"
12318 + " requires " + r.requiredPermission
12319 + " due to sender " + r.callerPackage
12320 + " (uid " + r.callingUid + ")");
12321 skip = true;
12322 }
12323 }
12324
12325 if (!skip) {
12326 // If this is not being sent as an ordered broadcast, then we
12327 // don't want to touch the fields that keep track of the current
12328 // state of ordered broadcasts.
12329 if (ordered) {
12330 r.receiver = filter.receiverList.receiver.asBinder();
12331 r.curFilter = filter;
12332 filter.receiverList.curBroadcast = r;
12333 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012334 if (filter.receiverList.app != null) {
12335 // Bump hosting application to no longer be in background
12336 // scheduling class. Note that we can't do that if there
12337 // isn't an app... but we can only be in that case for
12338 // things that directly call the IActivityManager API, which
12339 // are already core system stuff so don't matter for this.
12340 r.curApp = filter.receiverList.app;
12341 filter.receiverList.app.curReceiver = r;
12342 updateOomAdjLocked();
12343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012344 }
12345 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012346 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012347 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012348 Log.i(TAG, "Delivering to " + filter.receiverList.app
12349 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012350 }
12351 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12352 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012353 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012354 if (ordered) {
12355 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12356 }
12357 } catch (RemoteException e) {
12358 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12359 if (ordered) {
12360 r.receiver = null;
12361 r.curFilter = null;
12362 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012363 if (filter.receiverList.app != null) {
12364 filter.receiverList.app.curReceiver = null;
12365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012366 }
12367 }
12368 }
12369 }
12370
Dianne Hackborn12527f92009-11-11 17:39:50 -080012371 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12372 if (r.callingUid < 0) {
12373 // This was from a registerReceiver() call; ignore it.
12374 return;
12375 }
12376 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12377 MAX_BROADCAST_HISTORY-1);
12378 r.finishTime = SystemClock.uptimeMillis();
12379 mBroadcastHistory[0] = r;
12380 }
12381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012382 private final void processNextBroadcast(boolean fromMsg) {
12383 synchronized(this) {
12384 BroadcastRecord r;
12385
12386 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12387 + mParallelBroadcasts.size() + " broadcasts, "
12388 + mOrderedBroadcasts.size() + " serialized broadcasts");
12389
12390 updateCpuStats();
12391
12392 if (fromMsg) {
12393 mBroadcastsScheduled = false;
12394 }
12395
12396 // First, deliver any non-serialized broadcasts right away.
12397 while (mParallelBroadcasts.size() > 0) {
12398 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012399 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012400 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012401 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12402 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012403 for (int i=0; i<N; i++) {
12404 Object target = r.receivers.get(i);
12405 if (DEBUG_BROADCAST) Log.v(TAG,
12406 "Delivering non-serialized to registered "
12407 + target + ": " + r);
12408 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12409 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012410 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012411 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12412 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012413 }
12414
12415 // Now take care of the next serialized one...
12416
12417 // If we are waiting for a process to come up to handle the next
12418 // broadcast, then do nothing at this point. Just in case, we
12419 // check that the process we're waiting for still exists.
12420 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012421 if (DEBUG_BROADCAST_LIGHT) {
12422 Log.v(TAG, "processNextBroadcast: waiting for "
12423 + mPendingBroadcast.curApp);
12424 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012425
12426 boolean isDead;
12427 synchronized (mPidsSelfLocked) {
12428 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12429 }
12430 if (!isDead) {
12431 // It's still alive, so keep waiting
12432 return;
12433 } else {
12434 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12435 + " died before responding to broadcast");
12436 mPendingBroadcast = null;
12437 }
12438 }
12439
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012440 boolean looped = false;
12441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012442 do {
12443 if (mOrderedBroadcasts.size() == 0) {
12444 // No more broadcasts pending, so all done!
12445 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012446 if (looped) {
12447 // If we had finished the last ordered broadcast, then
12448 // make sure all processes have correct oom and sched
12449 // adjustments.
12450 updateOomAdjLocked();
12451 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012452 return;
12453 }
12454 r = mOrderedBroadcasts.get(0);
12455 boolean forceReceive = false;
12456
12457 // Ensure that even if something goes awry with the timeout
12458 // detection, we catch "hung" broadcasts here, discard them,
12459 // and continue to make progress.
12460 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12461 long now = SystemClock.uptimeMillis();
12462 if (r.dispatchTime > 0) {
12463 if ((numReceivers > 0) &&
12464 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12465 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12466 + " now=" + now
12467 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012468 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012469 + " intent=" + r.intent
12470 + " numReceivers=" + numReceivers
12471 + " nextReceiver=" + r.nextReceiver
12472 + " state=" + r.state);
12473 broadcastTimeout(); // forcibly finish this broadcast
12474 forceReceive = true;
12475 r.state = BroadcastRecord.IDLE;
12476 }
12477 }
12478
12479 if (r.state != BroadcastRecord.IDLE) {
12480 if (DEBUG_BROADCAST) Log.d(TAG,
12481 "processNextBroadcast() called when not idle (state="
12482 + r.state + ")");
12483 return;
12484 }
12485
12486 if (r.receivers == null || r.nextReceiver >= numReceivers
12487 || r.resultAbort || forceReceive) {
12488 // No more receivers for this broadcast! Send the final
12489 // result if requested...
12490 if (r.resultTo != null) {
12491 try {
12492 if (DEBUG_BROADCAST) {
12493 int seq = r.intent.getIntExtra("seq", -1);
12494 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12495 + " seq=" + seq + " app=" + r.callerApp);
12496 }
12497 performReceive(r.callerApp, r.resultTo,
12498 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012499 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012500 } catch (RemoteException e) {
12501 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12502 }
12503 }
12504
12505 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12506 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12507
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012508 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12509 + r);
12510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012511 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012512 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012513 mOrderedBroadcasts.remove(0);
12514 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012515 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012516 continue;
12517 }
12518 } while (r == null);
12519
12520 // Get the next receiver...
12521 int recIdx = r.nextReceiver++;
12522
12523 // Keep track of when this receiver started, and make sure there
12524 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012525 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012526 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012527 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012528
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012529 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12530 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012531 if (DEBUG_BROADCAST) Log.v(TAG,
12532 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012533 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012534 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012535 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012536 }
12537
12538 Object nextReceiver = r.receivers.get(recIdx);
12539 if (nextReceiver instanceof BroadcastFilter) {
12540 // Simple case: this is a registered receiver who gets
12541 // a direct call.
12542 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12543 if (DEBUG_BROADCAST) Log.v(TAG,
12544 "Delivering serialized to registered "
12545 + filter + ": " + r);
12546 deliverToRegisteredReceiver(r, filter, r.ordered);
12547 if (r.receiver == null || !r.ordered) {
12548 // The receiver has already finished, so schedule to
12549 // process the next one.
12550 r.state = BroadcastRecord.IDLE;
12551 scheduleBroadcastsLocked();
12552 }
12553 return;
12554 }
12555
12556 // Hard case: need to instantiate the receiver, possibly
12557 // starting its application process to host it.
12558
12559 ResolveInfo info =
12560 (ResolveInfo)nextReceiver;
12561
12562 boolean skip = false;
12563 int perm = checkComponentPermission(info.activityInfo.permission,
12564 r.callingPid, r.callingUid,
12565 info.activityInfo.exported
12566 ? -1 : info.activityInfo.applicationInfo.uid);
12567 if (perm != PackageManager.PERMISSION_GRANTED) {
12568 Log.w(TAG, "Permission Denial: broadcasting "
12569 + r.intent.toString()
12570 + " from " + r.callerPackage + " (pid=" + r.callingPid
12571 + ", uid=" + r.callingUid + ")"
12572 + " requires " + info.activityInfo.permission
12573 + " due to receiver " + info.activityInfo.packageName
12574 + "/" + info.activityInfo.name);
12575 skip = true;
12576 }
12577 if (r.callingUid != Process.SYSTEM_UID &&
12578 r.requiredPermission != null) {
12579 try {
12580 perm = ActivityThread.getPackageManager().
12581 checkPermission(r.requiredPermission,
12582 info.activityInfo.applicationInfo.packageName);
12583 } catch (RemoteException e) {
12584 perm = PackageManager.PERMISSION_DENIED;
12585 }
12586 if (perm != PackageManager.PERMISSION_GRANTED) {
12587 Log.w(TAG, "Permission Denial: receiving "
12588 + r.intent + " to "
12589 + info.activityInfo.applicationInfo.packageName
12590 + " requires " + r.requiredPermission
12591 + " due to sender " + r.callerPackage
12592 + " (uid " + r.callingUid + ")");
12593 skip = true;
12594 }
12595 }
12596 if (r.curApp != null && r.curApp.crashing) {
12597 // If the target process is crashing, just skip it.
12598 skip = true;
12599 }
12600
12601 if (skip) {
12602 r.receiver = null;
12603 r.curFilter = null;
12604 r.state = BroadcastRecord.IDLE;
12605 scheduleBroadcastsLocked();
12606 return;
12607 }
12608
12609 r.state = BroadcastRecord.APP_RECEIVE;
12610 String targetProcess = info.activityInfo.processName;
12611 r.curComponent = new ComponentName(
12612 info.activityInfo.applicationInfo.packageName,
12613 info.activityInfo.name);
12614 r.curReceiver = info.activityInfo;
12615
12616 // Is this receiver's application already running?
12617 ProcessRecord app = getProcessRecordLocked(targetProcess,
12618 info.activityInfo.applicationInfo.uid);
12619 if (app != null && app.thread != null) {
12620 try {
12621 processCurBroadcastLocked(r, app);
12622 return;
12623 } catch (RemoteException e) {
12624 Log.w(TAG, "Exception when sending broadcast to "
12625 + r.curComponent, e);
12626 }
12627
12628 // If a dead object exception was thrown -- fall through to
12629 // restart the application.
12630 }
12631
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012632 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012633 if ((r.curApp=startProcessLocked(targetProcess,
12634 info.activityInfo.applicationInfo, true,
12635 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012636 "broadcast", r.curComponent,
12637 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12638 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012639 // Ah, this recipient is unavailable. Finish it if necessary,
12640 // and mark the broadcast record as ready for the next.
12641 Log.w(TAG, "Unable to launch app "
12642 + info.activityInfo.applicationInfo.packageName + "/"
12643 + info.activityInfo.applicationInfo.uid + " for broadcast "
12644 + r.intent + ": process is bad");
12645 logBroadcastReceiverDiscard(r);
12646 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12647 r.resultExtras, r.resultAbort, true);
12648 scheduleBroadcastsLocked();
12649 r.state = BroadcastRecord.IDLE;
12650 return;
12651 }
12652
12653 mPendingBroadcast = r;
12654 }
12655 }
12656
12657 // =========================================================
12658 // INSTRUMENTATION
12659 // =========================================================
12660
12661 public boolean startInstrumentation(ComponentName className,
12662 String profileFile, int flags, Bundle arguments,
12663 IInstrumentationWatcher watcher) {
12664 // Refuse possible leaked file descriptors
12665 if (arguments != null && arguments.hasFileDescriptors()) {
12666 throw new IllegalArgumentException("File descriptors passed in Bundle");
12667 }
12668
12669 synchronized(this) {
12670 InstrumentationInfo ii = null;
12671 ApplicationInfo ai = null;
12672 try {
12673 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012674 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012675 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012676 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012677 } catch (PackageManager.NameNotFoundException e) {
12678 }
12679 if (ii == null) {
12680 reportStartInstrumentationFailure(watcher, className,
12681 "Unable to find instrumentation info for: " + className);
12682 return false;
12683 }
12684 if (ai == null) {
12685 reportStartInstrumentationFailure(watcher, className,
12686 "Unable to find instrumentation target package: " + ii.targetPackage);
12687 return false;
12688 }
12689
12690 int match = mContext.getPackageManager().checkSignatures(
12691 ii.targetPackage, ii.packageName);
12692 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12693 String msg = "Permission Denial: starting instrumentation "
12694 + className + " from pid="
12695 + Binder.getCallingPid()
12696 + ", uid=" + Binder.getCallingPid()
12697 + " not allowed because package " + ii.packageName
12698 + " does not have a signature matching the target "
12699 + ii.targetPackage;
12700 reportStartInstrumentationFailure(watcher, className, msg);
12701 throw new SecurityException(msg);
12702 }
12703
12704 final long origId = Binder.clearCallingIdentity();
12705 uninstallPackageLocked(ii.targetPackage, -1, true);
12706 ProcessRecord app = addAppLocked(ai);
12707 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012708 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012709 app.instrumentationProfileFile = profileFile;
12710 app.instrumentationArguments = arguments;
12711 app.instrumentationWatcher = watcher;
12712 app.instrumentationResultClass = className;
12713 Binder.restoreCallingIdentity(origId);
12714 }
12715
12716 return true;
12717 }
12718
12719 /**
12720 * Report errors that occur while attempting to start Instrumentation. Always writes the
12721 * error to the logs, but if somebody is watching, send the report there too. This enables
12722 * the "am" command to report errors with more information.
12723 *
12724 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12725 * @param cn The component name of the instrumentation.
12726 * @param report The error report.
12727 */
12728 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12729 ComponentName cn, String report) {
12730 Log.w(TAG, report);
12731 try {
12732 if (watcher != null) {
12733 Bundle results = new Bundle();
12734 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12735 results.putString("Error", report);
12736 watcher.instrumentationStatus(cn, -1, results);
12737 }
12738 } catch (RemoteException e) {
12739 Log.w(TAG, e);
12740 }
12741 }
12742
12743 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12744 if (app.instrumentationWatcher != null) {
12745 try {
12746 // NOTE: IInstrumentationWatcher *must* be oneway here
12747 app.instrumentationWatcher.instrumentationFinished(
12748 app.instrumentationClass,
12749 resultCode,
12750 results);
12751 } catch (RemoteException e) {
12752 }
12753 }
12754 app.instrumentationWatcher = null;
12755 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012756 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012757 app.instrumentationProfileFile = null;
12758 app.instrumentationArguments = null;
12759
12760 uninstallPackageLocked(app.processName, -1, false);
12761 }
12762
12763 public void finishInstrumentation(IApplicationThread target,
12764 int resultCode, Bundle results) {
12765 // Refuse possible leaked file descriptors
12766 if (results != null && results.hasFileDescriptors()) {
12767 throw new IllegalArgumentException("File descriptors passed in Intent");
12768 }
12769
12770 synchronized(this) {
12771 ProcessRecord app = getRecordForAppLocked(target);
12772 if (app == null) {
12773 Log.w(TAG, "finishInstrumentation: no app for " + target);
12774 return;
12775 }
12776 final long origId = Binder.clearCallingIdentity();
12777 finishInstrumentationLocked(app, resultCode, results);
12778 Binder.restoreCallingIdentity(origId);
12779 }
12780 }
12781
12782 // =========================================================
12783 // CONFIGURATION
12784 // =========================================================
12785
12786 public ConfigurationInfo getDeviceConfigurationInfo() {
12787 ConfigurationInfo config = new ConfigurationInfo();
12788 synchronized (this) {
12789 config.reqTouchScreen = mConfiguration.touchscreen;
12790 config.reqKeyboardType = mConfiguration.keyboard;
12791 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012792 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12793 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012794 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12795 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012796 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12797 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012798 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12799 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012800 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012801 }
12802 return config;
12803 }
12804
12805 public Configuration getConfiguration() {
12806 Configuration ci;
12807 synchronized(this) {
12808 ci = new Configuration(mConfiguration);
12809 }
12810 return ci;
12811 }
12812
12813 public void updateConfiguration(Configuration values) {
12814 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12815 "updateConfiguration()");
12816
12817 synchronized(this) {
12818 if (values == null && mWindowManager != null) {
12819 // sentinel: fetch the current configuration from the window manager
12820 values = mWindowManager.computeNewConfiguration();
12821 }
12822
12823 final long origId = Binder.clearCallingIdentity();
12824 updateConfigurationLocked(values, null);
12825 Binder.restoreCallingIdentity(origId);
12826 }
12827 }
12828
12829 /**
12830 * Do either or both things: (1) change the current configuration, and (2)
12831 * make sure the given activity is running with the (now) current
12832 * configuration. Returns true if the activity has been left running, or
12833 * false if <var>starting</var> is being destroyed to match the new
12834 * configuration.
12835 */
12836 public boolean updateConfigurationLocked(Configuration values,
12837 HistoryRecord starting) {
12838 int changes = 0;
12839
12840 boolean kept = true;
12841
12842 if (values != null) {
12843 Configuration newConfig = new Configuration(mConfiguration);
12844 changes = newConfig.updateFrom(values);
12845 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012846 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012847 Log.i(TAG, "Updating configuration to: " + values);
12848 }
12849
12850 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12851
12852 if (values.locale != null) {
12853 saveLocaleLocked(values.locale,
12854 !values.locale.equals(mConfiguration.locale),
12855 values.userSetLocale);
12856 }
12857
12858 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012859 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080012860
12861 AttributeCache ac = AttributeCache.instance();
12862 if (ac != null) {
12863 ac.updateConfiguration(mConfiguration);
12864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012865
12866 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12867 msg.obj = new Configuration(mConfiguration);
12868 mHandler.sendMessage(msg);
12869
12870 final int N = mLRUProcesses.size();
12871 for (int i=0; i<N; i++) {
12872 ProcessRecord app = mLRUProcesses.get(i);
12873 try {
12874 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012875 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12876 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012877 app.thread.scheduleConfigurationChanged(mConfiguration);
12878 }
12879 } catch (Exception e) {
12880 }
12881 }
12882 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012883 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012884 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12885 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012886 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
12887 broadcastIntentLocked(null, null,
12888 new Intent(Intent.ACTION_LOCALE_CHANGED),
12889 null, null, 0, null, null,
12890 null, false, false, MY_PID, Process.SYSTEM_UID);
12891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012892 }
12893 }
12894
12895 if (changes != 0 && starting == null) {
12896 // If the configuration changed, and the caller is not already
12897 // in the process of starting an activity, then find the top
12898 // activity to check if its configuration needs to change.
12899 starting = topRunningActivityLocked(null);
12900 }
12901
12902 if (starting != null) {
12903 kept = ensureActivityConfigurationLocked(starting, changes);
12904 if (kept) {
12905 // If this didn't result in the starting activity being
12906 // destroyed, then we need to make sure at this point that all
12907 // other activities are made visible.
12908 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12909 + ", ensuring others are correct.");
12910 ensureActivitiesVisibleLocked(starting, changes);
12911 }
12912 }
12913
12914 return kept;
12915 }
12916
12917 private final boolean relaunchActivityLocked(HistoryRecord r,
12918 int changes, boolean andResume) {
12919 List<ResultInfo> results = null;
12920 List<Intent> newIntents = null;
12921 if (andResume) {
12922 results = r.results;
12923 newIntents = r.newIntents;
12924 }
12925 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12926 + " with results=" + results + " newIntents=" + newIntents
12927 + " andResume=" + andResume);
12928 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12929 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12930 r.task.taskId, r.shortComponentName);
12931
12932 r.startFreezingScreenLocked(r.app, 0);
12933
12934 try {
12935 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12936 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080012937 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012938 // Note: don't need to call pauseIfSleepingLocked() here, because
12939 // the caller will only pass in 'andResume' if this activity is
12940 // currently resumed, which implies we aren't sleeping.
12941 } catch (RemoteException e) {
12942 return false;
12943 }
12944
12945 if (andResume) {
12946 r.results = null;
12947 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012948 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012949 }
12950
12951 return true;
12952 }
12953
12954 /**
12955 * Make sure the given activity matches the current configuration. Returns
12956 * false if the activity had to be destroyed. Returns true if the
12957 * configuration is the same, or the activity will remain running as-is
12958 * for whatever reason. Ensures the HistoryRecord is updated with the
12959 * correct configuration and all other bookkeeping is handled.
12960 */
12961 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12962 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012963 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12964 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012965
12966 // Short circuit: if the two configurations are the exact same
12967 // object (the common case), then there is nothing to do.
12968 Configuration newConfig = mConfiguration;
12969 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012970 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12971 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012972 return true;
12973 }
12974
12975 // We don't worry about activities that are finishing.
12976 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012977 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012978 "Configuration doesn't matter in finishing " + r);
12979 r.stopFreezingScreenLocked(false);
12980 return true;
12981 }
12982
12983 // Okay we now are going to make this activity have the new config.
12984 // But then we need to figure out how it needs to deal with that.
12985 Configuration oldConfig = r.configuration;
12986 r.configuration = newConfig;
12987
12988 // If the activity isn't currently running, just leave the new
12989 // configuration and it will pick that up next time it starts.
12990 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012991 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012992 "Configuration doesn't matter not running " + r);
12993 r.stopFreezingScreenLocked(false);
12994 return true;
12995 }
12996
12997 // If the activity isn't persistent, there is a chance we will
12998 // need to restart it.
12999 if (!r.persistent) {
13000
13001 // Figure out what has changed between the two configurations.
13002 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013003 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13004 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013005 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013006 + Integer.toHexString(r.info.configChanges)
13007 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013008 }
13009 if ((changes&(~r.info.configChanges)) != 0) {
13010 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13011 r.configChangeFlags |= changes;
13012 r.startFreezingScreenLocked(r.app, globalChanges);
13013 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013014 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13015 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013016 destroyActivityLocked(r, true);
13017 } else if (r.state == ActivityState.PAUSING) {
13018 // A little annoying: we are waiting for this activity to
13019 // finish pausing. Let's not do anything now, but just
13020 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013021 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13022 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013023 r.configDestroy = true;
13024 return true;
13025 } else if (r.state == ActivityState.RESUMED) {
13026 // Try to optimize this case: the configuration is changing
13027 // and we need to restart the top, resumed activity.
13028 // Instead of doing the normal handshaking, just say
13029 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013030 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13031 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013032 relaunchActivityLocked(r, r.configChangeFlags, true);
13033 r.configChangeFlags = 0;
13034 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013035 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13036 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013037 relaunchActivityLocked(r, r.configChangeFlags, false);
13038 r.configChangeFlags = 0;
13039 }
13040
13041 // All done... tell the caller we weren't able to keep this
13042 // activity around.
13043 return false;
13044 }
13045 }
13046
13047 // Default case: the activity can handle this new configuration, so
13048 // hand it over. Note that we don't need to give it the new
13049 // configuration, since we always send configuration changes to all
13050 // process when they happen so it can just use whatever configuration
13051 // it last got.
13052 if (r.app != null && r.app.thread != null) {
13053 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013054 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013055 r.app.thread.scheduleActivityConfigurationChanged(r);
13056 } catch (RemoteException e) {
13057 // If process died, whatever.
13058 }
13059 }
13060 r.stopFreezingScreenLocked(false);
13061
13062 return true;
13063 }
13064
13065 /**
13066 * Save the locale. You must be inside a synchronized (this) block.
13067 */
13068 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13069 if(isDiff) {
13070 SystemProperties.set("user.language", l.getLanguage());
13071 SystemProperties.set("user.region", l.getCountry());
13072 }
13073
13074 if(isPersist) {
13075 SystemProperties.set("persist.sys.language", l.getLanguage());
13076 SystemProperties.set("persist.sys.country", l.getCountry());
13077 SystemProperties.set("persist.sys.localevar", l.getVariant());
13078 }
13079 }
13080
13081 // =========================================================
13082 // LIFETIME MANAGEMENT
13083 // =========================================================
13084
13085 private final int computeOomAdjLocked(
13086 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13087 if (mAdjSeq == app.adjSeq) {
13088 // This adjustment has already been computed.
13089 return app.curAdj;
13090 }
13091
13092 if (app.thread == null) {
13093 app.adjSeq = mAdjSeq;
13094 return (app.curAdj=EMPTY_APP_ADJ);
13095 }
13096
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013097 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13098 // The max adjustment doesn't allow this app to be anything
13099 // below foreground, so it is not worth doing work for it.
13100 app.adjType = "fixed";
13101 app.adjSeq = mAdjSeq;
13102 app.curRawAdj = app.maxAdj;
13103 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13104 return (app.curAdj=app.maxAdj);
13105 }
13106
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013107 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013108 app.adjSource = null;
13109 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013110
The Android Open Source Project4df24232009-03-05 14:34:35 -080013111 // Determine the importance of the process, starting with most
13112 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013113 int adj;
13114 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013115 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013116 // The last app on the list is the foreground app.
13117 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013118 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013119 } else if (app.instrumentationClass != null) {
13120 // Don't want to kill running instrumentation.
13121 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013122 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013123 } else if (app.persistentActivities > 0) {
13124 // Special persistent activities... shouldn't be used these days.
13125 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013126 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013127 } else if (app.curReceiver != null ||
13128 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13129 // An app that is currently receiving a broadcast also
13130 // counts as being in the foreground.
13131 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013132 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013133 } else if (app.executingServices.size() > 0) {
13134 // An app that is currently executing a service callback also
13135 // counts as being in the foreground.
13136 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013137 app.adjType = "exec-service";
13138 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013139 // The user is aware of this app, so make it visible.
13140 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013141 app.adjType = "foreground-service";
13142 } else if (app.forcingToForeground != null) {
13143 // The user is aware of this app, so make it visible.
13144 adj = VISIBLE_APP_ADJ;
13145 app.adjType = "force-foreground";
13146 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013147 } else if (app == mHomeProcess) {
13148 // This process is hosting what we currently consider to be the
13149 // home app, so we don't want to let it go into the background.
13150 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013151 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013152 } else if ((N=app.activities.size()) != 0) {
13153 // This app is in the background with paused activities.
13154 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013155 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013156 for (int j=0; j<N; j++) {
13157 if (((HistoryRecord)app.activities.get(j)).visible) {
13158 // This app has a visible activity!
13159 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013160 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013161 break;
13162 }
13163 }
13164 } else {
13165 // A very not-needed process.
13166 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013167 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013168 }
13169
The Android Open Source Project4df24232009-03-05 14:34:35 -080013170 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013171 // there are applications dependent on our services or providers, but
13172 // this gives us a baseline and makes sure we don't get into an
13173 // infinite recursion.
13174 app.adjSeq = mAdjSeq;
13175 app.curRawAdj = adj;
13176 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13177
Christopher Tate6fa95972009-06-05 18:43:55 -070013178 if (mBackupTarget != null && app == mBackupTarget.app) {
13179 // If possible we want to avoid killing apps while they're being backed up
13180 if (adj > BACKUP_APP_ADJ) {
13181 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13182 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013183 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013184 }
13185 }
13186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013187 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013188 final long now = SystemClock.uptimeMillis();
13189 // This process is more important if the top activity is
13190 // bound to the service.
13191 Iterator jt = app.services.iterator();
13192 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13193 ServiceRecord s = (ServiceRecord)jt.next();
13194 if (s.startRequested) {
13195 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13196 // This service has seen some activity within
13197 // recent memory, so we will keep its process ahead
13198 // of the background processes.
13199 if (adj > SECONDARY_SERVER_ADJ) {
13200 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013201 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013202 }
13203 }
13204 }
13205 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13206 Iterator<ConnectionRecord> kt
13207 = s.connections.values().iterator();
13208 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13209 // XXX should compute this based on the max of
13210 // all connected clients.
13211 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013212 if (cr.binding.client == app) {
13213 // Binding to ourself is not interesting.
13214 continue;
13215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013216 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13217 ProcessRecord client = cr.binding.client;
13218 int myHiddenAdj = hiddenAdj;
13219 if (myHiddenAdj > client.hiddenAdj) {
13220 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13221 myHiddenAdj = client.hiddenAdj;
13222 } else {
13223 myHiddenAdj = VISIBLE_APP_ADJ;
13224 }
13225 }
13226 int clientAdj = computeOomAdjLocked(
13227 client, myHiddenAdj, TOP_APP);
13228 if (adj > clientAdj) {
13229 adj = clientAdj > VISIBLE_APP_ADJ
13230 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013231 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013232 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13233 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013234 app.adjSource = cr.binding.client;
13235 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013236 }
13237 }
13238 HistoryRecord a = cr.activity;
13239 //if (a != null) {
13240 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13241 //}
13242 if (a != null && adj > FOREGROUND_APP_ADJ &&
13243 (a.state == ActivityState.RESUMED
13244 || a.state == ActivityState.PAUSING)) {
13245 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013246 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013247 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13248 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013249 app.adjSource = a;
13250 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013251 }
13252 }
13253 }
13254 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013255
13256 // Finally, f this process has active services running in it, we
13257 // would like to avoid killing it unless it would prevent the current
13258 // application from running. By default we put the process in
13259 // with the rest of the background processes; as we scan through
13260 // its services we may bump it up from there.
13261 if (adj > hiddenAdj) {
13262 adj = hiddenAdj;
13263 app.adjType = "bg-services";
13264 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013265 }
13266
13267 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013268 Iterator jt = app.pubProviders.values().iterator();
13269 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13270 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13271 if (cpr.clients.size() != 0) {
13272 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13273 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13274 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013275 if (client == app) {
13276 // Being our own client is not interesting.
13277 continue;
13278 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013279 int myHiddenAdj = hiddenAdj;
13280 if (myHiddenAdj > client.hiddenAdj) {
13281 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13282 myHiddenAdj = client.hiddenAdj;
13283 } else {
13284 myHiddenAdj = FOREGROUND_APP_ADJ;
13285 }
13286 }
13287 int clientAdj = computeOomAdjLocked(
13288 client, myHiddenAdj, TOP_APP);
13289 if (adj > clientAdj) {
13290 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013291 ? clientAdj : FOREGROUND_APP_ADJ;
13292 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013293 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13294 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013295 app.adjSource = client;
13296 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013297 }
13298 }
13299 }
13300 // If the provider has external (non-framework) process
13301 // dependencies, ensure that its adjustment is at least
13302 // FOREGROUND_APP_ADJ.
13303 if (cpr.externals != 0) {
13304 if (adj > FOREGROUND_APP_ADJ) {
13305 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013306 app.adjType = "provider";
13307 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013308 }
13309 }
13310 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013311
13312 // Finally, if this process has published any content providers,
13313 // then its adjustment makes it at least as important as any of the
13314 // processes using those providers, and no less important than
13315 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13316 if (adj > CONTENT_PROVIDER_ADJ) {
13317 adj = CONTENT_PROVIDER_ADJ;
13318 app.adjType = "pub-providers";
13319 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013320 }
13321
13322 app.curRawAdj = adj;
13323
13324 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13325 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13326 if (adj > app.maxAdj) {
13327 adj = app.maxAdj;
13328 }
13329
13330 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013331 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013332 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13333 : Process.THREAD_GROUP_DEFAULT;
13334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013335 return adj;
13336 }
13337
13338 /**
13339 * Ask a given process to GC right now.
13340 */
13341 final void performAppGcLocked(ProcessRecord app) {
13342 try {
13343 app.lastRequestedGc = SystemClock.uptimeMillis();
13344 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013345 if (app.reportLowMemory) {
13346 app.reportLowMemory = false;
13347 app.thread.scheduleLowMemory();
13348 } else {
13349 app.thread.processInBackground();
13350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013351 }
13352 } catch (Exception e) {
13353 // whatever.
13354 }
13355 }
13356
13357 /**
13358 * Returns true if things are idle enough to perform GCs.
13359 */
Josh Bartel7f208742010-02-25 11:01:44 -060013360 private final boolean canGcNowLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013361 return mParallelBroadcasts.size() == 0
13362 && mOrderedBroadcasts.size() == 0
13363 && (mSleeping || (mResumedActivity != null &&
13364 mResumedActivity.idle));
13365 }
13366
13367 /**
13368 * Perform GCs on all processes that are waiting for it, but only
13369 * if things are idle.
13370 */
13371 final void performAppGcsLocked() {
13372 final int N = mProcessesToGc.size();
13373 if (N <= 0) {
13374 return;
13375 }
Josh Bartel7f208742010-02-25 11:01:44 -060013376 if (canGcNowLocked()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013377 while (mProcessesToGc.size() > 0) {
13378 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013379 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13380 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13381 <= SystemClock.uptimeMillis()) {
13382 // To avoid spamming the system, we will GC processes one
13383 // at a time, waiting a few seconds between each.
13384 performAppGcLocked(proc);
13385 scheduleAppGcsLocked();
13386 return;
13387 } else {
13388 // It hasn't been long enough since we last GCed this
13389 // process... put it in the list to wait for its time.
13390 addProcessToGcListLocked(proc);
13391 break;
13392 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013393 }
13394 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013395
13396 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013397 }
13398 }
13399
13400 /**
13401 * If all looks good, perform GCs on all processes waiting for them.
13402 */
13403 final void performAppGcsIfAppropriateLocked() {
Josh Bartel7f208742010-02-25 11:01:44 -060013404 if (canGcNowLocked()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013405 performAppGcsLocked();
13406 return;
13407 }
13408 // Still not idle, wait some more.
13409 scheduleAppGcsLocked();
13410 }
13411
13412 /**
13413 * Schedule the execution of all pending app GCs.
13414 */
13415 final void scheduleAppGcsLocked() {
13416 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013417
13418 if (mProcessesToGc.size() > 0) {
13419 // Schedule a GC for the time to the next process.
13420 ProcessRecord proc = mProcessesToGc.get(0);
13421 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13422
13423 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13424 long now = SystemClock.uptimeMillis();
13425 if (when < (now+GC_TIMEOUT)) {
13426 when = now + GC_TIMEOUT;
13427 }
13428 mHandler.sendMessageAtTime(msg, when);
13429 }
13430 }
13431
13432 /**
13433 * Add a process to the array of processes waiting to be GCed. Keeps the
13434 * list in sorted order by the last GC time. The process can't already be
13435 * on the list.
13436 */
13437 final void addProcessToGcListLocked(ProcessRecord proc) {
13438 boolean added = false;
13439 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13440 if (mProcessesToGc.get(i).lastRequestedGc <
13441 proc.lastRequestedGc) {
13442 added = true;
13443 mProcessesToGc.add(i+1, proc);
13444 break;
13445 }
13446 }
13447 if (!added) {
13448 mProcessesToGc.add(0, proc);
13449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013450 }
13451
13452 /**
13453 * Set up to ask a process to GC itself. This will either do it
13454 * immediately, or put it on the list of processes to gc the next
13455 * time things are idle.
13456 */
13457 final void scheduleAppGcLocked(ProcessRecord app) {
13458 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013459 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013460 return;
13461 }
13462 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013463 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013464 scheduleAppGcsLocked();
13465 }
13466 }
13467
13468 private final boolean updateOomAdjLocked(
13469 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13470 app.hiddenAdj = hiddenAdj;
13471
13472 if (app.thread == null) {
13473 return true;
13474 }
13475
13476 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013478 if (app.pid != 0 && app.pid != MY_PID) {
13479 if (app.curRawAdj != app.setRawAdj) {
13480 if (app.curRawAdj > FOREGROUND_APP_ADJ
13481 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13482 // If this app is transitioning from foreground to
13483 // non-foreground, have it do a gc.
13484 scheduleAppGcLocked(app);
13485 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13486 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13487 // Likewise do a gc when an app is moving in to the
13488 // background (such as a service stopping).
13489 scheduleAppGcLocked(app);
13490 }
13491 app.setRawAdj = app.curRawAdj;
13492 }
13493 if (adj != app.setAdj) {
13494 if (Process.setOomAdj(app.pid, adj)) {
13495 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13496 TAG, "Set app " + app.processName +
13497 " oom adj to " + adj);
13498 app.setAdj = adj;
13499 } else {
13500 return false;
13501 }
13502 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013503 if (app.setSchedGroup != app.curSchedGroup) {
13504 app.setSchedGroup = app.curSchedGroup;
13505 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13506 "Setting process group of " + app.processName
13507 + " to " + app.curSchedGroup);
13508 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013509 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013510 try {
13511 Process.setProcessGroup(app.pid, app.curSchedGroup);
13512 } catch (Exception e) {
13513 Log.w(TAG, "Failed setting process group of " + app.pid
13514 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013515 e.printStackTrace();
13516 } finally {
13517 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013518 }
13519 }
13520 if (false) {
13521 if (app.thread != null) {
13522 try {
13523 app.thread.setSchedulingGroup(app.curSchedGroup);
13524 } catch (RemoteException e) {
13525 }
13526 }
13527 }
13528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013529 }
13530
13531 return true;
13532 }
13533
13534 private final HistoryRecord resumedAppLocked() {
13535 HistoryRecord resumedActivity = mResumedActivity;
13536 if (resumedActivity == null || resumedActivity.app == null) {
13537 resumedActivity = mPausingActivity;
13538 if (resumedActivity == null || resumedActivity.app == null) {
13539 resumedActivity = topRunningActivityLocked(null);
13540 }
13541 }
13542 return resumedActivity;
13543 }
13544
13545 private final boolean updateOomAdjLocked(ProcessRecord app) {
13546 final HistoryRecord TOP_ACT = resumedAppLocked();
13547 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13548 int curAdj = app.curAdj;
13549 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13550 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13551
13552 mAdjSeq++;
13553
13554 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13555 if (res) {
13556 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13557 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13558 if (nowHidden != wasHidden) {
13559 // Changed to/from hidden state, so apps after it in the LRU
13560 // list may also be changed.
13561 updateOomAdjLocked();
13562 }
13563 }
13564 return res;
13565 }
13566
13567 private final boolean updateOomAdjLocked() {
13568 boolean didOomAdj = true;
13569 final HistoryRecord TOP_ACT = resumedAppLocked();
13570 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13571
13572 if (false) {
13573 RuntimeException e = new RuntimeException();
13574 e.fillInStackTrace();
13575 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13576 }
13577
13578 mAdjSeq++;
13579
13580 // First try updating the OOM adjustment for each of the
13581 // application processes based on their current state.
13582 int i = mLRUProcesses.size();
13583 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13584 while (i > 0) {
13585 i--;
13586 ProcessRecord app = mLRUProcesses.get(i);
13587 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13588 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13589 && app.curAdj == curHiddenAdj) {
13590 curHiddenAdj++;
13591 }
13592 } else {
13593 didOomAdj = false;
13594 }
13595 }
13596
13597 // todo: for now pretend like OOM ADJ didn't work, because things
13598 // aren't behaving as expected on Linux -- it's not killing processes.
13599 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13600 }
13601
13602 private final void trimApplications() {
13603 synchronized (this) {
13604 int i;
13605
13606 // First remove any unused application processes whose package
13607 // has been removed.
13608 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13609 final ProcessRecord app = mRemovedProcesses.get(i);
13610 if (app.activities.size() == 0
13611 && app.curReceiver == null && app.services.size() == 0) {
13612 Log.i(
13613 TAG, "Exiting empty application process "
13614 + app.processName + " ("
13615 + (app.thread != null ? app.thread.asBinder() : null)
13616 + ")\n");
13617 if (app.pid > 0 && app.pid != MY_PID) {
13618 Process.killProcess(app.pid);
13619 } else {
13620 try {
13621 app.thread.scheduleExit();
13622 } catch (Exception e) {
13623 // Ignore exceptions.
13624 }
13625 }
13626 cleanUpApplicationRecordLocked(app, false, -1);
13627 mRemovedProcesses.remove(i);
13628
13629 if (app.persistent) {
13630 if (app.persistent) {
13631 addAppLocked(app.info);
13632 }
13633 }
13634 }
13635 }
13636
13637 // Now try updating the OOM adjustment for each of the
13638 // application processes based on their current state.
13639 // If the setOomAdj() API is not supported, then go with our
13640 // back-up plan...
13641 if (!updateOomAdjLocked()) {
13642
13643 // Count how many processes are running services.
13644 int numServiceProcs = 0;
13645 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13646 final ProcessRecord app = mLRUProcesses.get(i);
13647
13648 if (app.persistent || app.services.size() != 0
13649 || app.curReceiver != null
13650 || app.persistentActivities > 0) {
13651 // Don't count processes holding services against our
13652 // maximum process count.
13653 if (localLOGV) Log.v(
13654 TAG, "Not trimming app " + app + " with services: "
13655 + app.services);
13656 numServiceProcs++;
13657 }
13658 }
13659
13660 int curMaxProcs = mProcessLimit;
13661 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13662 if (mAlwaysFinishActivities) {
13663 curMaxProcs = 1;
13664 }
13665 curMaxProcs += numServiceProcs;
13666
13667 // Quit as many processes as we can to get down to the desired
13668 // process count. First remove any processes that no longer
13669 // have activites running in them.
13670 for ( i=0;
13671 i<mLRUProcesses.size()
13672 && mLRUProcesses.size() > curMaxProcs;
13673 i++) {
13674 final ProcessRecord app = mLRUProcesses.get(i);
13675 // Quit an application only if it is not currently
13676 // running any activities.
13677 if (!app.persistent && app.activities.size() == 0
13678 && app.curReceiver == null && app.services.size() == 0) {
13679 Log.i(
13680 TAG, "Exiting empty application process "
13681 + app.processName + " ("
13682 + (app.thread != null ? app.thread.asBinder() : null)
13683 + ")\n");
13684 if (app.pid > 0 && app.pid != MY_PID) {
13685 Process.killProcess(app.pid);
13686 } else {
13687 try {
13688 app.thread.scheduleExit();
13689 } catch (Exception e) {
13690 // Ignore exceptions.
13691 }
13692 }
13693 // todo: For now we assume the application is not buggy
13694 // or evil, and will quit as a result of our request.
13695 // Eventually we need to drive this off of the death
13696 // notification, and kill the process if it takes too long.
13697 cleanUpApplicationRecordLocked(app, false, i);
13698 i--;
13699 }
13700 }
13701
13702 // If we still have too many processes, now from the least
13703 // recently used process we start finishing activities.
13704 if (Config.LOGV) Log.v(
13705 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13706 " of " + curMaxProcs + " processes");
13707 for ( i=0;
13708 i<mLRUProcesses.size()
13709 && mLRUProcesses.size() > curMaxProcs;
13710 i++) {
13711 final ProcessRecord app = mLRUProcesses.get(i);
13712 // Quit the application only if we have a state saved for
13713 // all of its activities.
13714 boolean canQuit = !app.persistent && app.curReceiver == null
13715 && app.services.size() == 0
13716 && app.persistentActivities == 0;
13717 int NUMA = app.activities.size();
13718 int j;
13719 if (Config.LOGV) Log.v(
13720 TAG, "Looking to quit " + app.processName);
13721 for (j=0; j<NUMA && canQuit; j++) {
13722 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13723 if (Config.LOGV) Log.v(
13724 TAG, " " + r.intent.getComponent().flattenToShortString()
13725 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13726 canQuit = (r.haveState || !r.stateNotNeeded)
13727 && !r.visible && r.stopped;
13728 }
13729 if (canQuit) {
13730 // Finish all of the activities, and then the app itself.
13731 for (j=0; j<NUMA; j++) {
13732 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13733 if (!r.finishing) {
13734 destroyActivityLocked(r, false);
13735 }
13736 r.resultTo = null;
13737 }
13738 Log.i(TAG, "Exiting application process "
13739 + app.processName + " ("
13740 + (app.thread != null ? app.thread.asBinder() : null)
13741 + ")\n");
13742 if (app.pid > 0 && app.pid != MY_PID) {
13743 Process.killProcess(app.pid);
13744 } else {
13745 try {
13746 app.thread.scheduleExit();
13747 } catch (Exception e) {
13748 // Ignore exceptions.
13749 }
13750 }
13751 // todo: For now we assume the application is not buggy
13752 // or evil, and will quit as a result of our request.
13753 // Eventually we need to drive this off of the death
13754 // notification, and kill the process if it takes too long.
13755 cleanUpApplicationRecordLocked(app, false, i);
13756 i--;
13757 //dump();
13758 }
13759 }
13760
13761 }
13762
13763 int curMaxActivities = MAX_ACTIVITIES;
13764 if (mAlwaysFinishActivities) {
13765 curMaxActivities = 1;
13766 }
13767
13768 // Finally, if there are too many activities now running, try to
13769 // finish as many as we can to get back down to the limit.
13770 for ( i=0;
13771 i<mLRUActivities.size()
13772 && mLRUActivities.size() > curMaxActivities;
13773 i++) {
13774 final HistoryRecord r
13775 = (HistoryRecord)mLRUActivities.get(i);
13776
13777 // We can finish this one if we have its icicle saved and
13778 // it is not persistent.
13779 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13780 && r.stopped && !r.persistent && !r.finishing) {
13781 final int origSize = mLRUActivities.size();
13782 destroyActivityLocked(r, true);
13783
13784 // This will remove it from the LRU list, so keep
13785 // our index at the same value. Note that this check to
13786 // see if the size changes is just paranoia -- if
13787 // something unexpected happens, we don't want to end up
13788 // in an infinite loop.
13789 if (origSize > mLRUActivities.size()) {
13790 i--;
13791 }
13792 }
13793 }
13794 }
13795 }
13796
13797 /** This method sends the specified signal to each of the persistent apps */
13798 public void signalPersistentProcesses(int sig) throws RemoteException {
13799 if (sig != Process.SIGNAL_USR1) {
13800 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13801 }
13802
13803 synchronized (this) {
13804 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13805 != PackageManager.PERMISSION_GRANTED) {
13806 throw new SecurityException("Requires permission "
13807 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13808 }
13809
13810 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13811 ProcessRecord r = mLRUProcesses.get(i);
13812 if (r.thread != null && r.persistent) {
13813 Process.sendSignal(r.pid, sig);
13814 }
13815 }
13816 }
13817 }
13818
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013819 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013820 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013821
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013822 try {
13823 synchronized (this) {
13824 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13825 // its own permission.
13826 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13827 != PackageManager.PERMISSION_GRANTED) {
13828 throw new SecurityException("Requires permission "
13829 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013830 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013831
13832 if (start && fd == null) {
13833 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013834 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013835
13836 ProcessRecord proc = null;
13837 try {
13838 int pid = Integer.parseInt(process);
13839 synchronized (mPidsSelfLocked) {
13840 proc = mPidsSelfLocked.get(pid);
13841 }
13842 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013843 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013844
13845 if (proc == null) {
13846 HashMap<String, SparseArray<ProcessRecord>> all
13847 = mProcessNames.getMap();
13848 SparseArray<ProcessRecord> procs = all.get(process);
13849 if (procs != null && procs.size() > 0) {
13850 proc = procs.valueAt(0);
13851 }
13852 }
13853
13854 if (proc == null || proc.thread == null) {
13855 throw new IllegalArgumentException("Unknown process: " + process);
13856 }
13857
13858 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13859 if (isSecure) {
13860 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13861 throw new SecurityException("Process not debuggable: " + proc);
13862 }
13863 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013864
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013865 proc.thread.profilerControl(start, path, fd);
13866 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013867 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013868 }
13869 } catch (RemoteException e) {
13870 throw new IllegalStateException("Process disappeared");
13871 } finally {
13872 if (fd != null) {
13873 try {
13874 fd.close();
13875 } catch (IOException e) {
13876 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013877 }
13878 }
13879 }
13880
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013881 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13882 public void monitor() {
13883 synchronized (this) { }
13884 }
13885}