blob: 7f12b6dc81de75a5f4869658b8f9c103f822621a [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
Dianne Hackborndd71fc82009-12-16 19:24:32 -080028import dalvik.system.Zygote;
29
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.app.Activity;
31import android.app.ActivityManager;
32import android.app.ActivityManagerNative;
33import android.app.ActivityThread;
34import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020035import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070037import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.app.IActivityWatcher;
39import android.app.IApplicationThread;
40import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.app.IServiceConnection;
42import android.app.IThumbnailReceiver;
43import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070044import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.app.PendingIntent;
46import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070047import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070048import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020049import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.content.ComponentName;
51import android.content.ContentResolver;
52import android.content.Context;
53import android.content.Intent;
54import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070055import android.content.IIntentReceiver;
56import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070057import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.content.pm.ActivityInfo;
59import android.content.pm.ApplicationInfo;
60import android.content.pm.ConfigurationInfo;
61import android.content.pm.IPackageDataObserver;
62import android.content.pm.IPackageManager;
63import android.content.pm.InstrumentationInfo;
64import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070065import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.content.pm.ProviderInfo;
67import android.content.pm.ResolveInfo;
68import android.content.pm.ServiceInfo;
69import android.content.res.Configuration;
70import android.graphics.Bitmap;
71import android.net.Uri;
72import android.os.Binder;
73import android.os.Bundle;
Dan Egnor60d87622009-12-16 16:32:58 -080074import android.os.Build;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070075import android.os.Debug;
Dan Egnor60d87622009-12-16 16:32:58 -080076import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.os.Environment;
78import android.os.FileUtils;
79import android.os.Handler;
80import android.os.IBinder;
81import android.os.IPermissionController;
82import android.os.Looper;
83import android.os.Message;
84import android.os.Parcel;
85import android.os.ParcelFileDescriptor;
86import android.os.PowerManager;
87import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070088import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.os.RemoteException;
90import android.os.ServiceManager;
91import android.os.SystemClock;
92import android.os.SystemProperties;
93import android.provider.Checkin;
94import android.provider.Settings;
95import android.text.TextUtils;
96import android.util.Config;
97import android.util.EventLog;
98import android.util.Log;
99import android.util.PrintWriterPrinter;
100import android.util.SparseArray;
101import android.view.Gravity;
102import android.view.LayoutInflater;
103import android.view.View;
104import android.view.WindowManager;
105import android.view.WindowManagerPolicy;
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import java.io.File;
108import java.io.FileDescriptor;
109import java.io.FileInputStream;
110import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200111import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112import java.io.PrintWriter;
113import java.lang.IllegalStateException;
114import java.lang.ref.WeakReference;
115import java.util.ArrayList;
116import java.util.HashMap;
117import java.util.HashSet;
118import java.util.Iterator;
119import java.util.List;
120import java.util.Locale;
121import java.util.Map;
122
123public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
124 static final String TAG = "ActivityManager";
125 static final boolean DEBUG = false;
126 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
127 static final boolean DEBUG_SWITCH = localLOGV || false;
128 static final boolean DEBUG_TASKS = localLOGV || false;
129 static final boolean DEBUG_PAUSE = localLOGV || false;
130 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
131 static final boolean DEBUG_TRANSITION = localLOGV || false;
132 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700133 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 static final boolean DEBUG_SERVICE = localLOGV || false;
135 static final boolean DEBUG_VISBILITY = localLOGV || false;
136 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700137 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700139 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700140 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700141 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 static final boolean VALIDATE_TOKENS = false;
143 static final boolean SHOW_ACTIVITY_START_TIME = true;
144
145 // Control over CPU and battery monitoring.
146 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
147 static final boolean MONITOR_CPU_USAGE = true;
148 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
149 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
150 static final boolean MONITOR_THREAD_CPU_USAGE = false;
151
Dianne Hackborn1655be42009-05-08 14:29:01 -0700152 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700153 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 private static final String SYSTEM_SECURE = "ro.secure";
156
157 // This is the maximum number of application processes we would like
158 // to have running. Due to the asynchronous nature of things, we can
159 // temporarily go beyond this limit.
160 static final int MAX_PROCESSES = 2;
161
162 // Set to false to leave processes running indefinitely, relying on
163 // the kernel killing them as resources are required.
164 static final boolean ENFORCE_PROCESS_LIMIT = false;
165
166 // This is the maximum number of activities that we would like to have
167 // running at a given time.
168 static final int MAX_ACTIVITIES = 20;
169
170 // Maximum number of recent tasks that we can remember.
171 static final int MAX_RECENT_TASKS = 20;
172
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700173 // Amount of time after a call to stopAppSwitches() during which we will
174 // prevent further untrusted switches from happening.
175 static final long APP_SWITCH_DELAY_TIME = 5*1000;
176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 // How long until we reset a task when the user returns to it. Currently
178 // 30 minutes.
179 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
180
181 // Set to true to disable the icon that is shown while a new activity
182 // is being started.
183 static final boolean SHOW_APP_STARTING_ICON = true;
184
185 // How long we wait until giving up on the last activity to pause. This
186 // is short because it directly impacts the responsiveness of starting the
187 // next activity.
188 static final int PAUSE_TIMEOUT = 500;
189
190 /**
191 * How long we can hold the launch wake lock before giving up.
192 */
193 static final int LAUNCH_TIMEOUT = 10*1000;
194
195 // How long we wait for a launched process to attach to the activity manager
196 // before we decide it's never going to come up for real.
197 static final int PROC_START_TIMEOUT = 10*1000;
198
199 // How long we wait until giving up on the last activity telling us it
200 // is idle.
201 static final int IDLE_TIMEOUT = 10*1000;
202
203 // How long to wait after going idle before forcing apps to GC.
204 static final int GC_TIMEOUT = 5*1000;
205
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700206 // The minimum amount of time between successive GC requests for a process.
207 static final int GC_MIN_INTERVAL = 60*1000;
208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 // How long we wait until giving up on an activity telling us it has
210 // finished destroying itself.
211 static final int DESTROY_TIMEOUT = 10*1000;
212
213 // How long we allow a receiver to run before giving up on it.
214 static final int BROADCAST_TIMEOUT = 10*1000;
215
216 // How long we wait for a service to finish executing.
217 static final int SERVICE_TIMEOUT = 20*1000;
218
219 // How long a service needs to be running until restarting its process
220 // is no longer considered to be a relaunch of the service.
221 static final int SERVICE_RESTART_DURATION = 5*1000;
222
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700223 // How long a service needs to be running until it will start back at
224 // SERVICE_RESTART_DURATION after being killed.
225 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
226
227 // Multiplying factor to increase restart duration time by, for each time
228 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
229 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
230
231 // The minimum amount of time between restarting services that we allow.
232 // That is, when multiple services are restarting, we won't allow each
233 // to restart less than this amount of time from the last one.
234 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 // Maximum amount of time for there to be no activity on a service before
237 // we consider it non-essential and allow its process to go on the
238 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700239 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
241 // How long we wait until we timeout on key dispatching.
242 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
243
244 // The minimum time we allow between crashes, for us to consider this
245 // application to be bad and stop and its services and reject broadcasts.
246 static final int MIN_CRASH_INTERVAL = 60*1000;
247
248 // How long we wait until we timeout on key dispatching during instrumentation.
249 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
250
251 // OOM adjustments for processes in various states:
252
253 // This is a process without anything currently running in it. Definitely
254 // the first to go! Value set in system/rootdir/init.rc on startup.
255 // This value is initalized in the constructor, careful when refering to
256 // this static variable externally.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800257 static final int EMPTY_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
259 // This is a process only hosting activities that are not visible,
260 // so it can be killed without any disruption. Value set in
261 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800262 static final int HIDDEN_APP_MAX_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 static int HIDDEN_APP_MIN_ADJ;
264
The Android Open Source Project4df24232009-03-05 14:34:35 -0800265 // This is a process holding the home application -- we want to try
266 // avoiding killing it, even if it would normally be in the background,
267 // because the user interacts with it so much.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800268 static final int HOME_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800269
Christopher Tate6fa95972009-06-05 18:43:55 -0700270 // This is a process currently hosting a backup operation. Killing it
271 // is not entirely fatal but is generally a bad idea.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800272 static final int BACKUP_APP_ADJ;
Christopher Tate6fa95972009-06-05 18:43:55 -0700273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 // This is a process holding a secondary server -- killing it will not
275 // have much of an impact as far as the user is concerned. Value set in
276 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800277 static final int SECONDARY_SERVER_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278
279 // This is a process only hosting activities that are visible to the
280 // user, so we'd prefer they don't disappear. Value set in
281 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800282 static final int VISIBLE_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283
284 // This is the process running the current foreground app. We'd really
285 // rather not kill it! Value set in system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800286 static final int FOREGROUND_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287
288 // This is a process running a core server, such as telephony. Definitely
289 // don't want to kill it, but doing so is not completely fatal.
290 static final int CORE_SERVER_ADJ = -12;
291
292 // The system process runs at the default adjustment.
293 static final int SYSTEM_ADJ = -16;
294
295 // Memory pages are 4K.
296 static final int PAGE_SIZE = 4*1024;
297
Jacek Surazski82a73df2009-06-17 14:33:18 +0200298 // System property defining error report receiver for system apps
299 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
300
301 // System property defining default error report receiver
302 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 // Corresponding memory levels for above adjustments.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800305 static final int EMPTY_APP_MEM;
306 static final int HIDDEN_APP_MEM;
307 static final int HOME_APP_MEM;
308 static final int BACKUP_APP_MEM;
309 static final int SECONDARY_SERVER_MEM;
310 static final int VISIBLE_APP_MEM;
311 static final int FOREGROUND_APP_MEM;
312
313 // The minimum number of hidden apps we want to be able to keep around,
314 // without empty apps being able to push them out of memory.
315 static final int MIN_HIDDEN_APPS = 2;
316
317 // We put empty content processes after any hidden processes that have
318 // been idle for less than 30 seconds.
319 static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
320
321 // We put empty content processes after any hidden processes that have
322 // been idle for less than 60 seconds.
323 static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
324
325 static {
326 // These values are set in system/rootdir/init.rc on startup.
327 FOREGROUND_APP_ADJ =
328 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
329 VISIBLE_APP_ADJ =
330 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
331 SECONDARY_SERVER_ADJ =
332 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
333 BACKUP_APP_ADJ =
334 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
335 HOME_APP_ADJ =
336 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
337 HIDDEN_APP_MIN_ADJ =
338 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
339 EMPTY_APP_ADJ =
340 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
341 HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
342 FOREGROUND_APP_MEM =
343 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
344 VISIBLE_APP_MEM =
345 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
346 SECONDARY_SERVER_MEM =
347 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
348 BACKUP_APP_MEM =
349 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
350 HOME_APP_MEM =
351 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
352 HIDDEN_APP_MEM =
353 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
354 EMPTY_APP_MEM =
355 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
356 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357
358 final int MY_PID;
359
360 static final String[] EMPTY_STRING_ARRAY = new String[0];
361
362 enum ActivityState {
363 INITIALIZING,
364 RESUMED,
365 PAUSING,
366 PAUSED,
367 STOPPING,
368 STOPPED,
369 FINISHING,
370 DESTROYING,
371 DESTROYED
372 }
373
374 /**
375 * The back history of all previous (and possibly still
376 * running) activities. It contains HistoryRecord objects.
377 */
378 final ArrayList mHistory = new ArrayList();
379
380 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700381 * Description of a request to start a new activity, which has been held
382 * due to app switches being disabled.
383 */
384 class PendingActivityLaunch {
385 HistoryRecord r;
386 HistoryRecord sourceRecord;
387 Uri[] grantedUriPermissions;
388 int grantedMode;
389 boolean onlyIfNeeded;
390 }
391
392 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
393 = new ArrayList<PendingActivityLaunch>();
394
395 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 * List of all active broadcasts that are to be executed immediately
397 * (without waiting for another broadcast to finish). Currently this only
398 * contains broadcasts to registered receivers, to avoid spinning up
399 * a bunch of processes to execute IntentReceiver components.
400 */
401 final ArrayList<BroadcastRecord> mParallelBroadcasts
402 = new ArrayList<BroadcastRecord>();
403
404 /**
405 * List of all active broadcasts that are to be executed one at a time.
406 * The object at the top of the list is the currently activity broadcasts;
407 * those after it are waiting for the top to finish..
408 */
409 final ArrayList<BroadcastRecord> mOrderedBroadcasts
410 = new ArrayList<BroadcastRecord>();
411
412 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800413 * Historical data of past broadcasts, for debugging.
414 */
415 static final int MAX_BROADCAST_HISTORY = 100;
416 final BroadcastRecord[] mBroadcastHistory
417 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
418
419 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 * Set when we current have a BROADCAST_INTENT_MSG in flight.
421 */
422 boolean mBroadcastsScheduled = false;
423
424 /**
425 * Set to indicate whether to issue an onUserLeaving callback when a
426 * newly launched activity is being brought in front of us.
427 */
428 boolean mUserLeaving = false;
429
430 /**
431 * When we are in the process of pausing an activity, before starting the
432 * next one, this variable holds the activity that is currently being paused.
433 */
434 HistoryRecord mPausingActivity = null;
435
436 /**
437 * Current activity that is resumed, or null if there is none.
438 */
439 HistoryRecord mResumedActivity = null;
440
441 /**
442 * Activity we have told the window manager to have key focus.
443 */
444 HistoryRecord mFocusedActivity = null;
445
446 /**
447 * This is the last activity that we put into the paused state. This is
448 * used to determine if we need to do an activity transition while sleeping,
449 * when we normally hold the top activity paused.
450 */
451 HistoryRecord mLastPausedActivity = null;
452
453 /**
454 * List of activities that are waiting for a new activity
455 * to become visible before completing whatever operation they are
456 * supposed to do.
457 */
458 final ArrayList mWaitingVisibleActivities = new ArrayList();
459
460 /**
461 * List of activities that are ready to be stopped, but waiting
462 * for the next activity to settle down before doing so. It contains
463 * HistoryRecord objects.
464 */
465 final ArrayList<HistoryRecord> mStoppingActivities
466 = new ArrayList<HistoryRecord>();
467
468 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700469 * Animations that for the current transition have requested not to
470 * be considered for the transition animation.
471 */
472 final ArrayList<HistoryRecord> mNoAnimActivities
473 = new ArrayList<HistoryRecord>();
474
475 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 * List of intents that were used to start the most recent tasks.
477 */
478 final ArrayList<TaskRecord> mRecentTasks
479 = new ArrayList<TaskRecord>();
480
481 /**
482 * List of activities that are ready to be finished, but waiting
483 * for the previous activity to settle down before doing so. It contains
484 * HistoryRecord objects.
485 */
486 final ArrayList mFinishingActivities = new ArrayList();
487
488 /**
489 * All of the applications we currently have running organized by name.
490 * The keys are strings of the application package name (as
491 * returned by the package manager), and the keys are ApplicationRecord
492 * objects.
493 */
494 final ProcessMap<ProcessRecord> mProcessNames
495 = new ProcessMap<ProcessRecord>();
496
497 /**
498 * The last time that various processes have crashed.
499 */
500 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
501
502 /**
503 * Set of applications that we consider to be bad, and will reject
504 * incoming broadcasts from (which the user has no control over).
505 * Processes are added to this set when they have crashed twice within
506 * a minimum amount of time; they are removed from it when they are
507 * later restarted (hopefully due to some user action). The value is the
508 * time it was added to the list.
509 */
510 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
511
512 /**
513 * All of the processes we currently have running organized by pid.
514 * The keys are the pid running the application.
515 *
516 * <p>NOTE: This object is protected by its own lock, NOT the global
517 * activity manager lock!
518 */
519 final SparseArray<ProcessRecord> mPidsSelfLocked
520 = new SparseArray<ProcessRecord>();
521
522 /**
523 * All of the processes that have been forced to be foreground. The key
524 * is the pid of the caller who requested it (we hold a death
525 * link on it).
526 */
527 abstract class ForegroundToken implements IBinder.DeathRecipient {
528 int pid;
529 IBinder token;
530 }
531 final SparseArray<ForegroundToken> mForegroundProcesses
532 = new SparseArray<ForegroundToken>();
533
534 /**
535 * List of records for processes that someone had tried to start before the
536 * system was ready. We don't start them at that point, but ensure they
537 * are started by the time booting is complete.
538 */
539 final ArrayList<ProcessRecord> mProcessesOnHold
540 = new ArrayList<ProcessRecord>();
541
542 /**
543 * List of records for processes that we have started and are waiting
544 * for them to call back. This is really only needed when running in
545 * single processes mode, in which case we do not have a unique pid for
546 * each process.
547 */
548 final ArrayList<ProcessRecord> mStartingProcesses
549 = new ArrayList<ProcessRecord>();
550
551 /**
552 * List of persistent applications that are in the process
553 * of being started.
554 */
555 final ArrayList<ProcessRecord> mPersistentStartingProcesses
556 = new ArrayList<ProcessRecord>();
557
558 /**
559 * Processes that are being forcibly torn down.
560 */
561 final ArrayList<ProcessRecord> mRemovedProcesses
562 = new ArrayList<ProcessRecord>();
563
564 /**
565 * List of running applications, sorted by recent usage.
566 * The first entry in the list is the least recently used.
567 * It contains ApplicationRecord objects. This list does NOT include
568 * any persistent application records (since we never want to exit them).
569 */
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800570 final ArrayList<ProcessRecord> mLruProcesses
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 = new ArrayList<ProcessRecord>();
572
573 /**
574 * List of processes that should gc as soon as things are idle.
575 */
576 final ArrayList<ProcessRecord> mProcessesToGc
577 = new ArrayList<ProcessRecord>();
578
579 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800580 * This is the process holding what we currently consider to be
581 * the "home" activity.
582 */
583 private ProcessRecord mHomeProcess;
584
585 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 * List of running activities, sorted by recent usage.
587 * The first entry in the list is the least recently used.
588 * It contains HistoryRecord objects.
589 */
590 private final ArrayList mLRUActivities = new ArrayList();
591
592 /**
593 * Set of PendingResultRecord objects that are currently active.
594 */
595 final HashSet mPendingResultRecords = new HashSet();
596
597 /**
598 * Set of IntentSenderRecord objects that are currently active.
599 */
600 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
601 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
602
603 /**
604 * Intent broadcast that we have tried to start, but are
605 * waiting for its application's process to be created. We only
606 * need one (instead of a list) because we always process broadcasts
607 * one at a time, so no others can be started while waiting for this
608 * one.
609 */
610 BroadcastRecord mPendingBroadcast = null;
611
612 /**
613 * Keeps track of all IIntentReceivers that have been registered for
614 * broadcasts. Hash keys are the receiver IBinder, hash value is
615 * a ReceiverList.
616 */
617 final HashMap mRegisteredReceivers = new HashMap();
618
619 /**
620 * Resolver for broadcast intents to registered receivers.
621 * Holds BroadcastFilter (subclass of IntentFilter).
622 */
623 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
624 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
625 @Override
626 protected boolean allowFilterResult(
627 BroadcastFilter filter, List<BroadcastFilter> dest) {
628 IBinder target = filter.receiverList.receiver.asBinder();
629 for (int i=dest.size()-1; i>=0; i--) {
630 if (dest.get(i).receiverList.receiver.asBinder() == target) {
631 return false;
632 }
633 }
634 return true;
635 }
636 };
637
638 /**
639 * State of all active sticky broadcasts. Keys are the action of the
640 * sticky Intent, values are an ArrayList of all broadcasted intents with
641 * that action (which should usually be one).
642 */
643 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
644 new HashMap<String, ArrayList<Intent>>();
645
646 /**
647 * All currently running services.
648 */
649 final HashMap<ComponentName, ServiceRecord> mServices =
650 new HashMap<ComponentName, ServiceRecord>();
651
652 /**
653 * All currently running services indexed by the Intent used to start them.
654 */
655 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
656 new HashMap<Intent.FilterComparison, ServiceRecord>();
657
658 /**
659 * All currently bound service connections. Keys are the IBinder of
660 * the client's IServiceConnection.
661 */
662 final HashMap<IBinder, ConnectionRecord> mServiceConnections
663 = new HashMap<IBinder, ConnectionRecord>();
664
665 /**
666 * List of services that we have been asked to start,
667 * but haven't yet been able to. It is used to hold start requests
668 * while waiting for their corresponding application thread to get
669 * going.
670 */
671 final ArrayList<ServiceRecord> mPendingServices
672 = new ArrayList<ServiceRecord>();
673
674 /**
675 * List of services that are scheduled to restart following a crash.
676 */
677 final ArrayList<ServiceRecord> mRestartingServices
678 = new ArrayList<ServiceRecord>();
679
680 /**
681 * List of services that are in the process of being stopped.
682 */
683 final ArrayList<ServiceRecord> mStoppingServices
684 = new ArrayList<ServiceRecord>();
685
686 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700687 * Backup/restore process management
688 */
689 String mBackupAppName = null;
690 BackupRecord mBackupTarget = null;
691
692 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 * List of PendingThumbnailsRecord objects of clients who are still
694 * waiting to receive all of the thumbnails for a task.
695 */
696 final ArrayList mPendingThumbnails = new ArrayList();
697
698 /**
699 * List of HistoryRecord objects that have been finished and must
700 * still report back to a pending thumbnail receiver.
701 */
702 final ArrayList mCancelledThumbnails = new ArrayList();
703
704 /**
705 * All of the currently running global content providers. Keys are a
706 * string containing the provider name and values are a
707 * ContentProviderRecord object containing the data about it. Note
708 * that a single provider may be published under multiple names, so
709 * there may be multiple entries here for a single one in mProvidersByClass.
710 */
711 final HashMap mProvidersByName = new HashMap();
712
713 /**
714 * All of the currently running global content providers. Keys are a
715 * string containing the provider's implementation class and values are a
716 * ContentProviderRecord object containing the data about it.
717 */
718 final HashMap mProvidersByClass = new HashMap();
719
720 /**
721 * List of content providers who have clients waiting for them. The
722 * application is currently being launched and the provider will be
723 * removed from this list once it is published.
724 */
725 final ArrayList mLaunchingProviders = new ArrayList();
726
727 /**
728 * Global set of specific Uri permissions that have been granted.
729 */
730 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
731 = new SparseArray<HashMap<Uri, UriPermission>>();
732
733 /**
734 * Thread-local storage used to carry caller permissions over through
735 * indirect content-provider access.
736 * @see #ActivityManagerService.openContentUri()
737 */
738 private class Identity {
739 public int pid;
740 public int uid;
741
742 Identity(int _pid, int _uid) {
743 pid = _pid;
744 uid = _uid;
745 }
746 }
747 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
748
749 /**
750 * All information we have collected about the runtime performance of
751 * any user id that can impact battery performance.
752 */
753 final BatteryStatsService mBatteryStatsService;
754
755 /**
756 * information about component usage
757 */
758 final UsageStatsService mUsageStatsService;
759
760 /**
761 * Current configuration information. HistoryRecord objects are given
762 * a reference to this object to indicate which configuration they are
763 * currently running in, so this object must be kept immutable.
764 */
765 Configuration mConfiguration = new Configuration();
766
767 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700768 * Hardware-reported OpenGLES version.
769 */
770 final int GL_ES_VERSION;
771
772 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 * List of initialization arguments to pass to all processes when binding applications to them.
774 * For example, references to the commonly used services.
775 */
776 HashMap<String, IBinder> mAppBindArgs;
777
778 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700779 * Temporary to avoid allocations. Protected by main lock.
780 */
781 final StringBuilder mStringBuilder = new StringBuilder(256);
782
783 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 * Used to control how we initialize the service.
785 */
786 boolean mStartRunning = false;
787 ComponentName mTopComponent;
788 String mTopAction;
789 String mTopData;
790 boolean mSystemReady = false;
791 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700792 boolean mWaitingUpdate = false;
793 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794
795 Context mContext;
796
797 int mFactoryTest;
798
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700799 boolean mCheckedForSetup;
800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700802 * The time at which we will allow normal application switches again,
803 * after a call to {@link #stopAppSwitches()}.
804 */
805 long mAppSwitchesAllowedTime;
806
807 /**
808 * This is set to true after the first switch after mAppSwitchesAllowedTime
809 * is set; any switches after that will clear the time.
810 */
811 boolean mDidAppSwitch;
812
813 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 * Set while we are wanting to sleep, to prevent any
815 * activities from being started/resumed.
816 */
817 boolean mSleeping = false;
818
819 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700820 * Set if we are shutting down the system, similar to sleeping.
821 */
822 boolean mShuttingDown = false;
823
824 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 * Set when the system is going to sleep, until we have
826 * successfully paused the current activity and released our wake lock.
827 * At that point the system is allowed to actually sleep.
828 */
829 PowerManager.WakeLock mGoingToSleep;
830
831 /**
832 * We don't want to allow the device to go to sleep while in the process
833 * of launching an activity. This is primarily to allow alarm intent
834 * receivers to launch an activity and get that to run before the device
835 * goes back to sleep.
836 */
837 PowerManager.WakeLock mLaunchingActivity;
838
839 /**
840 * Task identifier that activities are currently being started
841 * in. Incremented each time a new task is created.
842 * todo: Replace this with a TokenSpace class that generates non-repeating
843 * integers that won't wrap.
844 */
845 int mCurTask = 1;
846
847 /**
848 * Current sequence id for oom_adj computation traversal.
849 */
850 int mAdjSeq = 0;
851
852 /**
853 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
854 * is set, indicating the user wants processes started in such a way
855 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
856 * running in each process (thus no pre-initialized process, etc).
857 */
858 boolean mSimpleProcessManagement = false;
859
860 /**
861 * System monitoring: number of processes that died since the last
862 * N procs were started.
863 */
864 int[] mProcDeaths = new int[20];
865
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700866 /**
867 * This is set if we had to do a delayed dexopt of an app before launching
868 * it, to increasing the ANR timeouts in that case.
869 */
870 boolean mDidDexOpt;
871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 String mDebugApp = null;
873 boolean mWaitForDebugger = false;
874 boolean mDebugTransient = false;
875 String mOrigDebugApp = null;
876 boolean mOrigWaitForDebugger = false;
877 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700878 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700880 final RemoteCallbackList<IActivityWatcher> mWatchers
881 = new RemoteCallbackList<IActivityWatcher>();
882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 /**
884 * Callback of last caller to {@link #requestPss}.
885 */
886 Runnable mRequestPssCallback;
887
888 /**
889 * Remaining processes for which we are waiting results from the last
890 * call to {@link #requestPss}.
891 */
892 final ArrayList<ProcessRecord> mRequestPssList
893 = new ArrayList<ProcessRecord>();
894
895 /**
896 * Runtime statistics collection thread. This object's lock is used to
897 * protect all related state.
898 */
899 final Thread mProcessStatsThread;
900
901 /**
902 * Used to collect process stats when showing not responding dialog.
903 * Protected by mProcessStatsThread.
904 */
905 final ProcessStats mProcessStats = new ProcessStats(
906 MONITOR_THREAD_CPU_USAGE);
907 long mLastCpuTime = 0;
908 long mLastWriteTime = 0;
909
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700910 long mInitialStartTime = 0;
911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 /**
913 * Set to true after the system has finished booting.
914 */
915 boolean mBooted = false;
916
917 int mProcessLimit = 0;
918
919 WindowManagerService mWindowManager;
920
921 static ActivityManagerService mSelf;
922 static ActivityThread mSystemThread;
923
924 private final class AppDeathRecipient implements IBinder.DeathRecipient {
925 final ProcessRecord mApp;
926 final int mPid;
927 final IApplicationThread mAppThread;
928
929 AppDeathRecipient(ProcessRecord app, int pid,
930 IApplicationThread thread) {
931 if (localLOGV) Log.v(
932 TAG, "New death recipient " + this
933 + " for thread " + thread.asBinder());
934 mApp = app;
935 mPid = pid;
936 mAppThread = thread;
937 }
938
939 public void binderDied() {
940 if (localLOGV) Log.v(
941 TAG, "Death received in " + this
942 + " for thread " + mAppThread.asBinder());
943 removeRequestedPss(mApp);
944 synchronized(ActivityManagerService.this) {
945 appDiedLocked(mApp, mPid, mAppThread);
946 }
947 }
948 }
949
950 static final int SHOW_ERROR_MSG = 1;
951 static final int SHOW_NOT_RESPONDING_MSG = 2;
952 static final int SHOW_FACTORY_ERROR_MSG = 3;
953 static final int UPDATE_CONFIGURATION_MSG = 4;
954 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
955 static final int WAIT_FOR_DEBUGGER_MSG = 6;
956 static final int BROADCAST_INTENT_MSG = 7;
957 static final int BROADCAST_TIMEOUT_MSG = 8;
958 static final int PAUSE_TIMEOUT_MSG = 9;
959 static final int IDLE_TIMEOUT_MSG = 10;
960 static final int IDLE_NOW_MSG = 11;
961 static final int SERVICE_TIMEOUT_MSG = 12;
962 static final int UPDATE_TIME_ZONE = 13;
963 static final int SHOW_UID_ERROR_MSG = 14;
964 static final int IM_FEELING_LUCKY_MSG = 15;
965 static final int LAUNCH_TIMEOUT_MSG = 16;
966 static final int DESTROY_TIMEOUT_MSG = 17;
967 static final int SERVICE_ERROR_MSG = 18;
968 static final int RESUME_TOP_ACTIVITY_MSG = 19;
969 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700970 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700971 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972
973 AlertDialog mUidAlert;
974
975 final Handler mHandler = new Handler() {
976 //public Handler() {
977 // if (localLOGV) Log.v(TAG, "Handler started!");
978 //}
979
980 public void handleMessage(Message msg) {
981 switch (msg.what) {
982 case SHOW_ERROR_MSG: {
983 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 synchronized (ActivityManagerService.this) {
985 ProcessRecord proc = (ProcessRecord)data.get("app");
986 if (proc != null && proc.crashDialog != null) {
987 Log.e(TAG, "App already has crash dialog: " + proc);
988 return;
989 }
990 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700991 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -0800992 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 d.show();
994 proc.crashDialog = d;
995 } else {
996 // The device is asleep, so just pretend that the user
997 // saw a crash dialog and hit "force quit".
998 res.set(0);
999 }
1000 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001001
1002 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 } break;
1004 case SHOW_NOT_RESPONDING_MSG: {
1005 synchronized (ActivityManagerService.this) {
1006 HashMap data = (HashMap) msg.obj;
1007 ProcessRecord proc = (ProcessRecord)data.get("app");
1008 if (proc != null && proc.anrDialog != null) {
1009 Log.e(TAG, "App already has anr dialog: " + proc);
1010 return;
1011 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001012
1013 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1014 null, null, 0, null, null, null,
1015 false, false, MY_PID, Process.SYSTEM_UID);
1016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1018 mContext, proc, (HistoryRecord)data.get("activity"));
1019 d.show();
1020 proc.anrDialog = d;
1021 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001022
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001023 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 } break;
1025 case SHOW_FACTORY_ERROR_MSG: {
1026 Dialog d = new FactoryErrorDialog(
1027 mContext, msg.getData().getCharSequence("msg"));
1028 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001029 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 } break;
1031 case UPDATE_CONFIGURATION_MSG: {
1032 final ContentResolver resolver = mContext.getContentResolver();
1033 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1034 } break;
1035 case GC_BACKGROUND_PROCESSES_MSG: {
1036 synchronized (ActivityManagerService.this) {
1037 performAppGcsIfAppropriateLocked();
1038 }
1039 } break;
1040 case WAIT_FOR_DEBUGGER_MSG: {
1041 synchronized (ActivityManagerService.this) {
1042 ProcessRecord app = (ProcessRecord)msg.obj;
1043 if (msg.arg1 != 0) {
1044 if (!app.waitedForDebugger) {
1045 Dialog d = new AppWaitingForDebuggerDialog(
1046 ActivityManagerService.this,
1047 mContext, app);
1048 app.waitDialog = d;
1049 app.waitedForDebugger = true;
1050 d.show();
1051 }
1052 } else {
1053 if (app.waitDialog != null) {
1054 app.waitDialog.dismiss();
1055 app.waitDialog = null;
1056 }
1057 }
1058 }
1059 } break;
1060 case BROADCAST_INTENT_MSG: {
1061 if (DEBUG_BROADCAST) Log.v(
1062 TAG, "Received BROADCAST_INTENT_MSG");
1063 processNextBroadcast(true);
1064 } break;
1065 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001066 if (mDidDexOpt) {
1067 mDidDexOpt = false;
1068 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1069 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1070 return;
1071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 broadcastTimeout();
1073 } break;
1074 case PAUSE_TIMEOUT_MSG: {
1075 IBinder token = (IBinder)msg.obj;
1076 // We don't at this point know if the activity is fullscreen,
1077 // so we need to be conservative and assume it isn't.
1078 Log.w(TAG, "Activity pause timeout for " + token);
1079 activityPaused(token, null, true);
1080 } break;
1081 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001082 if (mDidDexOpt) {
1083 mDidDexOpt = false;
1084 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1085 nmsg.obj = msg.obj;
1086 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1087 return;
1088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 // We don't at this point know if the activity is fullscreen,
1090 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001091 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001093 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 } break;
1095 case DESTROY_TIMEOUT_MSG: {
1096 IBinder token = (IBinder)msg.obj;
1097 // We don't at this point know if the activity is fullscreen,
1098 // so we need to be conservative and assume it isn't.
1099 Log.w(TAG, "Activity destroy timeout for " + token);
1100 activityDestroyed(token);
1101 } break;
1102 case IDLE_NOW_MSG: {
1103 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001104 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 } break;
1106 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001107 if (mDidDexOpt) {
1108 mDidDexOpt = false;
1109 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1110 nmsg.obj = msg.obj;
1111 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1112 return;
1113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 serviceTimeout((ProcessRecord)msg.obj);
1115 } break;
1116 case UPDATE_TIME_ZONE: {
1117 synchronized (ActivityManagerService.this) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001118 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
1119 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 if (r.thread != null) {
1121 try {
1122 r.thread.updateTimeZone();
1123 } catch (RemoteException ex) {
1124 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1125 }
1126 }
1127 }
1128 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001129 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 case SHOW_UID_ERROR_MSG: {
1131 // XXX This is a temporary dialog, no need to localize.
1132 AlertDialog d = new BaseErrorDialog(mContext);
1133 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1134 d.setCancelable(false);
1135 d.setTitle("System UIDs Inconsistent");
1136 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1137 d.setButton("I'm Feeling Lucky",
1138 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1139 mUidAlert = d;
1140 d.show();
1141 } break;
1142 case IM_FEELING_LUCKY_MSG: {
1143 if (mUidAlert != null) {
1144 mUidAlert.dismiss();
1145 mUidAlert = null;
1146 }
1147 } break;
1148 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001149 if (mDidDexOpt) {
1150 mDidDexOpt = false;
1151 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1152 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1153 return;
1154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 synchronized (ActivityManagerService.this) {
1156 if (mLaunchingActivity.isHeld()) {
1157 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1158 mLaunchingActivity.release();
1159 }
1160 }
1161 } break;
1162 case SERVICE_ERROR_MSG: {
1163 ServiceRecord srv = (ServiceRecord)msg.obj;
1164 // This needs to be *un*synchronized to avoid deadlock.
1165 Checkin.logEvent(mContext.getContentResolver(),
1166 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1167 srv.name.toShortString());
1168 } break;
1169 case RESUME_TOP_ACTIVITY_MSG: {
1170 synchronized (ActivityManagerService.this) {
1171 resumeTopActivityLocked(null);
1172 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001173 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001175 if (mDidDexOpt) {
1176 mDidDexOpt = false;
1177 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1178 nmsg.obj = msg.obj;
1179 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1180 return;
1181 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 ProcessRecord app = (ProcessRecord)msg.obj;
1183 synchronized (ActivityManagerService.this) {
1184 processStartTimedOutLocked(app);
1185 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001186 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001187 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1188 synchronized (ActivityManagerService.this) {
1189 doPendingActivityLaunchesLocked(true);
1190 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001191 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001192 case KILL_APPLICATION_MSG: {
1193 synchronized (ActivityManagerService.this) {
1194 int uid = msg.arg1;
1195 boolean restart = (msg.arg2 == 1);
1196 String pkg = (String) msg.obj;
Dianne Hackborn03abb812010-01-04 18:43:19 -08001197 forceStopPackageLocked(pkg, uid, restart);
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001198 }
1199 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 }
1201 }
1202 };
1203
1204 public static void setSystemProcess() {
1205 try {
1206 ActivityManagerService m = mSelf;
1207
1208 ServiceManager.addService("activity", m);
1209 ServiceManager.addService("meminfo", new MemBinder(m));
1210 if (MONITOR_CPU_USAGE) {
1211 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1212 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 ServiceManager.addService("permission", new PermissionController(m));
1214
1215 ApplicationInfo info =
1216 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001217 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001218 mSystemThread.installSystemApplicationInfo(info);
1219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 synchronized (mSelf) {
1221 ProcessRecord app = mSelf.newProcessRecordLocked(
1222 mSystemThread.getApplicationThread(), info,
1223 info.processName);
1224 app.persistent = true;
1225 app.pid = Process.myPid();
1226 app.maxAdj = SYSTEM_ADJ;
1227 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1228 synchronized (mSelf.mPidsSelfLocked) {
1229 mSelf.mPidsSelfLocked.put(app.pid, app);
1230 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001231 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 }
1233 } catch (PackageManager.NameNotFoundException e) {
1234 throw new RuntimeException(
1235 "Unable to find android system package", e);
1236 }
1237 }
1238
1239 public void setWindowManager(WindowManagerService wm) {
1240 mWindowManager = wm;
1241 }
1242
1243 public static final Context main(int factoryTest) {
1244 AThread thr = new AThread();
1245 thr.start();
1246
1247 synchronized (thr) {
1248 while (thr.mService == null) {
1249 try {
1250 thr.wait();
1251 } catch (InterruptedException e) {
1252 }
1253 }
1254 }
1255
1256 ActivityManagerService m = thr.mService;
1257 mSelf = m;
1258 ActivityThread at = ActivityThread.systemMain();
1259 mSystemThread = at;
1260 Context context = at.getSystemContext();
1261 m.mContext = context;
1262 m.mFactoryTest = factoryTest;
1263 PowerManager pm =
1264 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1265 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1266 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1267 m.mLaunchingActivity.setReferenceCounted(false);
1268
1269 m.mBatteryStatsService.publish(context);
1270 m.mUsageStatsService.publish(context);
1271
1272 synchronized (thr) {
1273 thr.mReady = true;
1274 thr.notifyAll();
1275 }
1276
1277 m.startRunning(null, null, null, null);
1278
1279 return context;
1280 }
1281
1282 public static ActivityManagerService self() {
1283 return mSelf;
1284 }
1285
1286 static class AThread extends Thread {
1287 ActivityManagerService mService;
1288 boolean mReady = false;
1289
1290 public AThread() {
1291 super("ActivityManager");
1292 }
1293
1294 public void run() {
1295 Looper.prepare();
1296
1297 android.os.Process.setThreadPriority(
1298 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1299
1300 ActivityManagerService m = new ActivityManagerService();
1301
1302 synchronized (this) {
1303 mService = m;
1304 notifyAll();
1305 }
1306
1307 synchronized (this) {
1308 while (!mReady) {
1309 try {
1310 wait();
1311 } catch (InterruptedException e) {
1312 }
1313 }
1314 }
1315
1316 Looper.loop();
1317 }
1318 }
1319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 static class MemBinder extends Binder {
1321 ActivityManagerService mActivityManagerService;
1322 MemBinder(ActivityManagerService activityManagerService) {
1323 mActivityManagerService = activityManagerService;
1324 }
1325
1326 @Override
1327 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1328 ActivityManagerService service = mActivityManagerService;
1329 ArrayList<ProcessRecord> procs;
1330 synchronized (mActivityManagerService) {
1331 if (args != null && args.length > 0
1332 && args[0].charAt(0) != '-') {
1333 procs = new ArrayList<ProcessRecord>();
1334 int pid = -1;
1335 try {
1336 pid = Integer.parseInt(args[0]);
1337 } catch (NumberFormatException e) {
1338
1339 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001340 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1341 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 if (proc.pid == pid) {
1343 procs.add(proc);
1344 } else if (proc.processName.equals(args[0])) {
1345 procs.add(proc);
1346 }
1347 }
1348 if (procs.size() <= 0) {
1349 pw.println("No process found for: " + args[0]);
1350 return;
1351 }
1352 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001353 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 }
1355 }
1356 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1357 }
1358 }
1359
1360 static class CpuBinder extends Binder {
1361 ActivityManagerService mActivityManagerService;
1362 CpuBinder(ActivityManagerService activityManagerService) {
1363 mActivityManagerService = activityManagerService;
1364 }
1365
1366 @Override
1367 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1368 synchronized (mActivityManagerService.mProcessStatsThread) {
1369 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1370 }
1371 }
1372 }
1373
1374 private ActivityManagerService() {
1375 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1376 if (v != null && Integer.getInteger(v) != 0) {
1377 mSimpleProcessManagement = true;
1378 }
1379 v = System.getenv("ANDROID_DEBUG_APP");
1380 if (v != null) {
1381 mSimpleProcessManagement = true;
1382 }
1383
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001384 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 MY_PID = Process.myPid();
1387
1388 File dataDir = Environment.getDataDirectory();
1389 File systemDir = new File(dataDir, "system");
1390 systemDir.mkdirs();
1391 mBatteryStatsService = new BatteryStatsService(new File(
1392 systemDir, "batterystats.bin").toString());
1393 mBatteryStatsService.getActiveStatistics().readLocked();
1394 mBatteryStatsService.getActiveStatistics().writeLocked();
1395
1396 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001397 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398
Jack Palevichb90d28c2009-07-22 15:35:24 -07001399 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1400 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 mConfiguration.makeDefault();
1403 mProcessStats.init();
1404
1405 // Add ourself to the Watchdog monitors.
1406 Watchdog.getInstance().addMonitor(this);
1407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 mProcessStatsThread = new Thread("ProcessStats") {
1409 public void run() {
1410 while (true) {
1411 try {
1412 try {
1413 synchronized(this) {
1414 final long now = SystemClock.uptimeMillis();
1415 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1416 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1417 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1418 // + ", write delay=" + nextWriteDelay);
1419 if (nextWriteDelay < nextCpuDelay) {
1420 nextCpuDelay = nextWriteDelay;
1421 }
1422 if (nextCpuDelay > 0) {
1423 this.wait(nextCpuDelay);
1424 }
1425 }
1426 } catch (InterruptedException e) {
1427 }
1428
1429 updateCpuStatsNow();
1430 } catch (Exception e) {
1431 Log.e(TAG, "Unexpected exception collecting process stats", e);
1432 }
1433 }
1434 }
1435 };
1436 mProcessStatsThread.start();
1437 }
1438
1439 @Override
1440 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1441 throws RemoteException {
1442 try {
1443 return super.onTransact(code, data, reply, flags);
1444 } catch (RuntimeException e) {
1445 // The activity manager only throws security exceptions, so let's
1446 // log all others.
1447 if (!(e instanceof SecurityException)) {
1448 Log.e(TAG, "Activity Manager Crash", e);
1449 }
1450 throw e;
1451 }
1452 }
1453
1454 void updateCpuStats() {
1455 synchronized (mProcessStatsThread) {
1456 final long now = SystemClock.uptimeMillis();
1457 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1458 mProcessStatsThread.notify();
1459 }
1460 }
1461 }
1462
1463 void updateCpuStatsNow() {
1464 synchronized (mProcessStatsThread) {
1465 final long now = SystemClock.uptimeMillis();
1466 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 if (MONITOR_CPU_USAGE &&
1469 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1470 mLastCpuTime = now;
1471 haveNewCpuStats = true;
1472 mProcessStats.update();
1473 //Log.i(TAG, mProcessStats.printCurrentState());
1474 //Log.i(TAG, "Total CPU usage: "
1475 // + mProcessStats.getTotalCpuPercent() + "%");
1476
1477 // Log the cpu usage if the property is set.
1478 if ("true".equals(SystemProperties.get("events.cpu"))) {
1479 int user = mProcessStats.getLastUserTime();
1480 int system = mProcessStats.getLastSystemTime();
1481 int iowait = mProcessStats.getLastIoWaitTime();
1482 int irq = mProcessStats.getLastIrqTime();
1483 int softIrq = mProcessStats.getLastSoftIrqTime();
1484 int idle = mProcessStats.getLastIdleTime();
1485
1486 int total = user + system + iowait + irq + softIrq + idle;
1487 if (total == 0) total = 1;
1488
Doug Zongker2bec3d42009-12-04 12:52:44 -08001489 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 ((user+system+iowait+irq+softIrq) * 100) / total,
1491 (user * 100) / total,
1492 (system * 100) / total,
1493 (iowait * 100) / total,
1494 (irq * 100) / total,
1495 (softIrq * 100) / total);
1496 }
1497 }
1498
Amith Yamasanie43530a2009-08-21 13:11:37 -07001499 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001500 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001501 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 synchronized(mPidsSelfLocked) {
1503 if (haveNewCpuStats) {
1504 if (mBatteryStatsService.isOnBattery()) {
1505 final int N = mProcessStats.countWorkingStats();
1506 for (int i=0; i<N; i++) {
1507 ProcessStats.Stats st
1508 = mProcessStats.getWorkingStats(i);
1509 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1510 if (pr != null) {
1511 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1512 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001513 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001514 } else {
1515 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001516 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001517 if (ps != null) {
1518 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001519 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 }
1522 }
1523 }
1524 }
1525 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1528 mLastWriteTime = now;
1529 mBatteryStatsService.getActiveStatistics().writeLocked();
1530 }
1531 }
1532 }
1533 }
1534
1535 /**
1536 * Initialize the application bind args. These are passed to each
1537 * process when the bindApplication() IPC is sent to the process. They're
1538 * lazily setup to make sure the services are running when they're asked for.
1539 */
1540 private HashMap<String, IBinder> getCommonServicesLocked() {
1541 if (mAppBindArgs == null) {
1542 mAppBindArgs = new HashMap<String, IBinder>();
1543
1544 // Setup the application init args
1545 mAppBindArgs.put("package", ServiceManager.getService("package"));
1546 mAppBindArgs.put("window", ServiceManager.getService("window"));
1547 mAppBindArgs.put(Context.ALARM_SERVICE,
1548 ServiceManager.getService(Context.ALARM_SERVICE));
1549 }
1550 return mAppBindArgs;
1551 }
1552
1553 private final void setFocusedActivityLocked(HistoryRecord r) {
1554 if (mFocusedActivity != r) {
1555 mFocusedActivity = r;
1556 mWindowManager.setFocusedApp(r, true);
1557 }
1558 }
1559
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001560 private final void updateLruProcessLocked(ProcessRecord app,
1561 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001563 int lrui = mLruProcesses.indexOf(app);
1564 if (lrui >= 0) mLruProcesses.remove(lrui);
1565
1566 int i = mLruProcesses.size()-1;
1567 int skipTop = 0;
1568
1569 // compute the new weight for this process.
1570 if (updateActivityTime) {
1571 app.lastActivityTime = SystemClock.uptimeMillis();
1572 }
1573 if (app.activities.size() > 0) {
1574 // If this process has activities, we more strongly want to keep
1575 // it around.
1576 app.lruWeight = app.lastActivityTime;
1577 } else if (app.pubProviders.size() > 0) {
1578 // If this process contains content providers, we want to keep
1579 // it a little more strongly.
1580 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1581 // Also don't let it kick out the first few "real" hidden processes.
1582 skipTop = MIN_HIDDEN_APPS;
1583 } else {
1584 // If this process doesn't have activities, we less strongly
1585 // want to keep it around, and generally want to avoid getting
1586 // in front of any very recently used activities.
1587 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1588 // Also don't let it kick out the first few "real" hidden processes.
1589 skipTop = MIN_HIDDEN_APPS;
1590 }
1591 while (i >= 0) {
1592 ProcessRecord p = mLruProcesses.get(i);
1593 // If this app shouldn't be in front of the first N background
1594 // apps, then skip over that many that are currently hidden.
1595 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1596 skipTop--;
1597 }
1598 if (p.lruWeight <= app.lruWeight){
1599 mLruProcesses.add(i+1, app);
1600 break;
1601 }
1602 i--;
1603 }
1604 if (i < 0) {
1605 mLruProcesses.add(0, app);
1606 }
1607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 //Log.i(TAG, "Putting proc to front: " + app.processName);
1609 if (oomAdj) {
1610 updateOomAdjLocked();
1611 }
1612 }
1613
1614 private final boolean updateLRUListLocked(HistoryRecord r) {
1615 final boolean hadit = mLRUActivities.remove(r);
1616 mLRUActivities.add(r);
1617 return hadit;
1618 }
1619
1620 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1621 int i = mHistory.size()-1;
1622 while (i >= 0) {
1623 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1624 if (!r.finishing && r != notTop) {
1625 return r;
1626 }
1627 i--;
1628 }
1629 return null;
1630 }
1631
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001632 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1633 int i = mHistory.size()-1;
1634 while (i >= 0) {
1635 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1636 if (!r.finishing && !r.delayedResume && r != notTop) {
1637 return r;
1638 }
1639 i--;
1640 }
1641 return null;
1642 }
1643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 /**
1645 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001646 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 *
1648 * @param token If non-null, any history records matching this token will be skipped.
1649 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1650 *
1651 * @return Returns the HistoryRecord of the next activity on the stack.
1652 */
1653 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1654 int i = mHistory.size()-1;
1655 while (i >= 0) {
1656 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1657 // Note: the taskId check depends on real taskId fields being non-zero
1658 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1659 return r;
1660 }
1661 i--;
1662 }
1663 return null;
1664 }
1665
1666 private final ProcessRecord getProcessRecordLocked(
1667 String processName, int uid) {
1668 if (uid == Process.SYSTEM_UID) {
1669 // The system gets to run in any process. If there are multiple
1670 // processes with the same uid, just pick the first (this
1671 // should never happen).
1672 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1673 processName);
1674 return procs != null ? procs.valueAt(0) : null;
1675 }
1676 ProcessRecord proc = mProcessNames.get(processName, uid);
1677 return proc;
1678 }
1679
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001680 private void ensurePackageDexOpt(String packageName) {
1681 IPackageManager pm = ActivityThread.getPackageManager();
1682 try {
1683 if (pm.performDexOpt(packageName)) {
1684 mDidDexOpt = true;
1685 }
1686 } catch (RemoteException e) {
1687 }
1688 }
1689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 private boolean isNextTransitionForward() {
1691 int transit = mWindowManager.getPendingAppTransition();
1692 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1693 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1694 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1695 }
1696
1697 private final boolean realStartActivityLocked(HistoryRecord r,
1698 ProcessRecord app, boolean andResume, boolean checkConfig)
1699 throws RemoteException {
1700
1701 r.startFreezingScreenLocked(app, 0);
1702 mWindowManager.setAppVisibility(r, true);
1703
1704 // Have the window manager re-evaluate the orientation of
1705 // the screen based on the new activity order. Note that
1706 // as a result of this, it can call back into the activity
1707 // manager with a new orientation. We don't care about that,
1708 // because the activity is not currently running so we are
1709 // just restarting it anyway.
1710 if (checkConfig) {
1711 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001712 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 r.mayFreezeScreenLocked(app) ? r : null);
1714 updateConfigurationLocked(config, r);
1715 }
1716
1717 r.app = app;
1718
1719 if (localLOGV) Log.v(TAG, "Launching: " + r);
1720
1721 int idx = app.activities.indexOf(r);
1722 if (idx < 0) {
1723 app.activities.add(r);
1724 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001725 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726
1727 try {
1728 if (app.thread == null) {
1729 throw new RemoteException();
1730 }
1731 List<ResultInfo> results = null;
1732 List<Intent> newIntents = null;
1733 if (andResume) {
1734 results = r.results;
1735 newIntents = r.newIntents;
1736 }
1737 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1738 + " icicle=" + r.icicle
1739 + " with results=" + results + " newIntents=" + newIntents
1740 + " andResume=" + andResume);
1741 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001742 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 System.identityHashCode(r),
1744 r.task.taskId, r.shortComponentName);
1745 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001746 if (r.isHomeActivity) {
1747 mHomeProcess = app;
1748 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001749 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001751 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 r.info, r.icicle, results, newIntents, !andResume,
1753 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 } catch (RemoteException e) {
1755 if (r.launchFailed) {
1756 // This is the second time we failed -- finish activity
1757 // and give up.
1758 Log.e(TAG, "Second failure launching "
1759 + r.intent.getComponent().flattenToShortString()
1760 + ", giving up", e);
1761 appDiedLocked(app, app.pid, app.thread);
1762 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1763 "2nd-crash");
1764 return false;
1765 }
1766
1767 // This is the first time we failed -- restart process and
1768 // retry.
1769 app.activities.remove(r);
1770 throw e;
1771 }
1772
1773 r.launchFailed = false;
1774 if (updateLRUListLocked(r)) {
1775 Log.w(TAG, "Activity " + r
1776 + " being launched, but already in LRU list");
1777 }
1778
1779 if (andResume) {
1780 // As part of the process of launching, ActivityThread also performs
1781 // a resume.
1782 r.state = ActivityState.RESUMED;
1783 r.icicle = null;
1784 r.haveState = false;
1785 r.stopped = false;
1786 mResumedActivity = r;
1787 r.task.touchActiveTime();
1788 completeResumeLocked(r);
1789 pauseIfSleepingLocked();
1790 } else {
1791 // This activity is not starting in the resumed state... which
1792 // should look like we asked it to pause+stop (but remain visible),
1793 // and it has done so and reported back the current icicle and
1794 // other state.
1795 r.state = ActivityState.STOPPED;
1796 r.stopped = true;
1797 }
1798
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001799 // Launch the new version setup screen if needed. We do this -after-
1800 // launching the initial activity (that is, home), so that it can have
1801 // a chance to initialize itself while in the background, making the
1802 // switch back to it faster and look better.
1803 startSetupActivityLocked();
1804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 return true;
1806 }
1807
1808 private final void startSpecificActivityLocked(HistoryRecord r,
1809 boolean andResume, boolean checkConfig) {
1810 // Is this activity's application already running?
1811 ProcessRecord app = getProcessRecordLocked(r.processName,
1812 r.info.applicationInfo.uid);
1813
1814 if (r.startTime == 0) {
1815 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001816 if (mInitialStartTime == 0) {
1817 mInitialStartTime = r.startTime;
1818 }
1819 } else if (mInitialStartTime == 0) {
1820 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 }
1822
1823 if (app != null && app.thread != null) {
1824 try {
1825 realStartActivityLocked(r, app, andResume, checkConfig);
1826 return;
1827 } catch (RemoteException e) {
1828 Log.w(TAG, "Exception when starting activity "
1829 + r.intent.getComponent().flattenToShortString(), e);
1830 }
1831
1832 // If a dead object exception was thrown -- fall through to
1833 // restart the application.
1834 }
1835
1836 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001837 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 }
1839
1840 private final ProcessRecord startProcessLocked(String processName,
1841 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001842 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1844 // We don't have to do anything more if:
1845 // (1) There is an existing application record; and
1846 // (2) The caller doesn't think it is dead, OR there is no thread
1847 // object attached to it so we know it couldn't have crashed; and
1848 // (3) There is a pid assigned to it, so it is either starting or
1849 // already running.
1850 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1851 + " app=" + app + " knownToBeDead=" + knownToBeDead
1852 + " thread=" + (app != null ? app.thread : null)
1853 + " pid=" + (app != null ? app.pid : -1));
1854 if (app != null &&
1855 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1856 return app;
1857 }
1858
1859 String hostingNameStr = hostingName != null
1860 ? hostingName.flattenToShortString() : null;
1861
1862 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1863 // If we are in the background, then check to see if this process
1864 // is bad. If so, we will just silently fail.
1865 if (mBadProcesses.get(info.processName, info.uid) != null) {
1866 return null;
1867 }
1868 } else {
1869 // When the user is explicitly starting a process, then clear its
1870 // crash count so that we won't make it bad until they see at
1871 // least one crash dialog again, and make the process good again
1872 // if it had been bad.
1873 mProcessCrashTimes.remove(info.processName, info.uid);
1874 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001875 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 info.processName);
1877 mBadProcesses.remove(info.processName, info.uid);
1878 if (app != null) {
1879 app.bad = false;
1880 }
1881 }
1882 }
1883
1884 if (app == null) {
1885 app = newProcessRecordLocked(null, info, processName);
1886 mProcessNames.put(processName, info.uid, app);
1887 } else {
1888 // If this is a new package in the process, add the package to the list
1889 app.addPackage(info.packageName);
1890 }
1891
1892 // If the system is not ready yet, then hold off on starting this
1893 // process until it is.
1894 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001895 && !isAllowedWhileBooting(info)
1896 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 if (!mProcessesOnHold.contains(app)) {
1898 mProcessesOnHold.add(app);
1899 }
1900 return app;
1901 }
1902
1903 startProcessLocked(app, hostingType, hostingNameStr);
1904 return (app.pid != 0) ? app : null;
1905 }
1906
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001907 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1908 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1909 }
1910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 private final void startProcessLocked(ProcessRecord app,
1912 String hostingType, String hostingNameStr) {
1913 if (app.pid > 0 && app.pid != MY_PID) {
1914 synchronized (mPidsSelfLocked) {
1915 mPidsSelfLocked.remove(app.pid);
1916 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1917 }
1918 app.pid = 0;
1919 }
1920
1921 mProcessesOnHold.remove(app);
1922
1923 updateCpuStats();
1924
1925 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1926 mProcDeaths[0] = 0;
1927
1928 try {
1929 int uid = app.info.uid;
1930 int[] gids = null;
1931 try {
1932 gids = mContext.getPackageManager().getPackageGids(
1933 app.info.packageName);
1934 } catch (PackageManager.NameNotFoundException e) {
1935 Log.w(TAG, "Unable to retrieve gids", e);
1936 }
1937 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1938 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1939 && mTopComponent != null
1940 && app.processName.equals(mTopComponent.getPackageName())) {
1941 uid = 0;
1942 }
1943 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1944 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1945 uid = 0;
1946 }
1947 }
1948 int debugFlags = 0;
1949 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1950 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1951 }
1952 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1953 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1954 }
1955 if ("1".equals(SystemProperties.get("debug.assert"))) {
1956 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1957 }
1958 int pid = Process.start("android.app.ActivityThread",
1959 mSimpleProcessManagement ? app.processName : null, uid, uid,
1960 gids, debugFlags, null);
1961 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1962 synchronized (bs) {
1963 if (bs.isOnBattery()) {
1964 app.batteryStats.incStartsLocked();
1965 }
1966 }
1967
Doug Zongker2bec3d42009-12-04 12:52:44 -08001968 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 app.processName, hostingType,
1970 hostingNameStr != null ? hostingNameStr : "");
1971
1972 if (app.persistent) {
1973 Watchdog.getInstance().processStarted(app, app.processName, pid);
1974 }
1975
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001976 StringBuilder buf = mStringBuilder;
1977 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 buf.append("Start proc ");
1979 buf.append(app.processName);
1980 buf.append(" for ");
1981 buf.append(hostingType);
1982 if (hostingNameStr != null) {
1983 buf.append(" ");
1984 buf.append(hostingNameStr);
1985 }
1986 buf.append(": pid=");
1987 buf.append(pid);
1988 buf.append(" uid=");
1989 buf.append(uid);
1990 buf.append(" gids={");
1991 if (gids != null) {
1992 for (int gi=0; gi<gids.length; gi++) {
1993 if (gi != 0) buf.append(", ");
1994 buf.append(gids[gi]);
1995
1996 }
1997 }
1998 buf.append("}");
1999 Log.i(TAG, buf.toString());
2000 if (pid == 0 || pid == MY_PID) {
2001 // Processes are being emulated with threads.
2002 app.pid = MY_PID;
2003 app.removed = false;
2004 mStartingProcesses.add(app);
2005 } else if (pid > 0) {
2006 app.pid = pid;
2007 app.removed = false;
2008 synchronized (mPidsSelfLocked) {
2009 this.mPidsSelfLocked.put(pid, app);
2010 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2011 msg.obj = app;
2012 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2013 }
2014 } else {
2015 app.pid = 0;
2016 RuntimeException e = new RuntimeException(
2017 "Failure starting process " + app.processName
2018 + ": returned pid=" + pid);
2019 Log.e(TAG, e.getMessage(), e);
2020 }
2021 } catch (RuntimeException e) {
2022 // XXX do better error recovery.
2023 app.pid = 0;
2024 Log.e(TAG, "Failure starting process " + app.processName, e);
2025 }
2026 }
2027
2028 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2029 if (mPausingActivity != null) {
2030 RuntimeException e = new RuntimeException();
2031 Log.e(TAG, "Trying to pause when pause is already pending for "
2032 + mPausingActivity, e);
2033 }
2034 HistoryRecord prev = mResumedActivity;
2035 if (prev == null) {
2036 RuntimeException e = new RuntimeException();
2037 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2038 resumeTopActivityLocked(null);
2039 return;
2040 }
2041 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2042 mResumedActivity = null;
2043 mPausingActivity = prev;
2044 mLastPausedActivity = prev;
2045 prev.state = ActivityState.PAUSING;
2046 prev.task.touchActiveTime();
2047
2048 updateCpuStats();
2049
2050 if (prev.app != null && prev.app.thread != null) {
2051 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2052 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002053 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 System.identityHashCode(prev),
2055 prev.shortComponentName);
2056 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2057 prev.configChangeFlags);
2058 updateUsageStats(prev, false);
2059 } catch (Exception e) {
2060 // Ignore exception, if process died other code will cleanup.
2061 Log.w(TAG, "Exception thrown during pause", e);
2062 mPausingActivity = null;
2063 mLastPausedActivity = null;
2064 }
2065 } else {
2066 mPausingActivity = null;
2067 mLastPausedActivity = null;
2068 }
2069
2070 // If we are not going to sleep, we want to ensure the device is
2071 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002072 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 mLaunchingActivity.acquire();
2074 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2075 // To be safe, don't allow the wake lock to be held for too long.
2076 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2077 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2078 }
2079 }
2080
2081
2082 if (mPausingActivity != null) {
2083 // Have the window manager pause its key dispatching until the new
2084 // activity has started. If we're pausing the activity just because
2085 // the screen is being turned off and the UI is sleeping, don't interrupt
2086 // key dispatch; the same activity will pick it up again on wakeup.
2087 if (!uiSleeping) {
2088 prev.pauseKeyDispatchingLocked();
2089 } else {
2090 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2091 }
2092
2093 // Schedule a pause timeout in case the app doesn't respond.
2094 // We don't give it much time because this directly impacts the
2095 // responsiveness seen by the user.
2096 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2097 msg.obj = prev;
2098 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2099 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2100 } else {
2101 // This activity failed to schedule the
2102 // pause, so just treat it as being paused now.
2103 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2104 resumeTopActivityLocked(null);
2105 }
2106 }
2107
2108 private final void completePauseLocked() {
2109 HistoryRecord prev = mPausingActivity;
2110 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2111
2112 if (prev != null) {
2113 if (prev.finishing) {
2114 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2115 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2116 } else if (prev.app != null) {
2117 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2118 if (prev.waitingVisible) {
2119 prev.waitingVisible = false;
2120 mWaitingVisibleActivities.remove(prev);
2121 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2122 TAG, "Complete pause, no longer waiting: " + prev);
2123 }
2124 if (prev.configDestroy) {
2125 // The previous is being paused because the configuration
2126 // is changing, which means it is actually stopping...
2127 // To juggle the fact that we are also starting a new
2128 // instance right now, we need to first completely stop
2129 // the current instance before starting the new one.
2130 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2131 destroyActivityLocked(prev, true);
2132 } else {
2133 mStoppingActivities.add(prev);
2134 if (mStoppingActivities.size() > 3) {
2135 // If we already have a few activities waiting to stop,
2136 // then give up on things going idle and start clearing
2137 // them out.
2138 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2139 Message msg = Message.obtain();
2140 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2141 mHandler.sendMessage(msg);
2142 }
2143 }
2144 } else {
2145 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2146 prev = null;
2147 }
2148 mPausingActivity = null;
2149 }
2150
Dianne Hackborn55280a92009-05-07 15:53:46 -07002151 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 resumeTopActivityLocked(prev);
2153 } else {
2154 if (mGoingToSleep.isHeld()) {
2155 mGoingToSleep.release();
2156 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002157 if (mShuttingDown) {
2158 notifyAll();
2159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 }
2161
2162 if (prev != null) {
2163 prev.resumeKeyDispatchingLocked();
2164 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002165
2166 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2167 long diff = 0;
2168 synchronized (mProcessStatsThread) {
2169 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2170 }
2171 if (diff > 0) {
2172 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2173 synchronized (bsi) {
2174 BatteryStatsImpl.Uid.Proc ps =
2175 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2176 prev.info.packageName);
2177 if (ps != null) {
2178 ps.addForegroundTimeLocked(diff);
2179 }
2180 }
2181 }
2182 }
2183 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 }
2185
2186 /**
2187 * Once we know that we have asked an application to put an activity in
2188 * the resumed state (either by launching it or explicitly telling it),
2189 * this function updates the rest of our state to match that fact.
2190 */
2191 private final void completeResumeLocked(HistoryRecord next) {
2192 next.idle = false;
2193 next.results = null;
2194 next.newIntents = null;
2195
2196 // schedule an idle timeout in case the app doesn't do it for us.
2197 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2198 msg.obj = next;
2199 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2200
2201 if (false) {
2202 // The activity was never told to pause, so just keep
2203 // things going as-is. To maintain our own state,
2204 // we need to emulate it coming back and saying it is
2205 // idle.
2206 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2207 msg.obj = next;
2208 mHandler.sendMessage(msg);
2209 }
2210
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002211 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 next.thumbnail = null;
2214 setFocusedActivityLocked(next);
2215 next.resumeKeyDispatchingLocked();
2216 ensureActivitiesVisibleLocked(null, 0);
2217 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002218 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002219
2220 // Mark the point when the activity is resuming
2221 // TODO: To be more accurate, the mark should be before the onCreate,
2222 // not after the onResume. But for subsequent starts, onResume is fine.
2223 if (next.app != null) {
2224 synchronized (mProcessStatsThread) {
2225 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2226 }
2227 } else {
2228 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002230 }
2231
2232 /**
2233 * Make sure that all activities that need to be visible (that is, they
2234 * currently can be seen by the user) actually are.
2235 */
2236 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2237 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2238 if (DEBUG_VISBILITY) Log.v(
2239 TAG, "ensureActivitiesVisible behind " + top
2240 + " configChanges=0x" + Integer.toHexString(configChanges));
2241
2242 // If the top activity is not fullscreen, then we need to
2243 // make sure any activities under it are now visible.
2244 final int count = mHistory.size();
2245 int i = count-1;
2246 while (mHistory.get(i) != top) {
2247 i--;
2248 }
2249 HistoryRecord r;
2250 boolean behindFullscreen = false;
2251 for (; i>=0; i--) {
2252 r = (HistoryRecord)mHistory.get(i);
2253 if (DEBUG_VISBILITY) Log.v(
2254 TAG, "Make visible? " + r + " finishing=" + r.finishing
2255 + " state=" + r.state);
2256 if (r.finishing) {
2257 continue;
2258 }
2259
2260 final boolean doThisProcess = onlyThisProcess == null
2261 || onlyThisProcess.equals(r.processName);
2262
2263 // First: if this is not the current activity being started, make
2264 // sure it matches the current configuration.
2265 if (r != starting && doThisProcess) {
2266 ensureActivityConfigurationLocked(r, 0);
2267 }
2268
2269 if (r.app == null || r.app.thread == null) {
2270 if (onlyThisProcess == null
2271 || onlyThisProcess.equals(r.processName)) {
2272 // This activity needs to be visible, but isn't even
2273 // running... get it started, but don't resume it
2274 // at this point.
2275 if (DEBUG_VISBILITY) Log.v(
2276 TAG, "Start and freeze screen for " + r);
2277 if (r != starting) {
2278 r.startFreezingScreenLocked(r.app, configChanges);
2279 }
2280 if (!r.visible) {
2281 if (DEBUG_VISBILITY) Log.v(
2282 TAG, "Starting and making visible: " + r);
2283 mWindowManager.setAppVisibility(r, true);
2284 }
2285 if (r != starting) {
2286 startSpecificActivityLocked(r, false, false);
2287 }
2288 }
2289
2290 } else if (r.visible) {
2291 // If this activity is already visible, then there is nothing
2292 // else to do here.
2293 if (DEBUG_VISBILITY) Log.v(
2294 TAG, "Skipping: already visible at " + r);
2295 r.stopFreezingScreenLocked(false);
2296
2297 } else if (onlyThisProcess == null) {
2298 // This activity is not currently visible, but is running.
2299 // Tell it to become visible.
2300 r.visible = true;
2301 if (r.state != ActivityState.RESUMED && r != starting) {
2302 // If this activity is paused, tell it
2303 // to now show its window.
2304 if (DEBUG_VISBILITY) Log.v(
2305 TAG, "Making visible and scheduling visibility: " + r);
2306 try {
2307 mWindowManager.setAppVisibility(r, true);
2308 r.app.thread.scheduleWindowVisibility(r, true);
2309 r.stopFreezingScreenLocked(false);
2310 } catch (Exception e) {
2311 // Just skip on any failure; we'll make it
2312 // visible when it next restarts.
2313 Log.w(TAG, "Exception thrown making visibile: "
2314 + r.intent.getComponent(), e);
2315 }
2316 }
2317 }
2318
2319 // Aggregate current change flags.
2320 configChanges |= r.configChangeFlags;
2321
2322 if (r.fullscreen) {
2323 // At this point, nothing else needs to be shown
2324 if (DEBUG_VISBILITY) Log.v(
2325 TAG, "Stopping: fullscreen at " + r);
2326 behindFullscreen = true;
2327 i--;
2328 break;
2329 }
2330 }
2331
2332 // Now for any activities that aren't visible to the user, make
2333 // sure they no longer are keeping the screen frozen.
2334 while (i >= 0) {
2335 r = (HistoryRecord)mHistory.get(i);
2336 if (DEBUG_VISBILITY) Log.v(
2337 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2338 + " state=" + r.state
2339 + " behindFullscreen=" + behindFullscreen);
2340 if (!r.finishing) {
2341 if (behindFullscreen) {
2342 if (r.visible) {
2343 if (DEBUG_VISBILITY) Log.v(
2344 TAG, "Making invisible: " + r);
2345 r.visible = false;
2346 try {
2347 mWindowManager.setAppVisibility(r, false);
2348 if ((r.state == ActivityState.STOPPING
2349 || r.state == ActivityState.STOPPED)
2350 && r.app != null && r.app.thread != null) {
2351 if (DEBUG_VISBILITY) Log.v(
2352 TAG, "Scheduling invisibility: " + r);
2353 r.app.thread.scheduleWindowVisibility(r, false);
2354 }
2355 } catch (Exception e) {
2356 // Just skip on any failure; we'll make it
2357 // visible when it next restarts.
2358 Log.w(TAG, "Exception thrown making hidden: "
2359 + r.intent.getComponent(), e);
2360 }
2361 } else {
2362 if (DEBUG_VISBILITY) Log.v(
2363 TAG, "Already invisible: " + r);
2364 }
2365 } else if (r.fullscreen) {
2366 if (DEBUG_VISBILITY) Log.v(
2367 TAG, "Now behindFullscreen: " + r);
2368 behindFullscreen = true;
2369 }
2370 }
2371 i--;
2372 }
2373 }
2374
2375 /**
2376 * Version of ensureActivitiesVisible that can easily be called anywhere.
2377 */
2378 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2379 int configChanges) {
2380 HistoryRecord r = topRunningActivityLocked(null);
2381 if (r != null) {
2382 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2383 }
2384 }
2385
2386 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2387 if (resumed) {
2388 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2389 } else {
2390 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2391 }
2392 }
2393
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002394 private boolean startHomeActivityLocked() {
2395 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2396 && mTopAction == null) {
2397 // We are running in factory test mode, but unable to find
2398 // the factory test app, so just sit around displaying the
2399 // error message and don't try to start anything.
2400 return false;
2401 }
2402 Intent intent = new Intent(
2403 mTopAction,
2404 mTopData != null ? Uri.parse(mTopData) : null);
2405 intent.setComponent(mTopComponent);
2406 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2407 intent.addCategory(Intent.CATEGORY_HOME);
2408 }
2409 ActivityInfo aInfo =
2410 intent.resolveActivityInfo(mContext.getPackageManager(),
2411 STOCK_PM_FLAGS);
2412 if (aInfo != null) {
2413 intent.setComponent(new ComponentName(
2414 aInfo.applicationInfo.packageName, aInfo.name));
2415 // Don't do this if the home app is currently being
2416 // instrumented.
2417 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2418 aInfo.applicationInfo.uid);
2419 if (app == null || app.instrumentationClass == null) {
2420 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2421 startActivityLocked(null, intent, null, null, 0, aInfo,
2422 null, null, 0, 0, 0, false, false);
2423 }
2424 }
2425
2426
2427 return true;
2428 }
2429
2430 /**
2431 * Starts the "new version setup screen" if appropriate.
2432 */
2433 private void startSetupActivityLocked() {
2434 // Only do this once per boot.
2435 if (mCheckedForSetup) {
2436 return;
2437 }
2438
2439 // We will show this screen if the current one is a different
2440 // version than the last one shown, and we are not running in
2441 // low-level factory test mode.
2442 final ContentResolver resolver = mContext.getContentResolver();
2443 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2444 Settings.Secure.getInt(resolver,
2445 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2446 mCheckedForSetup = true;
2447
2448 // See if we should be showing the platform update setup UI.
2449 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2450 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2451 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2452
2453 // We don't allow third party apps to replace this.
2454 ResolveInfo ri = null;
2455 for (int i=0; ris != null && i<ris.size(); i++) {
2456 if ((ris.get(i).activityInfo.applicationInfo.flags
2457 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2458 ri = ris.get(i);
2459 break;
2460 }
2461 }
2462
2463 if (ri != null) {
2464 String vers = ri.activityInfo.metaData != null
2465 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2466 : null;
2467 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2468 vers = ri.activityInfo.applicationInfo.metaData.getString(
2469 Intent.METADATA_SETUP_VERSION);
2470 }
2471 String lastVers = Settings.Secure.getString(
2472 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2473 if (vers != null && !vers.equals(lastVers)) {
2474 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2475 intent.setComponent(new ComponentName(
2476 ri.activityInfo.packageName, ri.activityInfo.name));
2477 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2478 null, null, 0, 0, 0, false, false);
2479 }
2480 }
2481 }
2482 }
2483
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002484 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002485 //Log.i(TAG, "**** REPORT RESUME: " + r);
2486
2487 final int identHash = System.identityHashCode(r);
2488 updateUsageStats(r, true);
2489
2490 int i = mWatchers.beginBroadcast();
2491 while (i > 0) {
2492 i--;
2493 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2494 if (w != null) {
2495 try {
2496 w.activityResuming(identHash);
2497 } catch (RemoteException e) {
2498 }
2499 }
2500 }
2501 mWatchers.finishBroadcast();
2502 }
2503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 /**
2505 * Ensure that the top activity in the stack is resumed.
2506 *
2507 * @param prev The previously resumed activity, for when in the process
2508 * of pausing; can be null to call from elsewhere.
2509 *
2510 * @return Returns true if something is being resumed, or false if
2511 * nothing happened.
2512 */
2513 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2514 // Find the first activity that is not finishing.
2515 HistoryRecord next = topRunningActivityLocked(null);
2516
2517 // Remember how we'll process this pause/resume situation, and ensure
2518 // that the state is reset however we wind up proceeding.
2519 final boolean userLeaving = mUserLeaving;
2520 mUserLeaving = false;
2521
2522 if (next == null) {
2523 // There are no more activities! Let's just start up the
2524 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002525 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 }
2527
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002528 next.delayedResume = false;
2529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002530 // If the top activity is the resumed one, nothing to do.
2531 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2532 // Make sure we have executed any pending transitions, since there
2533 // should be nothing left to do at this point.
2534 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002535 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002536 return false;
2537 }
2538
2539 // If we are sleeping, and there is no resumed activity, and the top
2540 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002541 if ((mSleeping || mShuttingDown)
2542 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002543 // Make sure we have executed any pending transitions, since there
2544 // should be nothing left to do at this point.
2545 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002546 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002547 return false;
2548 }
2549
2550 // The activity may be waiting for stop, but that is no longer
2551 // appropriate for it.
2552 mStoppingActivities.remove(next);
2553 mWaitingVisibleActivities.remove(next);
2554
2555 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2556
2557 // If we are currently pausing an activity, then don't do anything
2558 // until that is done.
2559 if (mPausingActivity != null) {
2560 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2561 return false;
2562 }
2563
2564 // We need to start pausing the current activity so the top one
2565 // can be resumed...
2566 if (mResumedActivity != null) {
2567 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2568 startPausingLocked(userLeaving, false);
2569 return true;
2570 }
2571
2572 if (prev != null && prev != next) {
2573 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2574 prev.waitingVisible = true;
2575 mWaitingVisibleActivities.add(prev);
2576 if (DEBUG_SWITCH) Log.v(
2577 TAG, "Resuming top, waiting visible to hide: " + prev);
2578 } else {
2579 // The next activity is already visible, so hide the previous
2580 // activity's windows right now so we can show the new one ASAP.
2581 // We only do this if the previous is finishing, which should mean
2582 // it is on top of the one being resumed so hiding it quickly
2583 // is good. Otherwise, we want to do the normal route of allowing
2584 // the resumed activity to be shown so we can decide if the
2585 // previous should actually be hidden depending on whether the
2586 // new one is found to be full-screen or not.
2587 if (prev.finishing) {
2588 mWindowManager.setAppVisibility(prev, false);
2589 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2590 + prev + ", waitingVisible="
2591 + (prev != null ? prev.waitingVisible : null)
2592 + ", nowVisible=" + next.nowVisible);
2593 } else {
2594 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2595 + prev + ", waitingVisible="
2596 + (prev != null ? prev.waitingVisible : null)
2597 + ", nowVisible=" + next.nowVisible);
2598 }
2599 }
2600 }
2601
2602 // We are starting up the next activity, so tell the window manager
2603 // that the previous one will be hidden soon. This way it can know
2604 // to ignore it when computing the desired screen orientation.
2605 if (prev != null) {
2606 if (prev.finishing) {
2607 if (DEBUG_TRANSITION) Log.v(TAG,
2608 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002609 if (mNoAnimActivities.contains(prev)) {
2610 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2611 } else {
2612 mWindowManager.prepareAppTransition(prev.task == next.task
2613 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2614 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 mWindowManager.setAppWillBeHidden(prev);
2617 mWindowManager.setAppVisibility(prev, false);
2618 } else {
2619 if (DEBUG_TRANSITION) Log.v(TAG,
2620 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002621 if (mNoAnimActivities.contains(next)) {
2622 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2623 } else {
2624 mWindowManager.prepareAppTransition(prev.task == next.task
2625 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2626 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 }
2629 if (false) {
2630 mWindowManager.setAppWillBeHidden(prev);
2631 mWindowManager.setAppVisibility(prev, false);
2632 }
2633 } else if (mHistory.size() > 1) {
2634 if (DEBUG_TRANSITION) Log.v(TAG,
2635 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002636 if (mNoAnimActivities.contains(next)) {
2637 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2638 } else {
2639 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2640 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002641 }
2642
2643 if (next.app != null && next.app.thread != null) {
2644 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2645
2646 // This activity is now becoming visible.
2647 mWindowManager.setAppVisibility(next, true);
2648
2649 HistoryRecord lastResumedActivity = mResumedActivity;
2650 ActivityState lastState = next.state;
2651
2652 updateCpuStats();
2653
2654 next.state = ActivityState.RESUMED;
2655 mResumedActivity = next;
2656 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002657 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 updateLRUListLocked(next);
2659
2660 // Have the window manager re-evaluate the orientation of
2661 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002662 boolean updated;
2663 synchronized (this) {
2664 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2665 mConfiguration,
2666 next.mayFreezeScreenLocked(next.app) ? next : null);
2667 if (config != null) {
2668 /*
2669 * Explicitly restore the locale to the one from the
2670 * old configuration, since the one that comes back from
2671 * the window manager has the default (boot) locale.
2672 *
2673 * It looks like previously the locale picker only worked
2674 * by coincidence: usually it would do its setting of
2675 * the locale after the activity transition, so it didn't
2676 * matter that this lost it. With the synchronized
2677 * block now keeping them from happening at the same time,
2678 * this one always would happen second and undo what the
2679 * locale picker had just done.
2680 */
2681 config.locale = mConfiguration.locale;
2682 next.frozenBeforeDestroy = true;
2683 }
2684 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002686 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 // The configuration update wasn't able to keep the existing
2688 // instance of the activity, and instead started a new one.
2689 // We should be all done, but let's just make sure our activity
2690 // is still at the top and schedule another run if something
2691 // weird happened.
2692 HistoryRecord nextNext = topRunningActivityLocked(null);
2693 if (DEBUG_SWITCH) Log.i(TAG,
2694 "Activity config changed during resume: " + next
2695 + ", new next: " + nextNext);
2696 if (nextNext != next) {
2697 // Do over!
2698 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2699 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002700 setFocusedActivityLocked(next);
2701 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002703 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002704 return true;
2705 }
2706
2707 try {
2708 // Deliver all pending results.
2709 ArrayList a = next.results;
2710 if (a != null) {
2711 final int N = a.size();
2712 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002713 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002714 TAG, "Delivering results to " + next
2715 + ": " + a);
2716 next.app.thread.scheduleSendResult(next, a);
2717 }
2718 }
2719
2720 if (next.newIntents != null) {
2721 next.app.thread.scheduleNewIntent(next.newIntents, next);
2722 }
2723
Doug Zongker2bec3d42009-12-04 12:52:44 -08002724 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002725 System.identityHashCode(next),
2726 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727
2728 next.app.thread.scheduleResumeActivity(next,
2729 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002731 pauseIfSleepingLocked();
2732
2733 } catch (Exception e) {
2734 // Whoops, need to restart this activity!
2735 next.state = lastState;
2736 mResumedActivity = lastResumedActivity;
Dianne Hackborn03abb812010-01-04 18:43:19 -08002737 Log.i(TAG, "Restarting because process died: " + next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002738 if (!next.hasBeenLaunched) {
2739 next.hasBeenLaunched = true;
2740 } else {
2741 if (SHOW_APP_STARTING_ICON) {
2742 mWindowManager.setAppStartingWindow(
2743 next, next.packageName, next.theme,
2744 next.nonLocalizedLabel,
2745 next.labelRes, next.icon, null, true);
2746 }
2747 }
2748 startSpecificActivityLocked(next, true, false);
2749 return true;
2750 }
2751
2752 // From this point on, if something goes wrong there is no way
2753 // to recover the activity.
2754 try {
2755 next.visible = true;
2756 completeResumeLocked(next);
2757 } catch (Exception e) {
2758 // If any exception gets thrown, toss away this
2759 // activity and try the next one.
2760 Log.w(TAG, "Exception thrown during resume of " + next, e);
2761 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2762 "resume-exception");
2763 return true;
2764 }
2765
2766 // Didn't need to use the icicle, and it is now out of date.
2767 next.icicle = null;
2768 next.haveState = false;
2769 next.stopped = false;
2770
2771 } else {
2772 // Whoops, need to restart this activity!
2773 if (!next.hasBeenLaunched) {
2774 next.hasBeenLaunched = true;
2775 } else {
2776 if (SHOW_APP_STARTING_ICON) {
2777 mWindowManager.setAppStartingWindow(
2778 next, next.packageName, next.theme,
2779 next.nonLocalizedLabel,
2780 next.labelRes, next.icon, null, true);
2781 }
2782 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2783 }
2784 startSpecificActivityLocked(next, true, true);
2785 }
2786
2787 return true;
2788 }
2789
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002790 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2791 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002792 final int NH = mHistory.size();
2793
2794 int addPos = -1;
2795
2796 if (!newTask) {
2797 // If starting in an existing task, find where that is...
2798 HistoryRecord next = null;
2799 boolean startIt = true;
2800 for (int i = NH-1; i >= 0; i--) {
2801 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2802 if (p.finishing) {
2803 continue;
2804 }
2805 if (p.task == r.task) {
2806 // Here it is! Now, if this is not yet visible to the
2807 // user, then just add it without starting; it will
2808 // get started when the user navigates back to it.
2809 addPos = i+1;
2810 if (!startIt) {
2811 mHistory.add(addPos, r);
2812 r.inHistory = true;
2813 r.task.numActivities++;
2814 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2815 r.info.screenOrientation, r.fullscreen);
2816 if (VALIDATE_TOKENS) {
2817 mWindowManager.validateAppTokens(mHistory);
2818 }
2819 return;
2820 }
2821 break;
2822 }
2823 if (p.fullscreen) {
2824 startIt = false;
2825 }
2826 next = p;
2827 }
2828 }
2829
2830 // Place a new activity at top of stack, so it is next to interact
2831 // with the user.
2832 if (addPos < 0) {
2833 addPos = mHistory.size();
2834 }
2835
2836 // If we are not placing the new activity frontmost, we do not want
2837 // to deliver the onUserLeaving callback to the actual frontmost
2838 // activity
2839 if (addPos < NH) {
2840 mUserLeaving = false;
2841 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2842 }
2843
2844 // Slot the activity into the history stack and proceed
2845 mHistory.add(addPos, r);
2846 r.inHistory = true;
2847 r.frontOfTask = newTask;
2848 r.task.numActivities++;
2849 if (NH > 0) {
2850 // We want to show the starting preview window if we are
2851 // switching to a new task, or the next activity's process is
2852 // not currently running.
2853 boolean showStartingIcon = newTask;
2854 ProcessRecord proc = r.app;
2855 if (proc == null) {
2856 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2857 }
2858 if (proc == null || proc.thread == null) {
2859 showStartingIcon = true;
2860 }
2861 if (DEBUG_TRANSITION) Log.v(TAG,
2862 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002863 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2864 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2865 mNoAnimActivities.add(r);
2866 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2867 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2868 mNoAnimActivities.remove(r);
2869 } else {
2870 mWindowManager.prepareAppTransition(newTask
2871 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2872 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2873 mNoAnimActivities.remove(r);
2874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002875 mWindowManager.addAppToken(
2876 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2877 boolean doShow = true;
2878 if (newTask) {
2879 // Even though this activity is starting fresh, we still need
2880 // to reset it to make sure we apply affinities to move any
2881 // existing activities from other tasks in to it.
2882 // If the caller has requested that the target task be
2883 // reset, then do so.
2884 if ((r.intent.getFlags()
2885 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2886 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002887 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002888 }
2889 }
2890 if (SHOW_APP_STARTING_ICON && doShow) {
2891 // Figure out if we are transitioning from another activity that is
2892 // "has the same starting icon" as the next one. This allows the
2893 // window manager to keep the previous window it had previously
2894 // created, if it still had one.
2895 HistoryRecord prev = mResumedActivity;
2896 if (prev != null) {
2897 // We don't want to reuse the previous starting preview if:
2898 // (1) The current activity is in a different task.
2899 if (prev.task != r.task) prev = null;
2900 // (2) The current activity is already displayed.
2901 else if (prev.nowVisible) prev = null;
2902 }
2903 mWindowManager.setAppStartingWindow(
2904 r, r.packageName, r.theme, r.nonLocalizedLabel,
2905 r.labelRes, r.icon, prev, showStartingIcon);
2906 }
2907 } else {
2908 // If this is the first activity, don't do any fancy animations,
2909 // because there is nothing for it to animate on top of.
2910 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2911 r.info.screenOrientation, r.fullscreen);
2912 }
2913 if (VALIDATE_TOKENS) {
2914 mWindowManager.validateAppTokens(mHistory);
2915 }
2916
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002917 if (doResume) {
2918 resumeTopActivityLocked(null);
2919 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 }
2921
2922 /**
2923 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002924 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2925 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926 * an instance of that activity in the stack and, if found, finish all
2927 * activities on top of it and return the instance.
2928 *
2929 * @param newR Description of the new activity being started.
2930 * @return Returns the old activity that should be continue to be used,
2931 * or null if none was found.
2932 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002933 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002934 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002936
2937 // First find the requested task.
2938 while (i > 0) {
2939 i--;
2940 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2941 if (r.task.taskId == taskId) {
2942 i++;
2943 break;
2944 }
2945 }
2946
2947 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 while (i > 0) {
2949 i--;
2950 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2951 if (r.finishing) {
2952 continue;
2953 }
2954 if (r.task.taskId != taskId) {
2955 return null;
2956 }
2957 if (r.realActivity.equals(newR.realActivity)) {
2958 // Here it is! Now finish everything in front...
2959 HistoryRecord ret = r;
2960 if (doClear) {
2961 while (i < (mHistory.size()-1)) {
2962 i++;
2963 r = (HistoryRecord)mHistory.get(i);
2964 if (r.finishing) {
2965 continue;
2966 }
2967 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2968 null, "clear")) {
2969 i--;
2970 }
2971 }
2972 }
2973
2974 // Finally, if this is a normal launch mode (that is, not
2975 // expecting onNewIntent()), then we will finish the current
2976 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002977 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2978 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002979 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002980 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002981 if (index >= 0) {
2982 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2983 null, "clear");
2984 }
2985 return null;
2986 }
2987 }
2988
2989 return ret;
2990 }
2991 }
2992
2993 return null;
2994 }
2995
2996 /**
2997 * Find the activity in the history stack within the given task. Returns
2998 * the index within the history at which it's found, or < 0 if not found.
2999 */
3000 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3001 int i = mHistory.size();
3002 while (i > 0) {
3003 i--;
3004 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3005 if (candidate.task.taskId != task) {
3006 break;
3007 }
3008 if (candidate.realActivity.equals(r.realActivity)) {
3009 return i;
3010 }
3011 }
3012
3013 return -1;
3014 }
3015
3016 /**
3017 * Reorder the history stack so that the activity at the given index is
3018 * brought to the front.
3019 */
3020 private final HistoryRecord moveActivityToFrontLocked(int where) {
3021 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3022 int top = mHistory.size();
3023 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3024 mHistory.add(top, newTop);
3025 oldTop.frontOfTask = false;
3026 newTop.frontOfTask = true;
3027 return newTop;
3028 }
3029
3030 /**
3031 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3032 * method will be called at the proper time.
3033 */
3034 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3035 boolean sent = false;
3036 if (r.state == ActivityState.RESUMED
3037 && r.app != null && r.app.thread != null) {
3038 try {
3039 ArrayList<Intent> ar = new ArrayList<Intent>();
3040 ar.add(new Intent(intent));
3041 r.app.thread.scheduleNewIntent(ar, r);
3042 sent = true;
3043 } catch (Exception e) {
3044 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3045 }
3046 }
3047 if (!sent) {
3048 r.addNewIntentLocked(new Intent(intent));
3049 }
3050 }
3051
3052 private final void logStartActivity(int tag, HistoryRecord r,
3053 TaskRecord task) {
3054 EventLog.writeEvent(tag,
3055 System.identityHashCode(r), task.taskId,
3056 r.shortComponentName, r.intent.getAction(),
3057 r.intent.getType(), r.intent.getDataString(),
3058 r.intent.getFlags());
3059 }
3060
3061 private final int startActivityLocked(IApplicationThread caller,
3062 Intent intent, String resolvedType,
3063 Uri[] grantedUriPermissions,
3064 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3065 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003066 int callingPid, int callingUid, boolean onlyIfNeeded,
3067 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003068 Log.i(TAG, "Starting activity: " + intent);
3069
3070 HistoryRecord sourceRecord = null;
3071 HistoryRecord resultRecord = null;
3072 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003073 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003074 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3076 if (index >= 0) {
3077 sourceRecord = (HistoryRecord)mHistory.get(index);
3078 if (requestCode >= 0 && !sourceRecord.finishing) {
3079 resultRecord = sourceRecord;
3080 }
3081 }
3082 }
3083
3084 int launchFlags = intent.getFlags();
3085
3086 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3087 && sourceRecord != null) {
3088 // Transfer the result target from the source activity to the new
3089 // one being started, including any failures.
3090 if (requestCode >= 0) {
3091 return START_FORWARD_AND_REQUEST_CONFLICT;
3092 }
3093 resultRecord = sourceRecord.resultTo;
3094 resultWho = sourceRecord.resultWho;
3095 requestCode = sourceRecord.requestCode;
3096 sourceRecord.resultTo = null;
3097 if (resultRecord != null) {
3098 resultRecord.removeResultsLocked(
3099 sourceRecord, resultWho, requestCode);
3100 }
3101 }
3102
3103 int err = START_SUCCESS;
3104
3105 if (intent.getComponent() == null) {
3106 // We couldn't find a class that can handle the given Intent.
3107 // That's the end of that!
3108 err = START_INTENT_NOT_RESOLVED;
3109 }
3110
3111 if (err == START_SUCCESS && aInfo == null) {
3112 // We couldn't find the specific class specified in the Intent.
3113 // Also the end of the line.
3114 err = START_CLASS_NOT_FOUND;
3115 }
3116
3117 ProcessRecord callerApp = null;
3118 if (err == START_SUCCESS && caller != null) {
3119 callerApp = getRecordForAppLocked(caller);
3120 if (callerApp != null) {
3121 callingPid = callerApp.pid;
3122 callingUid = callerApp.info.uid;
3123 } else {
3124 Log.w(TAG, "Unable to find app for caller " + caller
3125 + " (pid=" + callingPid + ") when starting: "
3126 + intent.toString());
3127 err = START_PERMISSION_DENIED;
3128 }
3129 }
3130
3131 if (err != START_SUCCESS) {
3132 if (resultRecord != null) {
3133 sendActivityResultLocked(-1,
3134 resultRecord, resultWho, requestCode,
3135 Activity.RESULT_CANCELED, null);
3136 }
3137 return err;
3138 }
3139
3140 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3141 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3142 if (perm != PackageManager.PERMISSION_GRANTED) {
3143 if (resultRecord != null) {
3144 sendActivityResultLocked(-1,
3145 resultRecord, resultWho, requestCode,
3146 Activity.RESULT_CANCELED, null);
3147 }
3148 String msg = "Permission Denial: starting " + intent.toString()
3149 + " from " + callerApp + " (pid=" + callingPid
3150 + ", uid=" + callingUid + ")"
3151 + " requires " + aInfo.permission;
3152 Log.w(TAG, msg);
3153 throw new SecurityException(msg);
3154 }
3155
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003156 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 boolean abort = false;
3158 try {
3159 // The Intent we give to the watcher has the extra data
3160 // stripped off, since it can contain private information.
3161 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003162 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 aInfo.applicationInfo.packageName);
3164 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003165 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003166 }
3167
3168 if (abort) {
3169 if (resultRecord != null) {
3170 sendActivityResultLocked(-1,
3171 resultRecord, resultWho, requestCode,
3172 Activity.RESULT_CANCELED, null);
3173 }
3174 // We pretend to the caller that it was really started, but
3175 // they will just get a cancel result.
3176 return START_SUCCESS;
3177 }
3178 }
3179
3180 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3181 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003182 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003184 if (mResumedActivity == null
3185 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3186 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3187 PendingActivityLaunch pal = new PendingActivityLaunch();
3188 pal.r = r;
3189 pal.sourceRecord = sourceRecord;
3190 pal.grantedUriPermissions = grantedUriPermissions;
3191 pal.grantedMode = grantedMode;
3192 pal.onlyIfNeeded = onlyIfNeeded;
3193 mPendingActivityLaunches.add(pal);
3194 return START_SWITCHES_CANCELED;
3195 }
3196 }
3197
3198 if (mDidAppSwitch) {
3199 // This is the second allowed switch since we stopped switches,
3200 // so now just generally allow switches. Use case: user presses
3201 // home (switches disabled, switch to home, mDidAppSwitch now true);
3202 // user taps a home icon (coming from home so allowed, we hit here
3203 // and now allow anyone to switch again).
3204 mAppSwitchesAllowedTime = 0;
3205 } else {
3206 mDidAppSwitch = true;
3207 }
3208
3209 doPendingActivityLaunchesLocked(false);
3210
3211 return startActivityUncheckedLocked(r, sourceRecord,
3212 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3213 }
3214
3215 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3216 final int N = mPendingActivityLaunches.size();
3217 if (N <= 0) {
3218 return;
3219 }
3220 for (int i=0; i<N; i++) {
3221 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3222 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3223 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3224 doResume && i == (N-1));
3225 }
3226 mPendingActivityLaunches.clear();
3227 }
3228
3229 private final int startActivityUncheckedLocked(HistoryRecord r,
3230 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3231 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3232 final Intent intent = r.intent;
3233 final int callingUid = r.launchedFromUid;
3234
3235 int launchFlags = intent.getFlags();
3236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 // We'll invoke onUserLeaving before onPause only if the launching
3238 // activity did not explicitly state that this is an automated launch.
3239 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3240 if (DEBUG_USER_LEAVING) Log.v(TAG,
3241 "startActivity() => mUserLeaving=" + mUserLeaving);
3242
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003243 // If the caller has asked not to resume at this point, we make note
3244 // of this in the record so that we can skip it when trying to find
3245 // the top running activity.
3246 if (!doResume) {
3247 r.delayedResume = true;
3248 }
3249
3250 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3251 != 0 ? r : null;
3252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003253 // If the onlyIfNeeded flag is set, then we can do this if the activity
3254 // being launched is the same as the one making the call... or, as
3255 // a special case, if we do not know the caller then we count the
3256 // current top activity as the caller.
3257 if (onlyIfNeeded) {
3258 HistoryRecord checkedCaller = sourceRecord;
3259 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003260 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003261 }
3262 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3263 // Caller is not the same as launcher, so always needed.
3264 onlyIfNeeded = false;
3265 }
3266 }
3267
3268 if (grantedUriPermissions != null && callingUid > 0) {
3269 for (int i=0; i<grantedUriPermissions.length; i++) {
3270 grantUriPermissionLocked(callingUid, r.packageName,
3271 grantedUriPermissions[i], grantedMode, r);
3272 }
3273 }
3274
3275 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3276 intent, r);
3277
3278 if (sourceRecord == null) {
3279 // This activity is not being started from another... in this
3280 // case we -always- start a new task.
3281 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3282 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3283 + intent);
3284 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3285 }
3286 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3287 // The original activity who is starting us is running as a single
3288 // instance... this new activity it is starting must go on its
3289 // own task.
3290 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3291 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3292 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3293 // The activity being started is a single instance... it always
3294 // gets launched into its own task.
3295 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3296 }
3297
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003298 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003299 // For whatever reason this activity is being launched into a new
3300 // task... yet the caller has requested a result back. Well, that
3301 // is pretty messed up, so instead immediately send back a cancel
3302 // and let the new task continue launched as normal without a
3303 // dependency on its originator.
3304 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3305 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003306 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 Activity.RESULT_CANCELED, null);
3308 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 }
3310
3311 boolean addingToTask = false;
3312 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3313 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3314 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3315 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3316 // If bring to front is requested, and no result is requested, and
3317 // we can find a task that was started with this same
3318 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003319 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 // See if there is a task to bring to the front. If this is
3321 // a SINGLE_INSTANCE activity, there can be one and only one
3322 // instance of it in the history, and it is always in its own
3323 // unique task, so we do a special search.
3324 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3325 ? findTaskLocked(intent, r.info)
3326 : findActivityLocked(intent, r.info);
3327 if (taskTop != null) {
3328 if (taskTop.task.intent == null) {
3329 // This task was started because of movement of
3330 // the activity based on affinity... now that we
3331 // are actually launching it, we can assign the
3332 // base intent.
3333 taskTop.task.setIntent(intent, r.info);
3334 }
3335 // If the target task is not in the front, then we need
3336 // to bring it to the front... except... well, with
3337 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3338 // to have the same behavior as if a new instance was
3339 // being started, which means not bringing it to the front
3340 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003341 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 if (curTop.task != taskTop.task) {
3343 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3344 boolean callerAtFront = sourceRecord == null
3345 || curTop.task == sourceRecord.task;
3346 if (callerAtFront) {
3347 // We really do want to push this one into the
3348 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003349 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 }
3351 }
3352 // If the caller has requested that the target task be
3353 // reset, then do so.
3354 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3355 taskTop = resetTaskIfNeededLocked(taskTop, r);
3356 }
3357 if (onlyIfNeeded) {
3358 // We don't need to start a new activity, and
3359 // the client said not to do anything if that
3360 // is the case, so this is it! And for paranoia, make
3361 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003362 if (doResume) {
3363 resumeTopActivityLocked(null);
3364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 return START_RETURN_INTENT_TO_CALLER;
3366 }
3367 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3368 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3369 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3370 // In this situation we want to remove all activities
3371 // from the task up to the one being started. In most
3372 // cases this means we are resetting the task to its
3373 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003374 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003375 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 if (top != null) {
3377 if (top.frontOfTask) {
3378 // Activity aliases may mean we use different
3379 // intents for the top activity, so make sure
3380 // the task now has the identity of the new
3381 // intent.
3382 top.task.setIntent(r.intent, r.info);
3383 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003384 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003385 deliverNewIntentLocked(top, r.intent);
3386 } else {
3387 // A special case: we need to
3388 // start the activity because it is not currently
3389 // running, and the caller has asked to clear the
3390 // current task to have this activity at the top.
3391 addingToTask = true;
3392 // Now pretend like this activity is being started
3393 // by the top of its task, so it is put in the
3394 // right place.
3395 sourceRecord = taskTop;
3396 }
3397 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3398 // In this case the top activity on the task is the
3399 // same as the one being launched, so we take that
3400 // as a request to bring the task to the foreground.
3401 // If the top activity in the task is the root
3402 // activity, deliver this new intent to it if it
3403 // desires.
3404 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3405 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003406 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 if (taskTop.frontOfTask) {
3408 taskTop.task.setIntent(r.intent, r.info);
3409 }
3410 deliverNewIntentLocked(taskTop, r.intent);
3411 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3412 // In this case we are launching the root activity
3413 // of the task, but with a different intent. We
3414 // should start a new instance on top.
3415 addingToTask = true;
3416 sourceRecord = taskTop;
3417 }
3418 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3419 // In this case an activity is being launched in to an
3420 // existing task, without resetting that task. This
3421 // is typically the situation of launching an activity
3422 // from a notification or shortcut. We want to place
3423 // the new activity on top of the current task.
3424 addingToTask = true;
3425 sourceRecord = taskTop;
3426 } else if (!taskTop.task.rootWasReset) {
3427 // In this case we are launching in to an existing task
3428 // that has not yet been started from its front door.
3429 // The current task has been brought to the front.
3430 // Ideally, we'd probably like to place this new task
3431 // at the bottom of its stack, but that's a little hard
3432 // to do with the current organization of the code so
3433 // for now we'll just drop it.
3434 taskTop.task.setIntent(r.intent, r.info);
3435 }
3436 if (!addingToTask) {
3437 // We didn't do anything... but it was needed (a.k.a., client
3438 // don't use that intent!) And for paranoia, make
3439 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003440 if (doResume) {
3441 resumeTopActivityLocked(null);
3442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003443 return START_TASK_TO_FRONT;
3444 }
3445 }
3446 }
3447 }
3448
3449 //String uri = r.intent.toURI();
3450 //Intent intent2 = new Intent(uri);
3451 //Log.i(TAG, "Given intent: " + r.intent);
3452 //Log.i(TAG, "URI is: " + uri);
3453 //Log.i(TAG, "To intent: " + intent2);
3454
3455 if (r.packageName != null) {
3456 // If the activity being launched is the same as the one currently
3457 // at the top, then we need to check if it should only be launched
3458 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003459 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3460 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003461 if (top.realActivity.equals(r.realActivity)) {
3462 if (top.app != null && top.app.thread != null) {
3463 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3464 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3465 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003466 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003467 // For paranoia, make sure we have correctly
3468 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003469 if (doResume) {
3470 resumeTopActivityLocked(null);
3471 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 if (onlyIfNeeded) {
3473 // We don't need to start a new activity, and
3474 // the client said not to do anything if that
3475 // is the case, so this is it!
3476 return START_RETURN_INTENT_TO_CALLER;
3477 }
3478 deliverNewIntentLocked(top, r.intent);
3479 return START_DELIVERED_TO_TOP;
3480 }
3481 }
3482 }
3483 }
3484
3485 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003486 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003487 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003488 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 Activity.RESULT_CANCELED, null);
3490 }
3491 return START_CLASS_NOT_FOUND;
3492 }
3493
3494 boolean newTask = false;
3495
3496 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003497 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3499 // todo: should do better management of integers.
3500 mCurTask++;
3501 if (mCurTask <= 0) {
3502 mCurTask = 1;
3503 }
3504 r.task = new TaskRecord(mCurTask, r.info, intent,
3505 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3506 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3507 + " in new task " + r.task);
3508 newTask = true;
3509 addRecentTask(r.task);
3510
3511 } else if (sourceRecord != null) {
3512 if (!addingToTask &&
3513 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3514 // In this case, we are adding the activity to an existing
3515 // task, but the caller has asked to clear that task if the
3516 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003517 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003518 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003520 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 deliverNewIntentLocked(top, r.intent);
3522 // For paranoia, make sure we have correctly
3523 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003524 if (doResume) {
3525 resumeTopActivityLocked(null);
3526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 return START_DELIVERED_TO_TOP;
3528 }
3529 } else if (!addingToTask &&
3530 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3531 // In this case, we are launching an activity in our own task
3532 // that may already be running somewhere in the history, and
3533 // we want to shuffle it to the front of the stack if so.
3534 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3535 if (where >= 0) {
3536 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003537 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003539 if (doResume) {
3540 resumeTopActivityLocked(null);
3541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 return START_DELIVERED_TO_TOP;
3543 }
3544 }
3545 // An existing activity is starting this new activity, so we want
3546 // to keep the new one in the same task as the one that is starting
3547 // it.
3548 r.task = sourceRecord.task;
3549 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3550 + " in existing task " + r.task);
3551
3552 } else {
3553 // This not being started from an existing activity, and not part
3554 // of a new task... just put it in the top task, though these days
3555 // this case should never happen.
3556 final int N = mHistory.size();
3557 HistoryRecord prev =
3558 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3559 r.task = prev != null
3560 ? prev.task
3561 : new TaskRecord(mCurTask, r.info, intent,
3562 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3563 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3564 + " in new guessed " + r.task);
3565 }
3566 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003567 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003569 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003570 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 return START_SUCCESS;
3572 }
3573
3574 public final int startActivity(IApplicationThread caller,
3575 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3576 int grantedMode, IBinder resultTo,
3577 String resultWho, int requestCode, boolean onlyIfNeeded,
3578 boolean debug) {
3579 // Refuse possible leaked file descriptors
3580 if (intent != null && intent.hasFileDescriptors()) {
3581 throw new IllegalArgumentException("File descriptors passed in Intent");
3582 }
3583
The Android Open Source Project4df24232009-03-05 14:34:35 -08003584 final boolean componentSpecified = intent.getComponent() != null;
3585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003586 // Don't modify the client's object!
3587 intent = new Intent(intent);
3588
3589 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003590 ActivityInfo aInfo;
3591 try {
3592 ResolveInfo rInfo =
3593 ActivityThread.getPackageManager().resolveIntent(
3594 intent, resolvedType,
3595 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003596 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 aInfo = rInfo != null ? rInfo.activityInfo : null;
3598 } catch (RemoteException e) {
3599 aInfo = null;
3600 }
3601
3602 if (aInfo != null) {
3603 // Store the found target back into the intent, because now that
3604 // we have it we never want to do this again. For example, if the
3605 // user navigates back to this point in the history, we should
3606 // always restart the exact same activity.
3607 intent.setComponent(new ComponentName(
3608 aInfo.applicationInfo.packageName, aInfo.name));
3609
3610 // Don't debug things in the system process
3611 if (debug) {
3612 if (!aInfo.processName.equals("system")) {
3613 setDebugApp(aInfo.processName, true, false);
3614 }
3615 }
3616 }
3617
3618 synchronized(this) {
3619 final long origId = Binder.clearCallingIdentity();
3620 int res = startActivityLocked(caller, intent, resolvedType,
3621 grantedUriPermissions, grantedMode, aInfo,
3622 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003623 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 Binder.restoreCallingIdentity(origId);
3625 return res;
3626 }
3627 }
3628
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003629 public int startActivityIntentSender(IApplicationThread caller,
3630 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003631 IBinder resultTo, String resultWho, int requestCode,
3632 int flagsMask, int flagsValues) {
3633 // Refuse possible leaked file descriptors
3634 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3635 throw new IllegalArgumentException("File descriptors passed in Intent");
3636 }
3637
3638 IIntentSender sender = intent.getTarget();
3639 if (!(sender instanceof PendingIntentRecord)) {
3640 throw new IllegalArgumentException("Bad PendingIntent object");
3641 }
3642
3643 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003644
3645 synchronized (this) {
3646 // If this is coming from the currently resumed activity, it is
3647 // effectively saying that app switches are allowed at this point.
3648 if (mResumedActivity != null
3649 && mResumedActivity.info.applicationInfo.uid ==
3650 Binder.getCallingUid()) {
3651 mAppSwitchesAllowedTime = 0;
3652 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003653 }
3654
3655 return pir.sendInner(0, fillInIntent, resolvedType,
3656 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3657 }
3658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003659 public boolean startNextMatchingActivity(IBinder callingActivity,
3660 Intent intent) {
3661 // Refuse possible leaked file descriptors
3662 if (intent != null && intent.hasFileDescriptors() == true) {
3663 throw new IllegalArgumentException("File descriptors passed in Intent");
3664 }
3665
3666 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003667 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003668 if (index < 0) {
3669 return false;
3670 }
3671 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3672 if (r.app == null || r.app.thread == null) {
3673 // The caller is not running... d'oh!
3674 return false;
3675 }
3676 intent = new Intent(intent);
3677 // The caller is not allowed to change the data.
3678 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3679 // And we are resetting to find the next component...
3680 intent.setComponent(null);
3681
3682 ActivityInfo aInfo = null;
3683 try {
3684 List<ResolveInfo> resolves =
3685 ActivityThread.getPackageManager().queryIntentActivities(
3686 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003687 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688
3689 // Look for the original activity in the list...
3690 final int N = resolves != null ? resolves.size() : 0;
3691 for (int i=0; i<N; i++) {
3692 ResolveInfo rInfo = resolves.get(i);
3693 if (rInfo.activityInfo.packageName.equals(r.packageName)
3694 && rInfo.activityInfo.name.equals(r.info.name)) {
3695 // We found the current one... the next matching is
3696 // after it.
3697 i++;
3698 if (i<N) {
3699 aInfo = resolves.get(i).activityInfo;
3700 }
3701 break;
3702 }
3703 }
3704 } catch (RemoteException e) {
3705 }
3706
3707 if (aInfo == null) {
3708 // Nobody who is next!
3709 return false;
3710 }
3711
3712 intent.setComponent(new ComponentName(
3713 aInfo.applicationInfo.packageName, aInfo.name));
3714 intent.setFlags(intent.getFlags()&~(
3715 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3716 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3717 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3718 Intent.FLAG_ACTIVITY_NEW_TASK));
3719
3720 // Okay now we need to start the new activity, replacing the
3721 // currently running activity. This is a little tricky because
3722 // we want to start the new one as if the current one is finished,
3723 // but not finish the current one first so that there is no flicker.
3724 // And thus...
3725 final boolean wasFinishing = r.finishing;
3726 r.finishing = true;
3727
3728 // Propagate reply information over to the new activity.
3729 final HistoryRecord resultTo = r.resultTo;
3730 final String resultWho = r.resultWho;
3731 final int requestCode = r.requestCode;
3732 r.resultTo = null;
3733 if (resultTo != null) {
3734 resultTo.removeResultsLocked(r, resultWho, requestCode);
3735 }
3736
3737 final long origId = Binder.clearCallingIdentity();
3738 // XXX we are not dealing with propagating grantedUriPermissions...
3739 // those are not yet exposed to user code, so there is no need.
3740 int res = startActivityLocked(r.app.thread, intent,
3741 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003742 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003743 Binder.restoreCallingIdentity(origId);
3744
3745 r.finishing = wasFinishing;
3746 if (res != START_SUCCESS) {
3747 return false;
3748 }
3749 return true;
3750 }
3751 }
3752
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003753 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 Intent intent, String resolvedType, IBinder resultTo,
3755 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003756
3757 // This is so super not safe, that only the system (or okay root)
3758 // can do it.
3759 final int callingUid = Binder.getCallingUid();
3760 if (callingUid != 0 && callingUid != Process.myUid()) {
3761 throw new SecurityException(
3762 "startActivityInPackage only available to the system");
3763 }
3764
The Android Open Source Project4df24232009-03-05 14:34:35 -08003765 final boolean componentSpecified = intent.getComponent() != null;
3766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 // Don't modify the client's object!
3768 intent = new Intent(intent);
3769
3770 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003771 ActivityInfo aInfo;
3772 try {
3773 ResolveInfo rInfo =
3774 ActivityThread.getPackageManager().resolveIntent(
3775 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003776 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003777 aInfo = rInfo != null ? rInfo.activityInfo : null;
3778 } catch (RemoteException e) {
3779 aInfo = null;
3780 }
3781
3782 if (aInfo != null) {
3783 // Store the found target back into the intent, because now that
3784 // we have it we never want to do this again. For example, if the
3785 // user navigates back to this point in the history, we should
3786 // always restart the exact same activity.
3787 intent.setComponent(new ComponentName(
3788 aInfo.applicationInfo.packageName, aInfo.name));
3789 }
3790
3791 synchronized(this) {
3792 return startActivityLocked(null, intent, resolvedType,
3793 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003794 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003795 }
3796 }
3797
3798 private final void addRecentTask(TaskRecord task) {
3799 // Remove any existing entries that are the same kind of task.
3800 int N = mRecentTasks.size();
3801 for (int i=0; i<N; i++) {
3802 TaskRecord tr = mRecentTasks.get(i);
3803 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3804 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3805 mRecentTasks.remove(i);
3806 i--;
3807 N--;
3808 if (task.intent == null) {
3809 // If the new recent task we are adding is not fully
3810 // specified, then replace it with the existing recent task.
3811 task = tr;
3812 }
3813 }
3814 }
3815 if (N >= MAX_RECENT_TASKS) {
3816 mRecentTasks.remove(N-1);
3817 }
3818 mRecentTasks.add(0, task);
3819 }
3820
3821 public void setRequestedOrientation(IBinder token,
3822 int requestedOrientation) {
3823 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003824 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003825 if (index < 0) {
3826 return;
3827 }
3828 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3829 final long origId = Binder.clearCallingIdentity();
3830 mWindowManager.setAppOrientation(r, requestedOrientation);
3831 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003832 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003833 r.mayFreezeScreenLocked(r.app) ? r : null);
3834 if (config != null) {
3835 r.frozenBeforeDestroy = true;
3836 if (!updateConfigurationLocked(config, r)) {
3837 resumeTopActivityLocked(null);
3838 }
3839 }
3840 Binder.restoreCallingIdentity(origId);
3841 }
3842 }
3843
3844 public int getRequestedOrientation(IBinder token) {
3845 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003846 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003847 if (index < 0) {
3848 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3849 }
3850 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3851 return mWindowManager.getAppOrientation(r);
3852 }
3853 }
3854
3855 private final void stopActivityLocked(HistoryRecord r) {
3856 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3857 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3858 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3859 if (!r.finishing) {
3860 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3861 "no-history");
3862 }
3863 } else if (r.app != null && r.app.thread != null) {
3864 if (mFocusedActivity == r) {
3865 setFocusedActivityLocked(topRunningActivityLocked(null));
3866 }
3867 r.resumeKeyDispatchingLocked();
3868 try {
3869 r.stopped = false;
3870 r.state = ActivityState.STOPPING;
3871 if (DEBUG_VISBILITY) Log.v(
3872 TAG, "Stopping visible=" + r.visible + " for " + r);
3873 if (!r.visible) {
3874 mWindowManager.setAppVisibility(r, false);
3875 }
3876 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3877 } catch (Exception e) {
3878 // Maybe just ignore exceptions here... if the process
3879 // has crashed, our death notification will clean things
3880 // up.
3881 Log.w(TAG, "Exception thrown during pause", e);
3882 // Just in case, assume it to be stopped.
3883 r.stopped = true;
3884 r.state = ActivityState.STOPPED;
3885 if (r.configDestroy) {
3886 destroyActivityLocked(r, true);
3887 }
3888 }
3889 }
3890 }
3891
3892 /**
3893 * @return Returns true if the activity is being finished, false if for
3894 * some reason it is being left as-is.
3895 */
3896 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3897 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003898 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899 TAG, "Finishing activity: token=" + token
3900 + ", result=" + resultCode + ", data=" + resultData);
3901
Dianne Hackborn75b03852009-06-12 15:43:26 -07003902 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 if (index < 0) {
3904 return false;
3905 }
3906 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3907
3908 // Is this the last activity left?
3909 boolean lastActivity = true;
3910 for (int i=mHistory.size()-1; i>=0; i--) {
3911 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3912 if (!p.finishing && p != r) {
3913 lastActivity = false;
3914 break;
3915 }
3916 }
3917
3918 // If this is the last activity, but it is the home activity, then
3919 // just don't finish it.
3920 if (lastActivity) {
3921 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3922 return false;
3923 }
3924 }
3925
3926 finishActivityLocked(r, index, resultCode, resultData, reason);
3927 return true;
3928 }
3929
3930 /**
3931 * @return Returns true if this activity has been removed from the history
3932 * list, or false if it is still in the list and will be removed later.
3933 */
3934 private final boolean finishActivityLocked(HistoryRecord r, int index,
3935 int resultCode, Intent resultData, String reason) {
3936 if (r.finishing) {
3937 Log.w(TAG, "Duplicate finish request for " + r);
3938 return false;
3939 }
3940
3941 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003942 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003943 System.identityHashCode(r),
3944 r.task.taskId, r.shortComponentName, reason);
3945 r.task.numActivities--;
3946 if (r.frontOfTask && index < (mHistory.size()-1)) {
3947 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3948 if (next.task == r.task) {
3949 next.frontOfTask = true;
3950 }
3951 }
3952
3953 r.pauseKeyDispatchingLocked();
3954 if (mFocusedActivity == r) {
3955 setFocusedActivityLocked(topRunningActivityLocked(null));
3956 }
3957
3958 // send the result
3959 HistoryRecord resultTo = r.resultTo;
3960 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003961 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3962 + " who=" + r.resultWho + " req=" + r.requestCode
3963 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003964 if (r.info.applicationInfo.uid > 0) {
3965 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3966 r.packageName, resultData, r);
3967 }
3968 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3969 resultData);
3970 r.resultTo = null;
3971 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003972 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003973
3974 // Make sure this HistoryRecord is not holding on to other resources,
3975 // because clients have remote IPC references to this object so we
3976 // can't assume that will go away and want to avoid circular IPC refs.
3977 r.results = null;
3978 r.pendingResults = null;
3979 r.newIntents = null;
3980 r.icicle = null;
3981
3982 if (mPendingThumbnails.size() > 0) {
3983 // There are clients waiting to receive thumbnails so, in case
3984 // this is an activity that someone is waiting for, add it
3985 // to the pending list so we can correctly update the clients.
3986 mCancelledThumbnails.add(r);
3987 }
3988
3989 if (mResumedActivity == r) {
3990 boolean endTask = index <= 0
3991 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3992 if (DEBUG_TRANSITION) Log.v(TAG,
3993 "Prepare close transition: finishing " + r);
3994 mWindowManager.prepareAppTransition(endTask
3995 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3996 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3997
3998 // Tell window manager to prepare for this one to be removed.
3999 mWindowManager.setAppVisibility(r, false);
4000
4001 if (mPausingActivity == null) {
4002 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4003 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4004 startPausingLocked(false, false);
4005 }
4006
4007 } else if (r.state != ActivityState.PAUSING) {
4008 // If the activity is PAUSING, we will complete the finish once
4009 // it is done pausing; else we can just directly finish it here.
4010 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4011 return finishCurrentActivityLocked(r, index,
4012 FINISH_AFTER_PAUSE) == null;
4013 } else {
4014 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4015 }
4016
4017 return false;
4018 }
4019
4020 private static final int FINISH_IMMEDIATELY = 0;
4021 private static final int FINISH_AFTER_PAUSE = 1;
4022 private static final int FINISH_AFTER_VISIBLE = 2;
4023
4024 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4025 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004026 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004027 if (index < 0) {
4028 return null;
4029 }
4030
4031 return finishCurrentActivityLocked(r, index, mode);
4032 }
4033
4034 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4035 int index, int mode) {
4036 // First things first: if this activity is currently visible,
4037 // and the resumed activity is not yet visible, then hold off on
4038 // finishing until the resumed one becomes visible.
4039 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4040 if (!mStoppingActivities.contains(r)) {
4041 mStoppingActivities.add(r);
4042 if (mStoppingActivities.size() > 3) {
4043 // If we already have a few activities waiting to stop,
4044 // then give up on things going idle and start clearing
4045 // them out.
4046 Message msg = Message.obtain();
4047 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4048 mHandler.sendMessage(msg);
4049 }
4050 }
4051 r.state = ActivityState.STOPPING;
4052 updateOomAdjLocked();
4053 return r;
4054 }
4055
4056 // make sure the record is cleaned out of other places.
4057 mStoppingActivities.remove(r);
4058 mWaitingVisibleActivities.remove(r);
4059 if (mResumedActivity == r) {
4060 mResumedActivity = null;
4061 }
4062 final ActivityState prevState = r.state;
4063 r.state = ActivityState.FINISHING;
4064
4065 if (mode == FINISH_IMMEDIATELY
4066 || prevState == ActivityState.STOPPED
4067 || prevState == ActivityState.INITIALIZING) {
4068 // If this activity is already stopped, we can just finish
4069 // it right now.
4070 return destroyActivityLocked(r, true) ? null : r;
4071 } else {
4072 // Need to go through the full pause cycle to get this
4073 // activity into the stopped state and then finish it.
4074 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4075 mFinishingActivities.add(r);
4076 resumeTopActivityLocked(null);
4077 }
4078 return r;
4079 }
4080
4081 /**
4082 * This is the internal entry point for handling Activity.finish().
4083 *
4084 * @param token The Binder token referencing the Activity we want to finish.
4085 * @param resultCode Result code, if any, from this Activity.
4086 * @param resultData Result data (Intent), if any, from this Activity.
4087 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004088 * @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 -08004089 */
4090 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4091 // Refuse possible leaked file descriptors
4092 if (resultData != null && resultData.hasFileDescriptors() == true) {
4093 throw new IllegalArgumentException("File descriptors passed in Intent");
4094 }
4095
4096 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004097 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004098 // Find the first activity that is not finishing.
4099 HistoryRecord next = topRunningActivityLocked(token, 0);
4100 if (next != null) {
4101 // ask watcher if this is allowed
4102 boolean resumeOK = true;
4103 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004104 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004105 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004106 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004107 }
4108
4109 if (!resumeOK) {
4110 return false;
4111 }
4112 }
4113 }
4114 final long origId = Binder.clearCallingIdentity();
4115 boolean res = requestFinishActivityLocked(token, resultCode,
4116 resultData, "app-request");
4117 Binder.restoreCallingIdentity(origId);
4118 return res;
4119 }
4120 }
4121
4122 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4123 String resultWho, int requestCode, int resultCode, Intent data) {
4124
4125 if (callingUid > 0) {
4126 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4127 data, r);
4128 }
4129
The Android Open Source Project10592532009-03-18 17:39:46 -07004130 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4131 + " : who=" + resultWho + " req=" + requestCode
4132 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004133 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4134 try {
4135 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4136 list.add(new ResultInfo(resultWho, requestCode,
4137 resultCode, data));
4138 r.app.thread.scheduleSendResult(r, list);
4139 return;
4140 } catch (Exception e) {
4141 Log.w(TAG, "Exception thrown sending result to " + r, e);
4142 }
4143 }
4144
4145 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4146 }
4147
4148 public final void finishSubActivity(IBinder token, String resultWho,
4149 int requestCode) {
4150 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004151 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004152 if (index < 0) {
4153 return;
4154 }
4155 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4156
4157 final long origId = Binder.clearCallingIdentity();
4158
4159 int i;
4160 for (i=mHistory.size()-1; i>=0; i--) {
4161 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4162 if (r.resultTo == self && r.requestCode == requestCode) {
4163 if ((r.resultWho == null && resultWho == null) ||
4164 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4165 finishActivityLocked(r, i,
4166 Activity.RESULT_CANCELED, null, "request-sub");
4167 }
4168 }
4169 }
4170
4171 Binder.restoreCallingIdentity(origId);
4172 }
4173 }
4174
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004175 public void overridePendingTransition(IBinder token, String packageName,
4176 int enterAnim, int exitAnim) {
4177 synchronized(this) {
4178 int index = indexOfTokenLocked(token);
4179 if (index < 0) {
4180 return;
4181 }
4182 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4183
4184 final long origId = Binder.clearCallingIdentity();
4185
4186 if (self.state == ActivityState.RESUMED
4187 || self.state == ActivityState.PAUSING) {
4188 mWindowManager.overridePendingAppTransition(packageName,
4189 enterAnim, exitAnim);
4190 }
4191
4192 Binder.restoreCallingIdentity(origId);
4193 }
4194 }
4195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004196 /**
4197 * Perform clean-up of service connections in an activity record.
4198 */
4199 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4200 // Throw away any services that have been bound by this activity.
4201 if (r.connections != null) {
4202 Iterator<ConnectionRecord> it = r.connections.iterator();
4203 while (it.hasNext()) {
4204 ConnectionRecord c = it.next();
4205 removeConnectionLocked(c, null, r);
4206 }
4207 r.connections = null;
4208 }
4209 }
4210
4211 /**
4212 * Perform the common clean-up of an activity record. This is called both
4213 * as part of destroyActivityLocked() (when destroying the client-side
4214 * representation) and cleaning things up as a result of its hosting
4215 * processing going away, in which case there is no remaining client-side
4216 * state to destroy so only the cleanup here is needed.
4217 */
4218 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4219 if (mResumedActivity == r) {
4220 mResumedActivity = null;
4221 }
4222 if (mFocusedActivity == r) {
4223 mFocusedActivity = null;
4224 }
4225
4226 r.configDestroy = false;
4227 r.frozenBeforeDestroy = false;
4228
4229 // Make sure this record is no longer in the pending finishes list.
4230 // This could happen, for example, if we are trimming activities
4231 // down to the max limit while they are still waiting to finish.
4232 mFinishingActivities.remove(r);
4233 mWaitingVisibleActivities.remove(r);
4234
4235 // Remove any pending results.
4236 if (r.finishing && r.pendingResults != null) {
4237 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4238 PendingIntentRecord rec = apr.get();
4239 if (rec != null) {
4240 cancelIntentSenderLocked(rec, false);
4241 }
4242 }
4243 r.pendingResults = null;
4244 }
4245
4246 if (cleanServices) {
4247 cleanUpActivityServicesLocked(r);
4248 }
4249
4250 if (mPendingThumbnails.size() > 0) {
4251 // There are clients waiting to receive thumbnails so, in case
4252 // this is an activity that someone is waiting for, add it
4253 // to the pending list so we can correctly update the clients.
4254 mCancelledThumbnails.add(r);
4255 }
4256
4257 // Get rid of any pending idle timeouts.
4258 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4259 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4260 }
4261
4262 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4263 if (r.state != ActivityState.DESTROYED) {
4264 mHistory.remove(r);
4265 r.inHistory = false;
4266 r.state = ActivityState.DESTROYED;
4267 mWindowManager.removeAppToken(r);
4268 if (VALIDATE_TOKENS) {
4269 mWindowManager.validateAppTokens(mHistory);
4270 }
4271 cleanUpActivityServicesLocked(r);
4272 removeActivityUriPermissionsLocked(r);
4273 }
4274 }
4275
4276 /**
4277 * Destroy the current CLIENT SIDE instance of an activity. This may be
4278 * called both when actually finishing an activity, or when performing
4279 * a configuration switch where we destroy the current client-side object
4280 * but then create a new client-side object for this same HistoryRecord.
4281 */
4282 private final boolean destroyActivityLocked(HistoryRecord r,
4283 boolean removeFromApp) {
4284 if (DEBUG_SWITCH) Log.v(
4285 TAG, "Removing activity: token=" + r
4286 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004287 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004288 System.identityHashCode(r),
4289 r.task.taskId, r.shortComponentName);
4290
4291 boolean removedFromHistory = false;
4292
4293 cleanUpActivityLocked(r, false);
4294
Dianne Hackborn03abb812010-01-04 18:43:19 -08004295 final boolean hadApp = r.app != null;
4296
4297 if (hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004298 if (removeFromApp) {
4299 int idx = r.app.activities.indexOf(r);
4300 if (idx >= 0) {
4301 r.app.activities.remove(idx);
4302 }
4303 if (r.persistent) {
4304 decPersistentCountLocked(r.app);
4305 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004306 if (r.app.activities.size() == 0) {
4307 // No longer have activities, so update location in
4308 // LRU list.
4309 updateLruProcessLocked(r.app, true, false);
4310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004311 }
4312
4313 boolean skipDestroy = false;
4314
4315 try {
4316 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4317 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4318 r.configChangeFlags);
4319 } catch (Exception e) {
4320 // We can just ignore exceptions here... if the process
4321 // has crashed, our death notification will clean things
4322 // up.
4323 //Log.w(TAG, "Exception thrown during finish", e);
4324 if (r.finishing) {
4325 removeActivityFromHistoryLocked(r);
4326 removedFromHistory = true;
4327 skipDestroy = true;
4328 }
4329 }
4330
4331 r.app = null;
4332 r.nowVisible = false;
4333
4334 if (r.finishing && !skipDestroy) {
4335 r.state = ActivityState.DESTROYING;
4336 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4337 msg.obj = r;
4338 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4339 } else {
4340 r.state = ActivityState.DESTROYED;
4341 }
4342 } else {
4343 // remove this record from the history.
4344 if (r.finishing) {
4345 removeActivityFromHistoryLocked(r);
4346 removedFromHistory = true;
4347 } else {
4348 r.state = ActivityState.DESTROYED;
4349 }
4350 }
4351
4352 r.configChangeFlags = 0;
4353
Dianne Hackborn03abb812010-01-04 18:43:19 -08004354 if (!mLRUActivities.remove(r) && hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004355 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4356 }
4357
4358 return removedFromHistory;
4359 }
4360
Dianne Hackborn03abb812010-01-04 18:43:19 -08004361 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004362 int i = list.size();
4363 if (localLOGV) Log.v(
4364 TAG, "Removing app " + app + " from list " + list
4365 + " with " + i + " entries");
4366 while (i > 0) {
4367 i--;
4368 HistoryRecord r = (HistoryRecord)list.get(i);
4369 if (localLOGV) Log.v(
4370 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4371 if (r.app == app) {
4372 if (localLOGV) Log.v(TAG, "Removing this entry!");
4373 list.remove(i);
4374 }
4375 }
4376 }
4377
4378 /**
4379 * Main function for removing an existing process from the activity manager
4380 * as a result of that process going away. Clears out all connections
4381 * to the process.
4382 */
4383 private final void handleAppDiedLocked(ProcessRecord app,
4384 boolean restarting) {
4385 cleanUpApplicationRecordLocked(app, restarting, -1);
4386 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004387 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004388 }
4389
4390 // Just in case...
4391 if (mPausingActivity != null && mPausingActivity.app == app) {
4392 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4393 mPausingActivity = null;
4394 }
4395 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4396 mLastPausedActivity = null;
4397 }
4398
4399 // Remove this application's activities from active lists.
4400 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4401 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4402 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4403 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4404
4405 boolean atTop = true;
4406 boolean hasVisibleActivities = false;
4407
4408 // Clean out the history list.
4409 int i = mHistory.size();
4410 if (localLOGV) Log.v(
4411 TAG, "Removing app " + app + " from history with " + i + " entries");
4412 while (i > 0) {
4413 i--;
4414 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4415 if (localLOGV) Log.v(
4416 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4417 if (r.app == app) {
4418 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4419 if (localLOGV) Log.v(
4420 TAG, "Removing this entry! frozen=" + r.haveState
4421 + " finishing=" + r.finishing);
4422 mHistory.remove(i);
4423
4424 r.inHistory = false;
4425 mWindowManager.removeAppToken(r);
4426 if (VALIDATE_TOKENS) {
4427 mWindowManager.validateAppTokens(mHistory);
4428 }
4429 removeActivityUriPermissionsLocked(r);
4430
4431 } else {
4432 // We have the current state for this activity, so
4433 // it can be restarted later when needed.
4434 if (localLOGV) Log.v(
4435 TAG, "Keeping entry, setting app to null");
4436 if (r.visible) {
4437 hasVisibleActivities = true;
4438 }
4439 r.app = null;
4440 r.nowVisible = false;
4441 if (!r.haveState) {
4442 r.icicle = null;
4443 }
4444 }
4445
4446 cleanUpActivityLocked(r, true);
4447 r.state = ActivityState.STOPPED;
4448 }
4449 atTop = false;
4450 }
4451
4452 app.activities.clear();
4453
4454 if (app.instrumentationClass != null) {
4455 Log.w(TAG, "Crash of app " + app.processName
4456 + " running instrumentation " + app.instrumentationClass);
4457 Bundle info = new Bundle();
4458 info.putString("shortMsg", "Process crashed.");
4459 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4460 }
4461
4462 if (!restarting) {
4463 if (!resumeTopActivityLocked(null)) {
4464 // If there was nothing to resume, and we are not already
4465 // restarting this process, but there is a visible activity that
4466 // is hosted by the process... then make sure all visible
4467 // activities are running, taking care of restarting this
4468 // process.
4469 if (hasVisibleActivities) {
4470 ensureActivitiesVisibleLocked(null, 0);
4471 }
4472 }
4473 }
4474 }
4475
4476 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4477 IBinder threadBinder = thread.asBinder();
4478
4479 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004480 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4481 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004482 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4483 return i;
4484 }
4485 }
4486 return -1;
4487 }
4488
4489 private final ProcessRecord getRecordForAppLocked(
4490 IApplicationThread thread) {
4491 if (thread == null) {
4492 return null;
4493 }
4494
4495 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004496 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004497 }
4498
4499 private final void appDiedLocked(ProcessRecord app, int pid,
4500 IApplicationThread thread) {
4501
4502 mProcDeaths[0]++;
4503
4504 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4505 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4506 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004507 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004508 if (localLOGV) Log.v(
4509 TAG, "Dying app: " + app + ", pid: " + pid
4510 + ", thread: " + thread.asBinder());
4511 boolean doLowMem = app.instrumentationClass == null;
4512 handleAppDiedLocked(app, false);
4513
4514 if (doLowMem) {
4515 // If there are no longer any background processes running,
4516 // and the app that died was not running instrumentation,
4517 // then tell everyone we are now low on memory.
4518 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004519 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4520 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004521 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4522 haveBg = true;
4523 break;
4524 }
4525 }
4526
4527 if (!haveBg) {
4528 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004529 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004530 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004531 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4532 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004533 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004534 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4535 // The low memory report is overriding any current
4536 // state for a GC request. Make sure to do
4537 // visible/foreground processes first.
4538 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4539 rec.lastRequestedGc = 0;
4540 } else {
4541 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004542 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004543 rec.reportLowMemory = true;
4544 rec.lastLowMemory = now;
4545 mProcessesToGc.remove(rec);
4546 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004547 }
4548 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004549 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004550 }
4551 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004552 } else if (DEBUG_PROCESSES) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004553 Log.d(TAG, "Received spurious death notification for thread "
4554 + thread.asBinder());
4555 }
4556 }
4557
4558 final String readFile(String filename) {
4559 try {
4560 FileInputStream fs = new FileInputStream(filename);
4561 byte[] inp = new byte[8192];
4562 int size = fs.read(inp);
4563 fs.close();
4564 return new String(inp, 0, 0, size);
4565 } catch (java.io.IOException e) {
4566 }
4567 return "";
4568 }
4569
4570 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004571 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004572 if (app.notResponding || app.crashing) {
4573 return;
4574 }
4575
4576 // Log the ANR to the event log.
Doug Zongker2bec3d42009-12-04 12:52:44 -08004577 EventLog.writeEvent(EventLogTags.ANR, app.pid, app.processName, annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004578
4579 // If we are on a secure build and the application is not interesting to the user (it is
4580 // not visible or in the background), just kill it instead of displaying a dialog.
4581 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4582 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4583 Process.killProcess(app.pid);
4584 return;
4585 }
4586
4587 // DeviceMonitor.start();
4588
4589 String processInfo = null;
4590 if (MONITOR_CPU_USAGE) {
4591 updateCpuStatsNow();
4592 synchronized (mProcessStatsThread) {
4593 processInfo = mProcessStats.printCurrentState();
4594 }
4595 }
4596
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004597 StringBuilder info = mStringBuilder;
4598 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004599 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004600 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004601 if (reportedActivity != null && reportedActivity.app != null) {
4602 info.append(" (last in ");
4603 info.append(reportedActivity.app.processName);
4604 info.append(")");
4605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004606 if (annotation != null) {
4607 info.append("\nAnnotation: ");
4608 info.append(annotation);
4609 }
4610 if (MONITOR_CPU_USAGE) {
4611 info.append("\nCPU usage:\n");
4612 info.append(processInfo);
4613 }
4614 Log.i(TAG, info.toString());
4615
4616 // The application is not responding. Dump as many thread traces as we can.
4617 boolean fileDump = prepareTraceFile(true);
4618 if (!fileDump) {
4619 // Dumping traces to the log, just dump the process that isn't responding so
4620 // we don't overflow the log
4621 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4622 } else {
4623 // Dumping traces to a file so dump all active processes we know about
4624 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004625 // First, these are the most important processes.
4626 final int[] imppids = new int[3];
4627 int i=0;
4628 imppids[0] = app.pid;
4629 i++;
4630 if (reportedActivity != null && reportedActivity.app != null
4631 && reportedActivity.app.thread != null
4632 && reportedActivity.app.pid != app.pid) {
4633 imppids[i] = reportedActivity.app.pid;
4634 i++;
4635 }
4636 imppids[i] = Process.myPid();
4637 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4638 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4639 synchronized (this) {
4640 try {
4641 wait(200);
4642 } catch (InterruptedException e) {
4643 }
4644 }
4645 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004646 for (i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
4647 ProcessRecord r = mLruProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004648 boolean done = false;
4649 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4650 if (imppids[j] == r.pid) {
4651 done = true;
4652 break;
4653 }
4654 }
4655 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004656 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004657 synchronized (this) {
4658 try {
4659 wait(200);
4660 } catch (InterruptedException e) {
4661 }
4662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004663 }
4664 }
4665 }
4666 }
4667
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004668 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004669 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004670 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004671 app.pid, info.toString());
4672 if (res != 0) {
4673 if (res < 0) {
4674 // wait until the SIGQUIT has had a chance to process before killing the
4675 // process.
4676 try {
4677 wait(2000);
4678 } catch (InterruptedException e) {
4679 }
4680
4681 Process.killProcess(app.pid);
4682 return;
4683 }
4684 }
4685 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004686 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004687 }
4688 }
4689
4690 makeAppNotRespondingLocked(app,
4691 activity != null ? activity.shortComponentName : null,
4692 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004693 info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004694 Message msg = Message.obtain();
4695 HashMap map = new HashMap();
4696 msg.what = SHOW_NOT_RESPONDING_MSG;
4697 msg.obj = map;
4698 map.put("app", app);
4699 if (activity != null) {
4700 map.put("activity", activity);
4701 }
4702
4703 mHandler.sendMessage(msg);
4704 return;
4705 }
4706
4707 /**
4708 * If a stack trace file has been configured, prepare the filesystem
4709 * by creating the directory if it doesn't exist and optionally
4710 * removing the old trace file.
4711 *
4712 * @param removeExisting If set, the existing trace file will be removed.
4713 * @return Returns true if the trace file preparations succeeded
4714 */
4715 public static boolean prepareTraceFile(boolean removeExisting) {
4716 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4717 boolean fileReady = false;
4718 if (!TextUtils.isEmpty(tracesPath)) {
4719 File f = new File(tracesPath);
4720 if (!f.exists()) {
4721 // Ensure the enclosing directory exists
4722 File dir = f.getParentFile();
4723 if (!dir.exists()) {
4724 fileReady = dir.mkdirs();
4725 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004726 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004727 } else if (dir.isDirectory()) {
4728 fileReady = true;
4729 }
4730 } else if (removeExisting) {
4731 // Remove the previous traces file, so we don't fill the disk.
4732 // The VM will recreate it
4733 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4734 fileReady = f.delete();
4735 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004736
4737 if (removeExisting) {
4738 try {
4739 f.createNewFile();
4740 FileUtils.setPermissions(f.getAbsolutePath(),
4741 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4742 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4743 fileReady = true;
4744 } catch (IOException e) {
4745 Log.w(TAG, "Unable to make ANR traces file", e);
4746 }
4747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004748 }
4749
4750 return fileReady;
4751 }
4752
4753
4754 private final void decPersistentCountLocked(ProcessRecord app)
4755 {
4756 app.persistentActivities--;
4757 if (app.persistentActivities > 0) {
4758 // Still more of 'em...
4759 return;
4760 }
4761 if (app.persistent) {
4762 // Ah, but the application itself is persistent. Whatever!
4763 return;
4764 }
4765
4766 // App is no longer persistent... make sure it and the ones
4767 // following it in the LRU list have the correc oom_adj.
4768 updateOomAdjLocked();
4769 }
4770
4771 public void setPersistent(IBinder token, boolean isPersistent) {
4772 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4773 != PackageManager.PERMISSION_GRANTED) {
4774 String msg = "Permission Denial: setPersistent() from pid="
4775 + Binder.getCallingPid()
4776 + ", uid=" + Binder.getCallingUid()
4777 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4778 Log.w(TAG, msg);
4779 throw new SecurityException(msg);
4780 }
4781
4782 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004783 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004784 if (index < 0) {
4785 return;
4786 }
4787 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4788 ProcessRecord app = r.app;
4789
4790 if (localLOGV) Log.v(
4791 TAG, "Setting persistence " + isPersistent + ": " + r);
4792
4793 if (isPersistent) {
4794 if (r.persistent) {
4795 // Okay okay, I heard you already!
4796 if (localLOGV) Log.v(TAG, "Already persistent!");
4797 return;
4798 }
4799 r.persistent = true;
4800 app.persistentActivities++;
4801 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4802 if (app.persistentActivities > 1) {
4803 // We aren't the first...
4804 if (localLOGV) Log.v(TAG, "Not the first!");
4805 return;
4806 }
4807 if (app.persistent) {
4808 // This would be redundant.
4809 if (localLOGV) Log.v(TAG, "App is persistent!");
4810 return;
4811 }
4812
4813 // App is now persistent... make sure it and the ones
4814 // following it now have the correct oom_adj.
4815 final long origId = Binder.clearCallingIdentity();
4816 updateOomAdjLocked();
4817 Binder.restoreCallingIdentity(origId);
4818
4819 } else {
4820 if (!r.persistent) {
4821 // Okay okay, I heard you already!
4822 return;
4823 }
4824 r.persistent = false;
4825 final long origId = Binder.clearCallingIdentity();
4826 decPersistentCountLocked(app);
4827 Binder.restoreCallingIdentity(origId);
4828
4829 }
4830 }
4831 }
4832
4833 public boolean clearApplicationUserData(final String packageName,
4834 final IPackageDataObserver observer) {
4835 int uid = Binder.getCallingUid();
4836 int pid = Binder.getCallingPid();
4837 long callingId = Binder.clearCallingIdentity();
4838 try {
4839 IPackageManager pm = ActivityThread.getPackageManager();
4840 int pkgUid = -1;
4841 synchronized(this) {
4842 try {
4843 pkgUid = pm.getPackageUid(packageName);
4844 } catch (RemoteException e) {
4845 }
4846 if (pkgUid == -1) {
4847 Log.w(TAG, "Invalid packageName:" + packageName);
4848 return false;
4849 }
4850 if (uid == pkgUid || checkComponentPermission(
4851 android.Manifest.permission.CLEAR_APP_USER_DATA,
4852 pid, uid, -1)
4853 == PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08004854 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004855 } else {
4856 throw new SecurityException(pid+" does not have permission:"+
4857 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4858 "for process:"+packageName);
4859 }
4860 }
4861
4862 try {
4863 //clear application user data
4864 pm.clearApplicationUserData(packageName, observer);
4865 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4866 Uri.fromParts("package", packageName, null));
4867 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4868 broadcastIntentLocked(null, null, intent,
4869 null, null, 0, null, null, null,
4870 false, false, MY_PID, Process.SYSTEM_UID);
4871 } catch (RemoteException e) {
4872 }
4873 } finally {
4874 Binder.restoreCallingIdentity(callingId);
4875 }
4876 return true;
4877 }
4878
Dianne Hackborn03abb812010-01-04 18:43:19 -08004879 public void killBackgroundProcesses(final String packageName) {
4880 if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
4881 != PackageManager.PERMISSION_GRANTED &&
4882 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4883 != PackageManager.PERMISSION_GRANTED) {
4884 String msg = "Permission Denial: killBackgroundProcesses() from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004885 + Binder.getCallingPid()
4886 + ", uid=" + Binder.getCallingUid()
Dianne Hackborn03abb812010-01-04 18:43:19 -08004887 + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004888 Log.w(TAG, msg);
4889 throw new SecurityException(msg);
4890 }
4891
4892 long callingId = Binder.clearCallingIdentity();
4893 try {
4894 IPackageManager pm = ActivityThread.getPackageManager();
4895 int pkgUid = -1;
4896 synchronized(this) {
4897 try {
4898 pkgUid = pm.getPackageUid(packageName);
4899 } catch (RemoteException e) {
4900 }
4901 if (pkgUid == -1) {
4902 Log.w(TAG, "Invalid packageName: " + packageName);
4903 return;
4904 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004905 killPackageProcessesLocked(packageName, pkgUid,
4906 SECONDARY_SERVER_ADJ, false);
4907 }
4908 } finally {
4909 Binder.restoreCallingIdentity(callingId);
4910 }
4911 }
4912
4913 public void forceStopPackage(final String packageName) {
4914 if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
4915 != PackageManager.PERMISSION_GRANTED) {
4916 String msg = "Permission Denial: forceStopPackage() from pid="
4917 + Binder.getCallingPid()
4918 + ", uid=" + Binder.getCallingUid()
4919 + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
4920 Log.w(TAG, msg);
4921 throw new SecurityException(msg);
4922 }
4923
4924 long callingId = Binder.clearCallingIdentity();
4925 try {
4926 IPackageManager pm = ActivityThread.getPackageManager();
4927 int pkgUid = -1;
4928 synchronized(this) {
4929 try {
4930 pkgUid = pm.getPackageUid(packageName);
4931 } catch (RemoteException e) {
4932 }
4933 if (pkgUid == -1) {
4934 Log.w(TAG, "Invalid packageName: " + packageName);
4935 return;
4936 }
4937 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004938 }
4939 } finally {
4940 Binder.restoreCallingIdentity(callingId);
4941 }
4942 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004943
4944 /*
4945 * The pkg name and uid have to be specified.
4946 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4947 */
4948 public void killApplicationWithUid(String pkg, int uid) {
4949 if (pkg == null) {
4950 return;
4951 }
4952 // Make sure the uid is valid.
4953 if (uid < 0) {
4954 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4955 return;
4956 }
4957 int callerUid = Binder.getCallingUid();
4958 // Only the system server can kill an application
4959 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004960 // Post an aysnc message to kill the application
4961 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4962 msg.arg1 = uid;
4963 msg.arg2 = 0;
4964 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004965 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004966 } else {
4967 throw new SecurityException(callerUid + " cannot kill pkg: " +
4968 pkg);
4969 }
4970 }
4971
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004972 public void closeSystemDialogs(String reason) {
4973 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4974 if (reason != null) {
4975 intent.putExtra("reason", reason);
4976 }
4977
4978 final int uid = Binder.getCallingUid();
4979 final long origId = Binder.clearCallingIdentity();
4980 synchronized (this) {
4981 int i = mWatchers.beginBroadcast();
4982 while (i > 0) {
4983 i--;
4984 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4985 if (w != null) {
4986 try {
4987 w.closingSystemDialogs(reason);
4988 } catch (RemoteException e) {
4989 }
4990 }
4991 }
4992 mWatchers.finishBroadcast();
4993
Dianne Hackbornffa42482009-09-23 22:20:11 -07004994 mWindowManager.closeSystemDialogs(reason);
4995
4996 for (i=mHistory.size()-1; i>=0; i--) {
4997 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4998 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4999 finishActivityLocked(r, i,
5000 Activity.RESULT_CANCELED, null, "close-sys");
5001 }
5002 }
5003
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005004 broadcastIntentLocked(null, null, intent, null,
5005 null, 0, null, null, null, false, false, -1, uid);
5006 }
5007 Binder.restoreCallingIdentity(origId);
5008 }
5009
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005010 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005011 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005012 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5013 for (int i=pids.length-1; i>=0; i--) {
5014 infos[i] = new Debug.MemoryInfo();
5015 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005016 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005017 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005018 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005019
5020 public void killApplicationProcess(String processName, int uid) {
5021 if (processName == null) {
5022 return;
5023 }
5024
5025 int callerUid = Binder.getCallingUid();
5026 // Only the system server can kill an application
5027 if (callerUid == Process.SYSTEM_UID) {
5028 synchronized (this) {
5029 ProcessRecord app = getProcessRecordLocked(processName, uid);
5030 if (app != null) {
5031 try {
5032 app.thread.scheduleSuicide();
5033 } catch (RemoteException e) {
5034 // If the other end already died, then our work here is done.
5035 }
5036 } else {
5037 Log.w(TAG, "Process/uid not found attempting kill of "
5038 + processName + " / " + uid);
5039 }
5040 }
5041 } else {
5042 throw new SecurityException(callerUid + " cannot kill app process: " +
5043 processName);
5044 }
5045 }
5046
Dianne Hackborn03abb812010-01-04 18:43:19 -08005047 private void forceStopPackageLocked(final String packageName, int uid) {
5048 forceStopPackageLocked(packageName, uid, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005049 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5050 Uri.fromParts("package", packageName, null));
5051 intent.putExtra(Intent.EXTRA_UID, uid);
5052 broadcastIntentLocked(null, null, intent,
5053 null, null, 0, null, null, null,
5054 false, false, MY_PID, Process.SYSTEM_UID);
5055 }
5056
Dianne Hackborn03abb812010-01-04 18:43:19 -08005057 private final void killPackageProcessesLocked(String packageName, int uid,
5058 int minOomAdj, boolean callerWillRestart) {
5059 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005060
Dianne Hackborn03abb812010-01-04 18:43:19 -08005061 // Remove all processes this package may have touched: all with the
5062 // same UID (except for the system or root user), and all whose name
5063 // matches the package name.
5064 final String procNamePrefix = packageName + ":";
5065 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5066 final int NA = apps.size();
5067 for (int ia=0; ia<NA; ia++) {
5068 ProcessRecord app = apps.valueAt(ia);
5069 if (app.removed) {
5070 procs.add(app);
5071 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5072 || app.processName.equals(packageName)
5073 || app.processName.startsWith(procNamePrefix)) {
5074 if (app.setAdj >= minOomAdj) {
5075 app.removed = true;
5076 procs.add(app);
5077 }
5078 }
5079 }
5080 }
5081
5082 int N = procs.size();
5083 for (int i=0; i<N; i++) {
5084 removeProcessLocked(procs.get(i), callerWillRestart);
5085 }
5086 }
5087
5088 private final void forceStopPackageLocked(String name, int uid,
5089 boolean callerWillRestart) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005090 int i, N;
5091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005092 if (uid < 0) {
5093 try {
5094 uid = ActivityThread.getPackageManager().getPackageUid(name);
5095 } catch (RemoteException e) {
5096 }
5097 }
5098
Dianne Hackborn03abb812010-01-04 18:43:19 -08005099 Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
5100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005101 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5102 while (badApps.hasNext()) {
5103 SparseArray<Long> ba = badApps.next();
5104 if (ba.get(uid) != null) {
5105 badApps.remove();
5106 }
5107 }
5108
Dianne Hackborn03abb812010-01-04 18:43:19 -08005109 killPackageProcessesLocked(name, uid, -100, callerWillRestart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005110
5111 for (i=mHistory.size()-1; i>=0; i--) {
5112 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5113 if (r.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005114 Log.i(TAG, " Force finishing activity " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005115 if (r.app != null) {
5116 r.app.removed = true;
5117 }
5118 r.app = null;
5119 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5120 }
5121 }
5122
5123 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5124 for (ServiceRecord service : mServices.values()) {
5125 if (service.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005126 Log.i(TAG, " Force stopping service " + service);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005127 if (service.app != null) {
5128 service.app.removed = true;
5129 }
5130 service.app = null;
5131 services.add(service);
5132 }
5133 }
5134
5135 N = services.size();
5136 for (i=0; i<N; i++) {
5137 bringDownServiceLocked(services.get(i), true);
5138 }
5139
5140 resumeTopActivityLocked(null);
5141 }
5142
5143 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5144 final String name = app.processName;
5145 final int uid = app.info.uid;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005146 if (DEBUG_PROCESSES) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005147 TAG, "Force removing process " + app + " (" + name
5148 + "/" + uid + ")");
5149
5150 mProcessNames.remove(name, uid);
5151 boolean needRestart = false;
5152 if (app.pid > 0 && app.pid != MY_PID) {
5153 int pid = app.pid;
5154 synchronized (mPidsSelfLocked) {
5155 mPidsSelfLocked.remove(pid);
5156 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5157 }
5158 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005159 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005160 Process.killProcess(pid);
5161
5162 if (app.persistent) {
5163 if (!callerWillRestart) {
5164 addAppLocked(app.info);
5165 } else {
5166 needRestart = true;
5167 }
5168 }
5169 } else {
5170 mRemovedProcesses.add(app);
5171 }
5172
5173 return needRestart;
5174 }
5175
5176 private final void processStartTimedOutLocked(ProcessRecord app) {
5177 final int pid = app.pid;
5178 boolean gone = false;
5179 synchronized (mPidsSelfLocked) {
5180 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5181 if (knownApp != null && knownApp.thread == null) {
5182 mPidsSelfLocked.remove(pid);
5183 gone = true;
5184 }
5185 }
5186
5187 if (gone) {
5188 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005189 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005190 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005191 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005192 // Take care of any launching providers waiting for this process.
5193 checkAppInLaunchingProvidersLocked(app, true);
5194 // Take care of any services that are waiting for the process.
5195 for (int i=0; i<mPendingServices.size(); i++) {
5196 ServiceRecord sr = mPendingServices.get(i);
5197 if (app.info.uid == sr.appInfo.uid
5198 && app.processName.equals(sr.processName)) {
5199 Log.w(TAG, "Forcing bringing down service: " + sr);
5200 mPendingServices.remove(i);
5201 i--;
5202 bringDownServiceLocked(sr, true);
5203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005204 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005205 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005206 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5207 Log.w(TAG, "Unattached app died before backup, skipping");
5208 try {
5209 IBackupManager bm = IBackupManager.Stub.asInterface(
5210 ServiceManager.getService(Context.BACKUP_SERVICE));
5211 bm.agentDisconnected(app.info.packageName);
5212 } catch (RemoteException e) {
5213 // Can't happen; the backup manager is local
5214 }
5215 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005216 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5217 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5218 mPendingBroadcast = null;
5219 scheduleBroadcastsLocked();
5220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005221 } else {
5222 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5223 }
5224 }
5225
5226 private final boolean attachApplicationLocked(IApplicationThread thread,
5227 int pid) {
5228
5229 // Find the application record that is being attached... either via
5230 // the pid if we are running in multiple processes, or just pull the
5231 // next app record if we are emulating process with anonymous threads.
5232 ProcessRecord app;
5233 if (pid != MY_PID && pid >= 0) {
5234 synchronized (mPidsSelfLocked) {
5235 app = mPidsSelfLocked.get(pid);
5236 }
5237 } else if (mStartingProcesses.size() > 0) {
5238 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005239 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005240 } else {
5241 app = null;
5242 }
5243
5244 if (app == null) {
5245 Log.w(TAG, "No pending application record for pid " + pid
5246 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005247 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005248 if (pid > 0 && pid != MY_PID) {
5249 Process.killProcess(pid);
5250 } else {
5251 try {
5252 thread.scheduleExit();
5253 } catch (Exception e) {
5254 // Ignore exceptions.
5255 }
5256 }
5257 return false;
5258 }
5259
5260 // If this application record is still attached to a previous
5261 // process, clean it up now.
5262 if (app.thread != null) {
5263 handleAppDiedLocked(app, true);
5264 }
5265
5266 // Tell the process all about itself.
5267
5268 if (localLOGV) Log.v(
5269 TAG, "Binding process pid " + pid + " to record " + app);
5270
5271 String processName = app.processName;
5272 try {
5273 thread.asBinder().linkToDeath(new AppDeathRecipient(
5274 app, pid, thread), 0);
5275 } catch (RemoteException e) {
5276 app.resetPackageList();
5277 startProcessLocked(app, "link fail", processName);
5278 return false;
5279 }
5280
Doug Zongker2bec3d42009-12-04 12:52:44 -08005281 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005282
5283 app.thread = thread;
5284 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005285 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5286 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005287 app.forcingToForeground = null;
5288 app.foregroundServices = false;
5289 app.debugging = false;
5290
5291 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5292
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005293 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5294 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005295
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005296 if (!normalMode) {
5297 Log.i(TAG, "Launching preboot mode app: " + app);
5298 }
5299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005300 if (localLOGV) Log.v(
5301 TAG, "New app record " + app
5302 + " thread=" + thread.asBinder() + " pid=" + pid);
5303 try {
5304 int testMode = IApplicationThread.DEBUG_OFF;
5305 if (mDebugApp != null && mDebugApp.equals(processName)) {
5306 testMode = mWaitForDebugger
5307 ? IApplicationThread.DEBUG_WAIT
5308 : IApplicationThread.DEBUG_ON;
5309 app.debugging = true;
5310 if (mDebugTransient) {
5311 mDebugApp = mOrigDebugApp;
5312 mWaitForDebugger = mOrigWaitForDebugger;
5313 }
5314 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005315
Christopher Tate181fafa2009-05-14 11:12:14 -07005316 // If the app is being launched for restore or full backup, set it up specially
5317 boolean isRestrictedBackupMode = false;
5318 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5319 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5320 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5321 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005322
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005323 ensurePackageDexOpt(app.instrumentationInfo != null
5324 ? app.instrumentationInfo.packageName
5325 : app.info.packageName);
5326 if (app.instrumentationClass != null) {
5327 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005328 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005329 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5330 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005331 thread.bindApplication(processName, app.instrumentationInfo != null
5332 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005333 app.instrumentationClass, app.instrumentationProfileFile,
5334 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005335 isRestrictedBackupMode || !normalMode,
5336 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005337 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005338 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005339 } catch (Exception e) {
5340 // todo: Yikes! What should we do? For now we will try to
5341 // start another process, but that could easily get us in
5342 // an infinite loop of restarting processes...
5343 Log.w(TAG, "Exception thrown during bind!", e);
5344
5345 app.resetPackageList();
5346 startProcessLocked(app, "bind fail", processName);
5347 return false;
5348 }
5349
5350 // Remove this record from the list of starting applications.
5351 mPersistentStartingProcesses.remove(app);
5352 mProcessesOnHold.remove(app);
5353
5354 boolean badApp = false;
5355 boolean didSomething = false;
5356
5357 // See if the top visible activity is waiting to run in this process...
5358 HistoryRecord hr = topRunningActivityLocked(null);
5359 if (hr != null) {
5360 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5361 && processName.equals(hr.processName)) {
5362 try {
5363 if (realStartActivityLocked(hr, app, true, true)) {
5364 didSomething = true;
5365 }
5366 } catch (Exception e) {
5367 Log.w(TAG, "Exception in new application when starting activity "
5368 + hr.intent.getComponent().flattenToShortString(), e);
5369 badApp = true;
5370 }
5371 } else {
5372 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5373 }
5374 }
5375
5376 // Find any services that should be running in this process...
5377 if (!badApp && mPendingServices.size() > 0) {
5378 ServiceRecord sr = null;
5379 try {
5380 for (int i=0; i<mPendingServices.size(); i++) {
5381 sr = mPendingServices.get(i);
5382 if (app.info.uid != sr.appInfo.uid
5383 || !processName.equals(sr.processName)) {
5384 continue;
5385 }
5386
5387 mPendingServices.remove(i);
5388 i--;
5389 realStartServiceLocked(sr, app);
5390 didSomething = true;
5391 }
5392 } catch (Exception e) {
5393 Log.w(TAG, "Exception in new application when starting service "
5394 + sr.shortName, e);
5395 badApp = true;
5396 }
5397 }
5398
5399 // Check if the next broadcast receiver is in this process...
5400 BroadcastRecord br = mPendingBroadcast;
5401 if (!badApp && br != null && br.curApp == app) {
5402 try {
5403 mPendingBroadcast = null;
5404 processCurBroadcastLocked(br, app);
5405 didSomething = true;
5406 } catch (Exception e) {
5407 Log.w(TAG, "Exception in new application when starting receiver "
5408 + br.curComponent.flattenToShortString(), e);
5409 badApp = true;
5410 logBroadcastReceiverDiscard(br);
5411 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5412 br.resultExtras, br.resultAbort, true);
5413 scheduleBroadcastsLocked();
5414 }
5415 }
5416
Christopher Tate181fafa2009-05-14 11:12:14 -07005417 // Check whether the next backup agent is in this process...
5418 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5419 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005420 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005421 try {
5422 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5423 } catch (Exception e) {
5424 Log.w(TAG, "Exception scheduling backup agent creation: ");
5425 e.printStackTrace();
5426 }
5427 }
5428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005429 if (badApp) {
5430 // todo: Also need to kill application to deal with all
5431 // kinds of exceptions.
5432 handleAppDiedLocked(app, false);
5433 return false;
5434 }
5435
5436 if (!didSomething) {
5437 updateOomAdjLocked();
5438 }
5439
5440 return true;
5441 }
5442
5443 public final void attachApplication(IApplicationThread thread) {
5444 synchronized (this) {
5445 int callingPid = Binder.getCallingPid();
5446 final long origId = Binder.clearCallingIdentity();
5447 attachApplicationLocked(thread, callingPid);
5448 Binder.restoreCallingIdentity(origId);
5449 }
5450 }
5451
Dianne Hackborne88846e2009-09-30 21:34:25 -07005452 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005453 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005454 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005455 Binder.restoreCallingIdentity(origId);
5456 }
5457
5458 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5459 boolean remove) {
5460 int N = mStoppingActivities.size();
5461 if (N <= 0) return null;
5462
5463 ArrayList<HistoryRecord> stops = null;
5464
5465 final boolean nowVisible = mResumedActivity != null
5466 && mResumedActivity.nowVisible
5467 && !mResumedActivity.waitingVisible;
5468 for (int i=0; i<N; i++) {
5469 HistoryRecord s = mStoppingActivities.get(i);
5470 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5471 + nowVisible + " waitingVisible=" + s.waitingVisible
5472 + " finishing=" + s.finishing);
5473 if (s.waitingVisible && nowVisible) {
5474 mWaitingVisibleActivities.remove(s);
5475 s.waitingVisible = false;
5476 if (s.finishing) {
5477 // If this activity is finishing, it is sitting on top of
5478 // everyone else but we now know it is no longer needed...
5479 // so get rid of it. Otherwise, we need to go through the
5480 // normal flow and hide it once we determine that it is
5481 // hidden by the activities in front of it.
5482 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5483 mWindowManager.setAppVisibility(s, false);
5484 }
5485 }
5486 if (!s.waitingVisible && remove) {
5487 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5488 if (stops == null) {
5489 stops = new ArrayList<HistoryRecord>();
5490 }
5491 stops.add(s);
5492 mStoppingActivities.remove(i);
5493 N--;
5494 i--;
5495 }
5496 }
5497
5498 return stops;
5499 }
5500
5501 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005502 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005503 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005504 mWindowManager.enableScreenAfterBoot();
5505 }
5506
Dianne Hackborne88846e2009-09-30 21:34:25 -07005507 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5508 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005509 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5510
5511 ArrayList<HistoryRecord> stops = null;
5512 ArrayList<HistoryRecord> finishes = null;
5513 ArrayList<HistoryRecord> thumbnails = null;
5514 int NS = 0;
5515 int NF = 0;
5516 int NT = 0;
5517 IApplicationThread sendThumbnail = null;
5518 boolean booting = false;
5519 boolean enableScreen = false;
5520
5521 synchronized (this) {
5522 if (token != null) {
5523 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5524 }
5525
5526 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005527 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005528 if (index >= 0) {
5529 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5530
Dianne Hackborne88846e2009-09-30 21:34:25 -07005531 // This is a hack to semi-deal with a race condition
5532 // in the client where it can be constructed with a
5533 // newer configuration from when we asked it to launch.
5534 // We'll update with whatever configuration it now says
5535 // it used to launch.
5536 if (config != null) {
5537 r.configuration = config;
5538 }
5539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005540 // No longer need to keep the device awake.
5541 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5542 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5543 mLaunchingActivity.release();
5544 }
5545
5546 // We are now idle. If someone is waiting for a thumbnail from
5547 // us, we can now deliver.
5548 r.idle = true;
5549 scheduleAppGcsLocked();
5550 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5551 sendThumbnail = r.app.thread;
5552 r.thumbnailNeeded = false;
5553 }
5554
5555 // If this activity is fullscreen, set up to hide those under it.
5556
5557 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5558 ensureActivitiesVisibleLocked(null, 0);
5559
5560 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5561 if (!mBooted && !fromTimeout) {
5562 mBooted = true;
5563 enableScreen = true;
5564 }
5565 }
5566
5567 // Atomically retrieve all of the other things to do.
5568 stops = processStoppingActivitiesLocked(true);
5569 NS = stops != null ? stops.size() : 0;
5570 if ((NF=mFinishingActivities.size()) > 0) {
5571 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5572 mFinishingActivities.clear();
5573 }
5574 if ((NT=mCancelledThumbnails.size()) > 0) {
5575 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5576 mCancelledThumbnails.clear();
5577 }
5578
5579 booting = mBooting;
5580 mBooting = false;
5581 }
5582
5583 int i;
5584
5585 // Send thumbnail if requested.
5586 if (sendThumbnail != null) {
5587 try {
5588 sendThumbnail.requestThumbnail(token);
5589 } catch (Exception e) {
5590 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5591 sendPendingThumbnail(null, token, null, null, true);
5592 }
5593 }
5594
5595 // Stop any activities that are scheduled to do so but have been
5596 // waiting for the next one to start.
5597 for (i=0; i<NS; i++) {
5598 HistoryRecord r = (HistoryRecord)stops.get(i);
5599 synchronized (this) {
5600 if (r.finishing) {
5601 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5602 } else {
5603 stopActivityLocked(r);
5604 }
5605 }
5606 }
5607
5608 // Finish any activities that are scheduled to do so but have been
5609 // waiting for the next one to start.
5610 for (i=0; i<NF; i++) {
5611 HistoryRecord r = (HistoryRecord)finishes.get(i);
5612 synchronized (this) {
5613 destroyActivityLocked(r, true);
5614 }
5615 }
5616
5617 // Report back to any thumbnail receivers.
5618 for (i=0; i<NT; i++) {
5619 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5620 sendPendingThumbnail(r, null, null, null, true);
5621 }
5622
5623 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005624 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005625 }
5626
5627 trimApplications();
5628 //dump();
5629 //mWindowManager.dump();
5630
5631 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005632 enableScreenAfterBoot();
5633 }
5634 }
5635
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005636 final void finishBooting() {
5637 // Ensure that any processes we had put on hold are now started
5638 // up.
5639 final int NP = mProcessesOnHold.size();
5640 if (NP > 0) {
5641 ArrayList<ProcessRecord> procs =
5642 new ArrayList<ProcessRecord>(mProcessesOnHold);
5643 for (int ip=0; ip<NP; ip++) {
5644 this.startProcessLocked(procs.get(ip), "on-hold", null);
5645 }
5646 }
5647 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5648 // Tell anyone interested that we are done booting!
5649 synchronized (this) {
5650 broadcastIntentLocked(null, null,
5651 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5652 null, null, 0, null, null,
5653 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5654 false, false, MY_PID, Process.SYSTEM_UID);
5655 }
5656 }
5657 }
5658
5659 final void ensureBootCompleted() {
5660 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005661 boolean enableScreen;
5662 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005663 booting = mBooting;
5664 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005665 enableScreen = !mBooted;
5666 mBooted = true;
5667 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005668
5669 if (booting) {
5670 finishBooting();
5671 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005672
5673 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005674 enableScreenAfterBoot();
5675 }
5676 }
5677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005678 public final void activityPaused(IBinder token, Bundle icicle) {
5679 // Refuse possible leaked file descriptors
5680 if (icicle != null && icicle.hasFileDescriptors()) {
5681 throw new IllegalArgumentException("File descriptors passed in Bundle");
5682 }
5683
5684 final long origId = Binder.clearCallingIdentity();
5685 activityPaused(token, icicle, false);
5686 Binder.restoreCallingIdentity(origId);
5687 }
5688
5689 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5690 if (DEBUG_PAUSE) Log.v(
5691 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5692 + ", timeout=" + timeout);
5693
5694 HistoryRecord r = null;
5695
5696 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005697 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005698 if (index >= 0) {
5699 r = (HistoryRecord)mHistory.get(index);
5700 if (!timeout) {
5701 r.icicle = icicle;
5702 r.haveState = true;
5703 }
5704 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5705 if (mPausingActivity == r) {
5706 r.state = ActivityState.PAUSED;
5707 completePauseLocked();
5708 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005709 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005710 System.identityHashCode(r), r.shortComponentName,
5711 mPausingActivity != null
5712 ? mPausingActivity.shortComponentName : "(none)");
5713 }
5714 }
5715 }
5716 }
5717
5718 public final void activityStopped(IBinder token, Bitmap thumbnail,
5719 CharSequence description) {
5720 if (localLOGV) Log.v(
5721 TAG, "Activity stopped: token=" + token);
5722
5723 HistoryRecord r = null;
5724
5725 final long origId = Binder.clearCallingIdentity();
5726
5727 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005728 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005729 if (index >= 0) {
5730 r = (HistoryRecord)mHistory.get(index);
5731 r.thumbnail = thumbnail;
5732 r.description = description;
5733 r.stopped = true;
5734 r.state = ActivityState.STOPPED;
5735 if (!r.finishing) {
5736 if (r.configDestroy) {
5737 destroyActivityLocked(r, true);
5738 resumeTopActivityLocked(null);
5739 }
5740 }
5741 }
5742 }
5743
5744 if (r != null) {
5745 sendPendingThumbnail(r, null, null, null, false);
5746 }
5747
5748 trimApplications();
5749
5750 Binder.restoreCallingIdentity(origId);
5751 }
5752
5753 public final void activityDestroyed(IBinder token) {
5754 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5755 synchronized (this) {
5756 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5757
Dianne Hackborn75b03852009-06-12 15:43:26 -07005758 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005759 if (index >= 0) {
5760 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5761 if (r.state == ActivityState.DESTROYING) {
5762 final long origId = Binder.clearCallingIdentity();
5763 removeActivityFromHistoryLocked(r);
5764 Binder.restoreCallingIdentity(origId);
5765 }
5766 }
5767 }
5768 }
5769
5770 public String getCallingPackage(IBinder token) {
5771 synchronized (this) {
5772 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005773 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005774 }
5775 }
5776
5777 public ComponentName getCallingActivity(IBinder token) {
5778 synchronized (this) {
5779 HistoryRecord r = getCallingRecordLocked(token);
5780 return r != null ? r.intent.getComponent() : null;
5781 }
5782 }
5783
5784 private HistoryRecord getCallingRecordLocked(IBinder token) {
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 != null) {
5789 return r.resultTo;
5790 }
5791 }
5792 return null;
5793 }
5794
5795 public ComponentName getActivityClassForToken(IBinder token) {
5796 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005797 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005798 if (index >= 0) {
5799 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5800 return r.intent.getComponent();
5801 }
5802 return null;
5803 }
5804 }
5805
5806 public String getPackageForToken(IBinder token) {
5807 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005808 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005809 if (index >= 0) {
5810 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5811 return r.packageName;
5812 }
5813 return null;
5814 }
5815 }
5816
5817 public IIntentSender getIntentSender(int type,
5818 String packageName, IBinder token, String resultWho,
5819 int requestCode, Intent intent, String resolvedType, int flags) {
5820 // Refuse possible leaked file descriptors
5821 if (intent != null && intent.hasFileDescriptors() == true) {
5822 throw new IllegalArgumentException("File descriptors passed in Intent");
5823 }
5824
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005825 if (type == INTENT_SENDER_BROADCAST) {
5826 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5827 throw new IllegalArgumentException(
5828 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5829 }
5830 }
5831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005832 synchronized(this) {
5833 int callingUid = Binder.getCallingUid();
5834 try {
5835 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5836 Process.supportsProcesses()) {
5837 int uid = ActivityThread.getPackageManager()
5838 .getPackageUid(packageName);
5839 if (uid != Binder.getCallingUid()) {
5840 String msg = "Permission Denial: getIntentSender() from pid="
5841 + Binder.getCallingPid()
5842 + ", uid=" + Binder.getCallingUid()
5843 + ", (need uid=" + uid + ")"
5844 + " is not allowed to send as package " + packageName;
5845 Log.w(TAG, msg);
5846 throw new SecurityException(msg);
5847 }
5848 }
5849 } catch (RemoteException e) {
5850 throw new SecurityException(e);
5851 }
5852 HistoryRecord activity = null;
5853 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005854 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005855 if (index < 0) {
5856 return null;
5857 }
5858 activity = (HistoryRecord)mHistory.get(index);
5859 if (activity.finishing) {
5860 return null;
5861 }
5862 }
5863
5864 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5865 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5866 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5867 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5868 |PendingIntent.FLAG_UPDATE_CURRENT);
5869
5870 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5871 type, packageName, activity, resultWho,
5872 requestCode, intent, resolvedType, flags);
5873 WeakReference<PendingIntentRecord> ref;
5874 ref = mIntentSenderRecords.get(key);
5875 PendingIntentRecord rec = ref != null ? ref.get() : null;
5876 if (rec != null) {
5877 if (!cancelCurrent) {
5878 if (updateCurrent) {
5879 rec.key.requestIntent.replaceExtras(intent);
5880 }
5881 return rec;
5882 }
5883 rec.canceled = true;
5884 mIntentSenderRecords.remove(key);
5885 }
5886 if (noCreate) {
5887 return rec;
5888 }
5889 rec = new PendingIntentRecord(this, key, callingUid);
5890 mIntentSenderRecords.put(key, rec.ref);
5891 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5892 if (activity.pendingResults == null) {
5893 activity.pendingResults
5894 = new HashSet<WeakReference<PendingIntentRecord>>();
5895 }
5896 activity.pendingResults.add(rec.ref);
5897 }
5898 return rec;
5899 }
5900 }
5901
5902 public void cancelIntentSender(IIntentSender sender) {
5903 if (!(sender instanceof PendingIntentRecord)) {
5904 return;
5905 }
5906 synchronized(this) {
5907 PendingIntentRecord rec = (PendingIntentRecord)sender;
5908 try {
5909 int uid = ActivityThread.getPackageManager()
5910 .getPackageUid(rec.key.packageName);
5911 if (uid != Binder.getCallingUid()) {
5912 String msg = "Permission Denial: cancelIntentSender() from pid="
5913 + Binder.getCallingPid()
5914 + ", uid=" + Binder.getCallingUid()
5915 + " is not allowed to cancel packges "
5916 + rec.key.packageName;
5917 Log.w(TAG, msg);
5918 throw new SecurityException(msg);
5919 }
5920 } catch (RemoteException e) {
5921 throw new SecurityException(e);
5922 }
5923 cancelIntentSenderLocked(rec, true);
5924 }
5925 }
5926
5927 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5928 rec.canceled = true;
5929 mIntentSenderRecords.remove(rec.key);
5930 if (cleanActivity && rec.key.activity != null) {
5931 rec.key.activity.pendingResults.remove(rec.ref);
5932 }
5933 }
5934
5935 public String getPackageForIntentSender(IIntentSender pendingResult) {
5936 if (!(pendingResult instanceof PendingIntentRecord)) {
5937 return null;
5938 }
5939 synchronized(this) {
5940 try {
5941 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5942 return res.key.packageName;
5943 } catch (ClassCastException e) {
5944 }
5945 }
5946 return null;
5947 }
5948
5949 public void setProcessLimit(int max) {
5950 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5951 "setProcessLimit()");
5952 mProcessLimit = max;
5953 }
5954
5955 public int getProcessLimit() {
5956 return mProcessLimit;
5957 }
5958
5959 void foregroundTokenDied(ForegroundToken token) {
5960 synchronized (ActivityManagerService.this) {
5961 synchronized (mPidsSelfLocked) {
5962 ForegroundToken cur
5963 = mForegroundProcesses.get(token.pid);
5964 if (cur != token) {
5965 return;
5966 }
5967 mForegroundProcesses.remove(token.pid);
5968 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5969 if (pr == null) {
5970 return;
5971 }
5972 pr.forcingToForeground = null;
5973 pr.foregroundServices = false;
5974 }
5975 updateOomAdjLocked();
5976 }
5977 }
5978
5979 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5980 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5981 "setProcessForeground()");
5982 synchronized(this) {
5983 boolean changed = false;
5984
5985 synchronized (mPidsSelfLocked) {
5986 ProcessRecord pr = mPidsSelfLocked.get(pid);
5987 if (pr == null) {
5988 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5989 return;
5990 }
5991 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5992 if (oldToken != null) {
5993 oldToken.token.unlinkToDeath(oldToken, 0);
5994 mForegroundProcesses.remove(pid);
5995 pr.forcingToForeground = null;
5996 changed = true;
5997 }
5998 if (isForeground && token != null) {
5999 ForegroundToken newToken = new ForegroundToken() {
6000 public void binderDied() {
6001 foregroundTokenDied(this);
6002 }
6003 };
6004 newToken.pid = pid;
6005 newToken.token = token;
6006 try {
6007 token.linkToDeath(newToken, 0);
6008 mForegroundProcesses.put(pid, newToken);
6009 pr.forcingToForeground = token;
6010 changed = true;
6011 } catch (RemoteException e) {
6012 // If the process died while doing this, we will later
6013 // do the cleanup with the process death link.
6014 }
6015 }
6016 }
6017
6018 if (changed) {
6019 updateOomAdjLocked();
6020 }
6021 }
6022 }
6023
6024 // =========================================================
6025 // PERMISSIONS
6026 // =========================================================
6027
6028 static class PermissionController extends IPermissionController.Stub {
6029 ActivityManagerService mActivityManagerService;
6030 PermissionController(ActivityManagerService activityManagerService) {
6031 mActivityManagerService = activityManagerService;
6032 }
6033
6034 public boolean checkPermission(String permission, int pid, int uid) {
6035 return mActivityManagerService.checkPermission(permission, pid,
6036 uid) == PackageManager.PERMISSION_GRANTED;
6037 }
6038 }
6039
6040 /**
6041 * This can be called with or without the global lock held.
6042 */
6043 int checkComponentPermission(String permission, int pid, int uid,
6044 int reqUid) {
6045 // We might be performing an operation on behalf of an indirect binder
6046 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6047 // client identity accordingly before proceeding.
6048 Identity tlsIdentity = sCallerIdentity.get();
6049 if (tlsIdentity != null) {
6050 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6051 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6052 uid = tlsIdentity.uid;
6053 pid = tlsIdentity.pid;
6054 }
6055
6056 // Root, system server and our own process get to do everything.
6057 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6058 !Process.supportsProcesses()) {
6059 return PackageManager.PERMISSION_GRANTED;
6060 }
6061 // If the target requires a specific UID, always fail for others.
6062 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006063 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006064 return PackageManager.PERMISSION_DENIED;
6065 }
6066 if (permission == null) {
6067 return PackageManager.PERMISSION_GRANTED;
6068 }
6069 try {
6070 return ActivityThread.getPackageManager()
6071 .checkUidPermission(permission, uid);
6072 } catch (RemoteException e) {
6073 // Should never happen, but if it does... deny!
6074 Log.e(TAG, "PackageManager is dead?!?", e);
6075 }
6076 return PackageManager.PERMISSION_DENIED;
6077 }
6078
6079 /**
6080 * As the only public entry point for permissions checking, this method
6081 * can enforce the semantic that requesting a check on a null global
6082 * permission is automatically denied. (Internally a null permission
6083 * string is used when calling {@link #checkComponentPermission} in cases
6084 * when only uid-based security is needed.)
6085 *
6086 * This can be called with or without the global lock held.
6087 */
6088 public int checkPermission(String permission, int pid, int uid) {
6089 if (permission == null) {
6090 return PackageManager.PERMISSION_DENIED;
6091 }
6092 return checkComponentPermission(permission, pid, uid, -1);
6093 }
6094
6095 /**
6096 * Binder IPC calls go through the public entry point.
6097 * This can be called with or without the global lock held.
6098 */
6099 int checkCallingPermission(String permission) {
6100 return checkPermission(permission,
6101 Binder.getCallingPid(),
6102 Binder.getCallingUid());
6103 }
6104
6105 /**
6106 * This can be called with or without the global lock held.
6107 */
6108 void enforceCallingPermission(String permission, String func) {
6109 if (checkCallingPermission(permission)
6110 == PackageManager.PERMISSION_GRANTED) {
6111 return;
6112 }
6113
6114 String msg = "Permission Denial: " + func + " from pid="
6115 + Binder.getCallingPid()
6116 + ", uid=" + Binder.getCallingUid()
6117 + " requires " + permission;
6118 Log.w(TAG, msg);
6119 throw new SecurityException(msg);
6120 }
6121
6122 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6123 ProviderInfo pi, int uid, int modeFlags) {
6124 try {
6125 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6126 if ((pi.readPermission != null) &&
6127 (pm.checkUidPermission(pi.readPermission, uid)
6128 != PackageManager.PERMISSION_GRANTED)) {
6129 return false;
6130 }
6131 }
6132 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6133 if ((pi.writePermission != null) &&
6134 (pm.checkUidPermission(pi.writePermission, uid)
6135 != PackageManager.PERMISSION_GRANTED)) {
6136 return false;
6137 }
6138 }
6139 return true;
6140 } catch (RemoteException e) {
6141 return false;
6142 }
6143 }
6144
6145 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6146 int modeFlags) {
6147 // Root gets to do everything.
6148 if (uid == 0 || !Process.supportsProcesses()) {
6149 return true;
6150 }
6151 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6152 if (perms == null) return false;
6153 UriPermission perm = perms.get(uri);
6154 if (perm == null) return false;
6155 return (modeFlags&perm.modeFlags) == modeFlags;
6156 }
6157
6158 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6159 // Another redirected-binder-call permissions check as in
6160 // {@link checkComponentPermission}.
6161 Identity tlsIdentity = sCallerIdentity.get();
6162 if (tlsIdentity != null) {
6163 uid = tlsIdentity.uid;
6164 pid = tlsIdentity.pid;
6165 }
6166
6167 // Our own process gets to do everything.
6168 if (pid == MY_PID) {
6169 return PackageManager.PERMISSION_GRANTED;
6170 }
6171 synchronized(this) {
6172 return checkUriPermissionLocked(uri, uid, modeFlags)
6173 ? PackageManager.PERMISSION_GRANTED
6174 : PackageManager.PERMISSION_DENIED;
6175 }
6176 }
6177
6178 private void grantUriPermissionLocked(int callingUid,
6179 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6180 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6181 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6182 if (modeFlags == 0) {
6183 return;
6184 }
6185
6186 final IPackageManager pm = ActivityThread.getPackageManager();
6187
6188 // If this is not a content: uri, we can't do anything with it.
6189 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6190 return;
6191 }
6192
6193 String name = uri.getAuthority();
6194 ProviderInfo pi = null;
6195 ContentProviderRecord cpr
6196 = (ContentProviderRecord)mProvidersByName.get(name);
6197 if (cpr != null) {
6198 pi = cpr.info;
6199 } else {
6200 try {
6201 pi = pm.resolveContentProvider(name,
6202 PackageManager.GET_URI_PERMISSION_PATTERNS);
6203 } catch (RemoteException ex) {
6204 }
6205 }
6206 if (pi == null) {
6207 Log.w(TAG, "No content provider found for: " + name);
6208 return;
6209 }
6210
6211 int targetUid;
6212 try {
6213 targetUid = pm.getPackageUid(targetPkg);
6214 if (targetUid < 0) {
6215 return;
6216 }
6217 } catch (RemoteException ex) {
6218 return;
6219 }
6220
6221 // First... does the target actually need this permission?
6222 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6223 // No need to grant the target this permission.
6224 return;
6225 }
6226
6227 // Second... maybe someone else has already granted the
6228 // permission?
6229 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6230 // No need to grant the target this permission.
6231 return;
6232 }
6233
6234 // Third... is the provider allowing granting of URI permissions?
6235 if (!pi.grantUriPermissions) {
6236 throw new SecurityException("Provider " + pi.packageName
6237 + "/" + pi.name
6238 + " does not allow granting of Uri permissions (uri "
6239 + uri + ")");
6240 }
6241 if (pi.uriPermissionPatterns != null) {
6242 final int N = pi.uriPermissionPatterns.length;
6243 boolean allowed = false;
6244 for (int i=0; i<N; i++) {
6245 if (pi.uriPermissionPatterns[i] != null
6246 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6247 allowed = true;
6248 break;
6249 }
6250 }
6251 if (!allowed) {
6252 throw new SecurityException("Provider " + pi.packageName
6253 + "/" + pi.name
6254 + " does not allow granting of permission to path of Uri "
6255 + uri);
6256 }
6257 }
6258
6259 // Fourth... does the caller itself have permission to access
6260 // this uri?
6261 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6262 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6263 throw new SecurityException("Uid " + callingUid
6264 + " does not have permission to uri " + uri);
6265 }
6266 }
6267
6268 // Okay! So here we are: the caller has the assumed permission
6269 // to the uri, and the target doesn't. Let's now give this to
6270 // the target.
6271
6272 HashMap<Uri, UriPermission> targetUris
6273 = mGrantedUriPermissions.get(targetUid);
6274 if (targetUris == null) {
6275 targetUris = new HashMap<Uri, UriPermission>();
6276 mGrantedUriPermissions.put(targetUid, targetUris);
6277 }
6278
6279 UriPermission perm = targetUris.get(uri);
6280 if (perm == null) {
6281 perm = new UriPermission(targetUid, uri);
6282 targetUris.put(uri, perm);
6283
6284 }
6285 perm.modeFlags |= modeFlags;
6286 if (activity == null) {
6287 perm.globalModeFlags |= modeFlags;
6288 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6289 perm.readActivities.add(activity);
6290 if (activity.readUriPermissions == null) {
6291 activity.readUriPermissions = new HashSet<UriPermission>();
6292 }
6293 activity.readUriPermissions.add(perm);
6294 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6295 perm.writeActivities.add(activity);
6296 if (activity.writeUriPermissions == null) {
6297 activity.writeUriPermissions = new HashSet<UriPermission>();
6298 }
6299 activity.writeUriPermissions.add(perm);
6300 }
6301 }
6302
6303 private void grantUriPermissionFromIntentLocked(int callingUid,
6304 String targetPkg, Intent intent, HistoryRecord activity) {
6305 if (intent == null) {
6306 return;
6307 }
6308 Uri data = intent.getData();
6309 if (data == null) {
6310 return;
6311 }
6312 grantUriPermissionLocked(callingUid, targetPkg, data,
6313 intent.getFlags(), activity);
6314 }
6315
6316 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6317 Uri uri, int modeFlags) {
6318 synchronized(this) {
6319 final ProcessRecord r = getRecordForAppLocked(caller);
6320 if (r == null) {
6321 throw new SecurityException("Unable to find app for caller "
6322 + caller
6323 + " when granting permission to uri " + uri);
6324 }
6325 if (targetPkg == null) {
6326 Log.w(TAG, "grantUriPermission: null target");
6327 return;
6328 }
6329 if (uri == null) {
6330 Log.w(TAG, "grantUriPermission: null uri");
6331 return;
6332 }
6333
6334 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6335 null);
6336 }
6337 }
6338
6339 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6340 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6341 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6342 HashMap<Uri, UriPermission> perms
6343 = mGrantedUriPermissions.get(perm.uid);
6344 if (perms != null) {
6345 perms.remove(perm.uri);
6346 if (perms.size() == 0) {
6347 mGrantedUriPermissions.remove(perm.uid);
6348 }
6349 }
6350 }
6351 }
6352
6353 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6354 if (activity.readUriPermissions != null) {
6355 for (UriPermission perm : activity.readUriPermissions) {
6356 perm.readActivities.remove(activity);
6357 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6358 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6359 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6360 removeUriPermissionIfNeededLocked(perm);
6361 }
6362 }
6363 }
6364 if (activity.writeUriPermissions != null) {
6365 for (UriPermission perm : activity.writeUriPermissions) {
6366 perm.writeActivities.remove(activity);
6367 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6368 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6369 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6370 removeUriPermissionIfNeededLocked(perm);
6371 }
6372 }
6373 }
6374 }
6375
6376 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6377 int modeFlags) {
6378 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6379 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6380 if (modeFlags == 0) {
6381 return;
6382 }
6383
6384 final IPackageManager pm = ActivityThread.getPackageManager();
6385
6386 final String authority = uri.getAuthority();
6387 ProviderInfo pi = null;
6388 ContentProviderRecord cpr
6389 = (ContentProviderRecord)mProvidersByName.get(authority);
6390 if (cpr != null) {
6391 pi = cpr.info;
6392 } else {
6393 try {
6394 pi = pm.resolveContentProvider(authority,
6395 PackageManager.GET_URI_PERMISSION_PATTERNS);
6396 } catch (RemoteException ex) {
6397 }
6398 }
6399 if (pi == null) {
6400 Log.w(TAG, "No content provider found for: " + authority);
6401 return;
6402 }
6403
6404 // Does the caller have this permission on the URI?
6405 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6406 // Right now, if you are not the original owner of the permission,
6407 // you are not allowed to revoke it.
6408 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6409 throw new SecurityException("Uid " + callingUid
6410 + " does not have permission to uri " + uri);
6411 //}
6412 }
6413
6414 // Go through all of the permissions and remove any that match.
6415 final List<String> SEGMENTS = uri.getPathSegments();
6416 if (SEGMENTS != null) {
6417 final int NS = SEGMENTS.size();
6418 int N = mGrantedUriPermissions.size();
6419 for (int i=0; i<N; i++) {
6420 HashMap<Uri, UriPermission> perms
6421 = mGrantedUriPermissions.valueAt(i);
6422 Iterator<UriPermission> it = perms.values().iterator();
6423 toploop:
6424 while (it.hasNext()) {
6425 UriPermission perm = it.next();
6426 Uri targetUri = perm.uri;
6427 if (!authority.equals(targetUri.getAuthority())) {
6428 continue;
6429 }
6430 List<String> targetSegments = targetUri.getPathSegments();
6431 if (targetSegments == null) {
6432 continue;
6433 }
6434 if (targetSegments.size() < NS) {
6435 continue;
6436 }
6437 for (int j=0; j<NS; j++) {
6438 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6439 continue toploop;
6440 }
6441 }
6442 perm.clearModes(modeFlags);
6443 if (perm.modeFlags == 0) {
6444 it.remove();
6445 }
6446 }
6447 if (perms.size() == 0) {
6448 mGrantedUriPermissions.remove(
6449 mGrantedUriPermissions.keyAt(i));
6450 N--;
6451 i--;
6452 }
6453 }
6454 }
6455 }
6456
6457 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6458 int modeFlags) {
6459 synchronized(this) {
6460 final ProcessRecord r = getRecordForAppLocked(caller);
6461 if (r == null) {
6462 throw new SecurityException("Unable to find app for caller "
6463 + caller
6464 + " when revoking permission to uri " + uri);
6465 }
6466 if (uri == null) {
6467 Log.w(TAG, "revokeUriPermission: null uri");
6468 return;
6469 }
6470
6471 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6472 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6473 if (modeFlags == 0) {
6474 return;
6475 }
6476
6477 final IPackageManager pm = ActivityThread.getPackageManager();
6478
6479 final String authority = uri.getAuthority();
6480 ProviderInfo pi = null;
6481 ContentProviderRecord cpr
6482 = (ContentProviderRecord)mProvidersByName.get(authority);
6483 if (cpr != null) {
6484 pi = cpr.info;
6485 } else {
6486 try {
6487 pi = pm.resolveContentProvider(authority,
6488 PackageManager.GET_URI_PERMISSION_PATTERNS);
6489 } catch (RemoteException ex) {
6490 }
6491 }
6492 if (pi == null) {
6493 Log.w(TAG, "No content provider found for: " + authority);
6494 return;
6495 }
6496
6497 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6498 }
6499 }
6500
6501 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6502 synchronized (this) {
6503 ProcessRecord app =
6504 who != null ? getRecordForAppLocked(who) : null;
6505 if (app == null) return;
6506
6507 Message msg = Message.obtain();
6508 msg.what = WAIT_FOR_DEBUGGER_MSG;
6509 msg.obj = app;
6510 msg.arg1 = waiting ? 1 : 0;
6511 mHandler.sendMessage(msg);
6512 }
6513 }
6514
6515 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6516 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006517 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006518 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006519 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006520 }
6521
6522 // =========================================================
6523 // TASK MANAGEMENT
6524 // =========================================================
6525
6526 public List getTasks(int maxNum, int flags,
6527 IThumbnailReceiver receiver) {
6528 ArrayList list = new ArrayList();
6529
6530 PendingThumbnailsRecord pending = null;
6531 IApplicationThread topThumbnail = null;
6532 HistoryRecord topRecord = null;
6533
6534 synchronized(this) {
6535 if (localLOGV) Log.v(
6536 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6537 + ", receiver=" + receiver);
6538
6539 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6540 != PackageManager.PERMISSION_GRANTED) {
6541 if (receiver != null) {
6542 // If the caller wants to wait for pending thumbnails,
6543 // it ain't gonna get them.
6544 try {
6545 receiver.finished();
6546 } catch (RemoteException ex) {
6547 }
6548 }
6549 String msg = "Permission Denial: getTasks() from pid="
6550 + Binder.getCallingPid()
6551 + ", uid=" + Binder.getCallingUid()
6552 + " requires " + android.Manifest.permission.GET_TASKS;
6553 Log.w(TAG, msg);
6554 throw new SecurityException(msg);
6555 }
6556
6557 int pos = mHistory.size()-1;
6558 HistoryRecord next =
6559 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6560 HistoryRecord top = null;
6561 CharSequence topDescription = null;
6562 TaskRecord curTask = null;
6563 int numActivities = 0;
6564 int numRunning = 0;
6565 while (pos >= 0 && maxNum > 0) {
6566 final HistoryRecord r = next;
6567 pos--;
6568 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6569
6570 // Initialize state for next task if needed.
6571 if (top == null ||
6572 (top.state == ActivityState.INITIALIZING
6573 && top.task == r.task)) {
6574 top = r;
6575 topDescription = r.description;
6576 curTask = r.task;
6577 numActivities = numRunning = 0;
6578 }
6579
6580 // Add 'r' into the current task.
6581 numActivities++;
6582 if (r.app != null && r.app.thread != null) {
6583 numRunning++;
6584 }
6585 if (topDescription == null) {
6586 topDescription = r.description;
6587 }
6588
6589 if (localLOGV) Log.v(
6590 TAG, r.intent.getComponent().flattenToShortString()
6591 + ": task=" + r.task);
6592
6593 // If the next one is a different task, generate a new
6594 // TaskInfo entry for what we have.
6595 if (next == null || next.task != curTask) {
6596 ActivityManager.RunningTaskInfo ci
6597 = new ActivityManager.RunningTaskInfo();
6598 ci.id = curTask.taskId;
6599 ci.baseActivity = r.intent.getComponent();
6600 ci.topActivity = top.intent.getComponent();
6601 ci.thumbnail = top.thumbnail;
6602 ci.description = topDescription;
6603 ci.numActivities = numActivities;
6604 ci.numRunning = numRunning;
6605 //System.out.println(
6606 // "#" + maxNum + ": " + " descr=" + ci.description);
6607 if (ci.thumbnail == null && receiver != null) {
6608 if (localLOGV) Log.v(
6609 TAG, "State=" + top.state + "Idle=" + top.idle
6610 + " app=" + top.app
6611 + " thr=" + (top.app != null ? top.app.thread : null));
6612 if (top.state == ActivityState.RESUMED
6613 || top.state == ActivityState.PAUSING) {
6614 if (top.idle && top.app != null
6615 && top.app.thread != null) {
6616 topRecord = top;
6617 topThumbnail = top.app.thread;
6618 } else {
6619 top.thumbnailNeeded = true;
6620 }
6621 }
6622 if (pending == null) {
6623 pending = new PendingThumbnailsRecord(receiver);
6624 }
6625 pending.pendingRecords.add(top);
6626 }
6627 list.add(ci);
6628 maxNum--;
6629 top = null;
6630 }
6631 }
6632
6633 if (pending != null) {
6634 mPendingThumbnails.add(pending);
6635 }
6636 }
6637
6638 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6639
6640 if (topThumbnail != null) {
6641 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6642 try {
6643 topThumbnail.requestThumbnail(topRecord);
6644 } catch (Exception e) {
6645 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6646 sendPendingThumbnail(null, topRecord, null, null, true);
6647 }
6648 }
6649
6650 if (pending == null && receiver != null) {
6651 // In this case all thumbnails were available and the client
6652 // is being asked to be told when the remaining ones come in...
6653 // which is unusually, since the top-most currently running
6654 // activity should never have a canned thumbnail! Oh well.
6655 try {
6656 receiver.finished();
6657 } catch (RemoteException ex) {
6658 }
6659 }
6660
6661 return list;
6662 }
6663
6664 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6665 int flags) {
6666 synchronized (this) {
6667 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6668 "getRecentTasks()");
6669
6670 final int N = mRecentTasks.size();
6671 ArrayList<ActivityManager.RecentTaskInfo> res
6672 = new ArrayList<ActivityManager.RecentTaskInfo>(
6673 maxNum < N ? maxNum : N);
6674 for (int i=0; i<N && maxNum > 0; i++) {
6675 TaskRecord tr = mRecentTasks.get(i);
6676 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6677 || (tr.intent == null)
6678 || ((tr.intent.getFlags()
6679 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6680 ActivityManager.RecentTaskInfo rti
6681 = new ActivityManager.RecentTaskInfo();
6682 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6683 rti.baseIntent = new Intent(
6684 tr.intent != null ? tr.intent : tr.affinityIntent);
6685 rti.origActivity = tr.origActivity;
6686 res.add(rti);
6687 maxNum--;
6688 }
6689 }
6690 return res;
6691 }
6692 }
6693
6694 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6695 int j;
6696 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6697 TaskRecord jt = startTask;
6698
6699 // First look backwards
6700 for (j=startIndex-1; j>=0; j--) {
6701 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6702 if (r.task != jt) {
6703 jt = r.task;
6704 if (affinity.equals(jt.affinity)) {
6705 return j;
6706 }
6707 }
6708 }
6709
6710 // Now look forwards
6711 final int N = mHistory.size();
6712 jt = startTask;
6713 for (j=startIndex+1; j<N; j++) {
6714 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6715 if (r.task != jt) {
6716 if (affinity.equals(jt.affinity)) {
6717 return j;
6718 }
6719 jt = r.task;
6720 }
6721 }
6722
6723 // Might it be at the top?
6724 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6725 return N-1;
6726 }
6727
6728 return -1;
6729 }
6730
6731 /**
6732 * Perform a reset of the given task, if needed as part of launching it.
6733 * Returns the new HistoryRecord at the top of the task.
6734 */
6735 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6736 HistoryRecord newActivity) {
6737 boolean forceReset = (newActivity.info.flags
6738 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6739 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6740 if ((newActivity.info.flags
6741 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6742 forceReset = true;
6743 }
6744 }
6745
6746 final TaskRecord task = taskTop.task;
6747
6748 // We are going to move through the history list so that we can look
6749 // at each activity 'target' with 'below' either the interesting
6750 // activity immediately below it in the stack or null.
6751 HistoryRecord target = null;
6752 int targetI = 0;
6753 int taskTopI = -1;
6754 int replyChainEnd = -1;
6755 int lastReparentPos = -1;
6756 for (int i=mHistory.size()-1; i>=-1; i--) {
6757 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6758
6759 if (below != null && below.finishing) {
6760 continue;
6761 }
6762 if (target == null) {
6763 target = below;
6764 targetI = i;
6765 // If we were in the middle of a reply chain before this
6766 // task, it doesn't appear like the root of the chain wants
6767 // anything interesting, so drop it.
6768 replyChainEnd = -1;
6769 continue;
6770 }
6771
6772 final int flags = target.info.flags;
6773
6774 final boolean finishOnTaskLaunch =
6775 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6776 final boolean allowTaskReparenting =
6777 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6778
6779 if (target.task == task) {
6780 // We are inside of the task being reset... we'll either
6781 // finish this activity, push it out for another task,
6782 // or leave it as-is. We only do this
6783 // for activities that are not the root of the task (since
6784 // if we finish the root, we may no longer have the task!).
6785 if (taskTopI < 0) {
6786 taskTopI = targetI;
6787 }
6788 if (below != null && below.task == task) {
6789 final boolean clearWhenTaskReset =
6790 (target.intent.getFlags()
6791 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006792 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006793 // If this activity is sending a reply to a previous
6794 // activity, we can't do anything with it now until
6795 // we reach the start of the reply chain.
6796 // XXX note that we are assuming the result is always
6797 // to the previous activity, which is almost always
6798 // the case but we really shouldn't count on.
6799 if (replyChainEnd < 0) {
6800 replyChainEnd = targetI;
6801 }
Ed Heyl73798232009-03-24 21:32:21 -07006802 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006803 && target.taskAffinity != null
6804 && !target.taskAffinity.equals(task.affinity)) {
6805 // If this activity has an affinity for another
6806 // task, then we need to move it out of here. We will
6807 // move it as far out of the way as possible, to the
6808 // bottom of the activity stack. This also keeps it
6809 // correctly ordered with any activities we previously
6810 // moved.
6811 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6812 if (target.taskAffinity != null
6813 && target.taskAffinity.equals(p.task.affinity)) {
6814 // If the activity currently at the bottom has the
6815 // same task affinity as the one we are moving,
6816 // then merge it into the same task.
6817 target.task = p.task;
6818 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6819 + " out to bottom task " + p.task);
6820 } else {
6821 mCurTask++;
6822 if (mCurTask <= 0) {
6823 mCurTask = 1;
6824 }
6825 target.task = new TaskRecord(mCurTask, target.info, null,
6826 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6827 target.task.affinityIntent = target.intent;
6828 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6829 + " out to new task " + target.task);
6830 }
6831 mWindowManager.setAppGroupId(target, task.taskId);
6832 if (replyChainEnd < 0) {
6833 replyChainEnd = targetI;
6834 }
6835 int dstPos = 0;
6836 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6837 p = (HistoryRecord)mHistory.get(srcPos);
6838 if (p.finishing) {
6839 continue;
6840 }
6841 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6842 + " out to target's task " + target.task);
6843 task.numActivities--;
6844 p.task = target.task;
6845 target.task.numActivities++;
6846 mHistory.remove(srcPos);
6847 mHistory.add(dstPos, p);
6848 mWindowManager.moveAppToken(dstPos, p);
6849 mWindowManager.setAppGroupId(p, p.task.taskId);
6850 dstPos++;
6851 if (VALIDATE_TOKENS) {
6852 mWindowManager.validateAppTokens(mHistory);
6853 }
6854 i++;
6855 }
6856 if (taskTop == p) {
6857 taskTop = below;
6858 }
6859 if (taskTopI == replyChainEnd) {
6860 taskTopI = -1;
6861 }
6862 replyChainEnd = -1;
6863 addRecentTask(target.task);
6864 } else if (forceReset || finishOnTaskLaunch
6865 || clearWhenTaskReset) {
6866 // If the activity should just be removed -- either
6867 // because it asks for it, or the task should be
6868 // cleared -- then finish it and anything that is
6869 // part of its reply chain.
6870 if (clearWhenTaskReset) {
6871 // In this case, we want to finish this activity
6872 // and everything above it, so be sneaky and pretend
6873 // like these are all in the reply chain.
6874 replyChainEnd = targetI+1;
6875 while (replyChainEnd < mHistory.size() &&
6876 ((HistoryRecord)mHistory.get(
6877 replyChainEnd)).task == task) {
6878 replyChainEnd++;
6879 }
6880 replyChainEnd--;
6881 } else if (replyChainEnd < 0) {
6882 replyChainEnd = targetI;
6883 }
6884 HistoryRecord p = null;
6885 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6886 p = (HistoryRecord)mHistory.get(srcPos);
6887 if (p.finishing) {
6888 continue;
6889 }
6890 if (finishActivityLocked(p, srcPos,
6891 Activity.RESULT_CANCELED, null, "reset")) {
6892 replyChainEnd--;
6893 srcPos--;
6894 }
6895 }
6896 if (taskTop == p) {
6897 taskTop = below;
6898 }
6899 if (taskTopI == replyChainEnd) {
6900 taskTopI = -1;
6901 }
6902 replyChainEnd = -1;
6903 } else {
6904 // If we were in the middle of a chain, well the
6905 // activity that started it all doesn't want anything
6906 // special, so leave it all as-is.
6907 replyChainEnd = -1;
6908 }
6909 } else {
6910 // Reached the bottom of the task -- any reply chain
6911 // should be left as-is.
6912 replyChainEnd = -1;
6913 }
6914
6915 } else if (target.resultTo != null) {
6916 // If this activity is sending a reply to a previous
6917 // activity, we can't do anything with it now until
6918 // we reach the start of the reply chain.
6919 // XXX note that we are assuming the result is always
6920 // to the previous activity, which is almost always
6921 // the case but we really shouldn't count on.
6922 if (replyChainEnd < 0) {
6923 replyChainEnd = targetI;
6924 }
6925
6926 } else if (taskTopI >= 0 && allowTaskReparenting
6927 && task.affinity != null
6928 && task.affinity.equals(target.taskAffinity)) {
6929 // We are inside of another task... if this activity has
6930 // an affinity for our task, then either remove it if we are
6931 // clearing or move it over to our task. Note that
6932 // we currently punt on the case where we are resetting a
6933 // task that is not at the top but who has activities above
6934 // with an affinity to it... this is really not a normal
6935 // case, and we will need to later pull that task to the front
6936 // and usually at that point we will do the reset and pick
6937 // up those remaining activities. (This only happens if
6938 // someone starts an activity in a new task from an activity
6939 // in a task that is not currently on top.)
6940 if (forceReset || finishOnTaskLaunch) {
6941 if (replyChainEnd < 0) {
6942 replyChainEnd = targetI;
6943 }
6944 HistoryRecord p = null;
6945 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6946 p = (HistoryRecord)mHistory.get(srcPos);
6947 if (p.finishing) {
6948 continue;
6949 }
6950 if (finishActivityLocked(p, srcPos,
6951 Activity.RESULT_CANCELED, null, "reset")) {
6952 taskTopI--;
6953 lastReparentPos--;
6954 replyChainEnd--;
6955 srcPos--;
6956 }
6957 }
6958 replyChainEnd = -1;
6959 } else {
6960 if (replyChainEnd < 0) {
6961 replyChainEnd = targetI;
6962 }
6963 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6964 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6965 if (p.finishing) {
6966 continue;
6967 }
6968 if (lastReparentPos < 0) {
6969 lastReparentPos = taskTopI;
6970 taskTop = p;
6971 } else {
6972 lastReparentPos--;
6973 }
6974 mHistory.remove(srcPos);
6975 p.task.numActivities--;
6976 p.task = task;
6977 mHistory.add(lastReparentPos, p);
6978 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6979 + " in to resetting task " + task);
6980 task.numActivities++;
6981 mWindowManager.moveAppToken(lastReparentPos, p);
6982 mWindowManager.setAppGroupId(p, p.task.taskId);
6983 if (VALIDATE_TOKENS) {
6984 mWindowManager.validateAppTokens(mHistory);
6985 }
6986 }
6987 replyChainEnd = -1;
6988
6989 // Now we've moved it in to place... but what if this is
6990 // a singleTop activity and we have put it on top of another
6991 // instance of the same activity? Then we drop the instance
6992 // below so it remains singleTop.
6993 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6994 for (int j=lastReparentPos-1; j>=0; j--) {
6995 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6996 if (p.finishing) {
6997 continue;
6998 }
6999 if (p.intent.getComponent().equals(target.intent.getComponent())) {
7000 if (finishActivityLocked(p, j,
7001 Activity.RESULT_CANCELED, null, "replace")) {
7002 taskTopI--;
7003 lastReparentPos--;
7004 }
7005 }
7006 }
7007 }
7008 }
7009 }
7010
7011 target = below;
7012 targetI = i;
7013 }
7014
7015 return taskTop;
7016 }
7017
7018 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007019 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007020 */
7021 public void moveTaskToFront(int task) {
7022 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7023 "moveTaskToFront()");
7024
7025 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007026 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7027 Binder.getCallingUid(), "Task to front")) {
7028 return;
7029 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007030 final long origId = Binder.clearCallingIdentity();
7031 try {
7032 int N = mRecentTasks.size();
7033 for (int i=0; i<N; i++) {
7034 TaskRecord tr = mRecentTasks.get(i);
7035 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007036 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007037 return;
7038 }
7039 }
7040 for (int i=mHistory.size()-1; i>=0; i--) {
7041 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7042 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007043 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007044 return;
7045 }
7046 }
7047 } finally {
7048 Binder.restoreCallingIdentity(origId);
7049 }
7050 }
7051 }
7052
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007053 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007054 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7055
7056 final int task = tr.taskId;
7057 int top = mHistory.size()-1;
7058
7059 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7060 // nothing to do!
7061 return;
7062 }
7063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007064 ArrayList moved = new ArrayList();
7065
7066 // Applying the affinities may have removed entries from the history,
7067 // so get the size again.
7068 top = mHistory.size()-1;
7069 int pos = top;
7070
7071 // Shift all activities with this task up to the top
7072 // of the stack, keeping them in the same internal order.
7073 while (pos >= 0) {
7074 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7075 if (localLOGV) Log.v(
7076 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7077 boolean first = true;
7078 if (r.task.taskId == task) {
7079 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7080 mHistory.remove(pos);
7081 mHistory.add(top, r);
7082 moved.add(0, r);
7083 top--;
7084 if (first) {
7085 addRecentTask(r.task);
7086 first = false;
7087 }
7088 }
7089 pos--;
7090 }
7091
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007092 if (DEBUG_TRANSITION) Log.v(TAG,
7093 "Prepare to front transition: task=" + tr);
7094 if (reason != null &&
7095 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7096 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7097 HistoryRecord r = topRunningActivityLocked(null);
7098 if (r != null) {
7099 mNoAnimActivities.add(r);
7100 }
7101 } else {
7102 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7103 }
7104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007105 mWindowManager.moveAppTokensToTop(moved);
7106 if (VALIDATE_TOKENS) {
7107 mWindowManager.validateAppTokens(mHistory);
7108 }
7109
7110 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007111 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007112 }
7113
7114 private final void finishTaskMove(int task) {
7115 resumeTopActivityLocked(null);
7116 }
7117
7118 public void moveTaskToBack(int task) {
7119 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7120 "moveTaskToBack()");
7121
7122 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007123 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7124 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7125 Binder.getCallingUid(), "Task to back")) {
7126 return;
7127 }
7128 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007129 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007130 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007131 Binder.restoreCallingIdentity(origId);
7132 }
7133 }
7134
7135 /**
7136 * Moves an activity, and all of the other activities within the same task, to the bottom
7137 * of the history stack. The activity's order within the task is unchanged.
7138 *
7139 * @param token A reference to the activity we wish to move
7140 * @param nonRoot If false then this only works if the activity is the root
7141 * of a task; if true it will work for any activity in a task.
7142 * @return Returns true if the move completed, false if not.
7143 */
7144 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7145 synchronized(this) {
7146 final long origId = Binder.clearCallingIdentity();
7147 int taskId = getTaskForActivityLocked(token, !nonRoot);
7148 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007149 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007150 }
7151 Binder.restoreCallingIdentity(origId);
7152 }
7153 return false;
7154 }
7155
7156 /**
7157 * Worker method for rearranging history stack. Implements the function of moving all
7158 * activities for a specific task (gathering them if disjoint) into a single group at the
7159 * bottom of the stack.
7160 *
7161 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7162 * to premeptively cancel the move.
7163 *
7164 * @param task The taskId to collect and move to the bottom.
7165 * @return Returns true if the move completed, false if not.
7166 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007167 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007168 Log.i(TAG, "moveTaskToBack: " + task);
7169
7170 // If we have a watcher, preflight the move before committing to it. First check
7171 // for *other* available tasks, but if none are available, then try again allowing the
7172 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007173 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007174 HistoryRecord next = topRunningActivityLocked(null, task);
7175 if (next == null) {
7176 next = topRunningActivityLocked(null, 0);
7177 }
7178 if (next != null) {
7179 // ask watcher if this is allowed
7180 boolean moveOK = true;
7181 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007182 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007183 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007184 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007185 }
7186 if (!moveOK) {
7187 return false;
7188 }
7189 }
7190 }
7191
7192 ArrayList moved = new ArrayList();
7193
7194 if (DEBUG_TRANSITION) Log.v(TAG,
7195 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007196
7197 final int N = mHistory.size();
7198 int bottom = 0;
7199 int pos = 0;
7200
7201 // Shift all activities with this task down to the bottom
7202 // of the stack, keeping them in the same internal order.
7203 while (pos < N) {
7204 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7205 if (localLOGV) Log.v(
7206 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7207 if (r.task.taskId == task) {
7208 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7209 mHistory.remove(pos);
7210 mHistory.add(bottom, r);
7211 moved.add(r);
7212 bottom++;
7213 }
7214 pos++;
7215 }
7216
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007217 if (reason != null &&
7218 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7219 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7220 HistoryRecord r = topRunningActivityLocked(null);
7221 if (r != null) {
7222 mNoAnimActivities.add(r);
7223 }
7224 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007225 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007226 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007227 mWindowManager.moveAppTokensToBottom(moved);
7228 if (VALIDATE_TOKENS) {
7229 mWindowManager.validateAppTokens(mHistory);
7230 }
7231
7232 finishTaskMove(task);
7233 return true;
7234 }
7235
7236 public void moveTaskBackwards(int task) {
7237 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7238 "moveTaskBackwards()");
7239
7240 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007241 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7242 Binder.getCallingUid(), "Task backwards")) {
7243 return;
7244 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007245 final long origId = Binder.clearCallingIdentity();
7246 moveTaskBackwardsLocked(task);
7247 Binder.restoreCallingIdentity(origId);
7248 }
7249 }
7250
7251 private final void moveTaskBackwardsLocked(int task) {
7252 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7253 }
7254
7255 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7256 synchronized(this) {
7257 return getTaskForActivityLocked(token, onlyRoot);
7258 }
7259 }
7260
7261 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7262 final int N = mHistory.size();
7263 TaskRecord lastTask = null;
7264 for (int i=0; i<N; i++) {
7265 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7266 if (r == token) {
7267 if (!onlyRoot || lastTask != r.task) {
7268 return r.task.taskId;
7269 }
7270 return -1;
7271 }
7272 lastTask = r.task;
7273 }
7274
7275 return -1;
7276 }
7277
7278 /**
7279 * Returns the top activity in any existing task matching the given
7280 * Intent. Returns null if no such task is found.
7281 */
7282 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7283 ComponentName cls = intent.getComponent();
7284 if (info.targetActivity != null) {
7285 cls = new ComponentName(info.packageName, info.targetActivity);
7286 }
7287
7288 TaskRecord cp = null;
7289
7290 final int N = mHistory.size();
7291 for (int i=(N-1); i>=0; i--) {
7292 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7293 if (!r.finishing && r.task != cp
7294 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7295 cp = r.task;
7296 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7297 // + "/aff=" + r.task.affinity + " to new cls="
7298 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7299 if (r.task.affinity != null) {
7300 if (r.task.affinity.equals(info.taskAffinity)) {
7301 //Log.i(TAG, "Found matching affinity!");
7302 return r;
7303 }
7304 } else if (r.task.intent != null
7305 && r.task.intent.getComponent().equals(cls)) {
7306 //Log.i(TAG, "Found matching class!");
7307 //dump();
7308 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7309 return r;
7310 } else if (r.task.affinityIntent != null
7311 && r.task.affinityIntent.getComponent().equals(cls)) {
7312 //Log.i(TAG, "Found matching class!");
7313 //dump();
7314 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7315 return r;
7316 }
7317 }
7318 }
7319
7320 return null;
7321 }
7322
7323 /**
7324 * Returns the first activity (starting from the top of the stack) that
7325 * is the same as the given activity. Returns null if no such activity
7326 * is found.
7327 */
7328 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7329 ComponentName cls = intent.getComponent();
7330 if (info.targetActivity != null) {
7331 cls = new ComponentName(info.packageName, info.targetActivity);
7332 }
7333
7334 final int N = mHistory.size();
7335 for (int i=(N-1); i>=0; i--) {
7336 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7337 if (!r.finishing) {
7338 if (r.intent.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 public void finishOtherInstances(IBinder token, ComponentName className) {
7351 synchronized(this) {
7352 final long origId = Binder.clearCallingIdentity();
7353
7354 int N = mHistory.size();
7355 TaskRecord lastTask = null;
7356 for (int i=0; i<N; i++) {
7357 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7358 if (r.realActivity.equals(className)
7359 && r != token && lastTask != r.task) {
7360 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7361 null, "others")) {
7362 i--;
7363 N--;
7364 }
7365 }
7366 lastTask = r.task;
7367 }
7368
7369 Binder.restoreCallingIdentity(origId);
7370 }
7371 }
7372
7373 // =========================================================
7374 // THUMBNAILS
7375 // =========================================================
7376
7377 public void reportThumbnail(IBinder token,
7378 Bitmap thumbnail, CharSequence description) {
7379 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7380 final long origId = Binder.clearCallingIdentity();
7381 sendPendingThumbnail(null, token, thumbnail, description, true);
7382 Binder.restoreCallingIdentity(origId);
7383 }
7384
7385 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7386 Bitmap thumbnail, CharSequence description, boolean always) {
7387 TaskRecord task = null;
7388 ArrayList receivers = null;
7389
7390 //System.out.println("Send pending thumbnail: " + r);
7391
7392 synchronized(this) {
7393 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007394 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007395 if (index < 0) {
7396 return;
7397 }
7398 r = (HistoryRecord)mHistory.get(index);
7399 }
7400 if (thumbnail == null) {
7401 thumbnail = r.thumbnail;
7402 description = r.description;
7403 }
7404 if (thumbnail == null && !always) {
7405 // If there is no thumbnail, and this entry is not actually
7406 // going away, then abort for now and pick up the next
7407 // thumbnail we get.
7408 return;
7409 }
7410 task = r.task;
7411
7412 int N = mPendingThumbnails.size();
7413 int i=0;
7414 while (i<N) {
7415 PendingThumbnailsRecord pr =
7416 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7417 //System.out.println("Looking in " + pr.pendingRecords);
7418 if (pr.pendingRecords.remove(r)) {
7419 if (receivers == null) {
7420 receivers = new ArrayList();
7421 }
7422 receivers.add(pr);
7423 if (pr.pendingRecords.size() == 0) {
7424 pr.finished = true;
7425 mPendingThumbnails.remove(i);
7426 N--;
7427 continue;
7428 }
7429 }
7430 i++;
7431 }
7432 }
7433
7434 if (receivers != null) {
7435 final int N = receivers.size();
7436 for (int i=0; i<N; i++) {
7437 try {
7438 PendingThumbnailsRecord pr =
7439 (PendingThumbnailsRecord)receivers.get(i);
7440 pr.receiver.newThumbnail(
7441 task != null ? task.taskId : -1, thumbnail, description);
7442 if (pr.finished) {
7443 pr.receiver.finished();
7444 }
7445 } catch (Exception e) {
7446 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7447 }
7448 }
7449 }
7450 }
7451
7452 // =========================================================
7453 // CONTENT PROVIDERS
7454 // =========================================================
7455
7456 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7457 List providers = null;
7458 try {
7459 providers = ActivityThread.getPackageManager().
7460 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007461 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007462 } catch (RemoteException ex) {
7463 }
7464 if (providers != null) {
7465 final int N = providers.size();
7466 for (int i=0; i<N; i++) {
7467 ProviderInfo cpi =
7468 (ProviderInfo)providers.get(i);
7469 ContentProviderRecord cpr =
7470 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7471 if (cpr == null) {
7472 cpr = new ContentProviderRecord(cpi, app.info);
7473 mProvidersByClass.put(cpi.name, cpr);
7474 }
7475 app.pubProviders.put(cpi.name, cpr);
7476 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007477 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007478 }
7479 }
7480 return providers;
7481 }
7482
7483 private final String checkContentProviderPermissionLocked(
7484 ProviderInfo cpi, ProcessRecord r, int mode) {
7485 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7486 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7487 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7488 cpi.exported ? -1 : cpi.applicationInfo.uid)
7489 == PackageManager.PERMISSION_GRANTED
7490 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7491 return null;
7492 }
7493 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7494 cpi.exported ? -1 : cpi.applicationInfo.uid)
7495 == PackageManager.PERMISSION_GRANTED) {
7496 return null;
7497 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007498
7499 PathPermission[] pps = cpi.pathPermissions;
7500 if (pps != null) {
7501 int i = pps.length;
7502 while (i > 0) {
7503 i--;
7504 PathPermission pp = pps[i];
7505 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7506 cpi.exported ? -1 : cpi.applicationInfo.uid)
7507 == PackageManager.PERMISSION_GRANTED
7508 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7509 return null;
7510 }
7511 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7512 cpi.exported ? -1 : cpi.applicationInfo.uid)
7513 == PackageManager.PERMISSION_GRANTED) {
7514 return null;
7515 }
7516 }
7517 }
7518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007519 String msg = "Permission Denial: opening provider " + cpi.name
7520 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7521 + ", uid=" + callingUid + ") requires "
7522 + cpi.readPermission + " or " + cpi.writePermission;
7523 Log.w(TAG, msg);
7524 return msg;
7525 }
7526
7527 private final ContentProviderHolder getContentProviderImpl(
7528 IApplicationThread caller, String name) {
7529 ContentProviderRecord cpr;
7530 ProviderInfo cpi = null;
7531
7532 synchronized(this) {
7533 ProcessRecord r = null;
7534 if (caller != null) {
7535 r = getRecordForAppLocked(caller);
7536 if (r == null) {
7537 throw new SecurityException(
7538 "Unable to find app for caller " + caller
7539 + " (pid=" + Binder.getCallingPid()
7540 + ") when getting content provider " + name);
7541 }
7542 }
7543
7544 // First check if this content provider has been published...
7545 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7546 if (cpr != null) {
7547 cpi = cpr.info;
7548 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7549 return new ContentProviderHolder(cpi,
7550 cpi.readPermission != null
7551 ? cpi.readPermission : cpi.writePermission);
7552 }
7553
7554 if (r != null && cpr.canRunHere(r)) {
7555 // This provider has been published or is in the process
7556 // of being published... but it is also allowed to run
7557 // in the caller's process, so don't make a connection
7558 // and just let the caller instantiate its own instance.
7559 if (cpr.provider != null) {
7560 // don't give caller the provider object, it needs
7561 // to make its own.
7562 cpr = new ContentProviderRecord(cpr);
7563 }
7564 return cpr;
7565 }
7566
7567 final long origId = Binder.clearCallingIdentity();
7568
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007569 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007570 // return it right away.
7571 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007572 if (DEBUG_PROVIDER) Log.v(TAG,
7573 "Adding provider requested by "
7574 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007575 + cpr.info.processName);
7576 Integer cnt = r.conProviders.get(cpr);
7577 if (cnt == null) {
7578 r.conProviders.put(cpr, new Integer(1));
7579 } else {
7580 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007582 cpr.clients.add(r);
7583 } else {
7584 cpr.externals++;
7585 }
7586
7587 if (cpr.app != null) {
7588 updateOomAdjLocked(cpr.app);
7589 }
7590
7591 Binder.restoreCallingIdentity(origId);
7592
7593 } else {
7594 try {
7595 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007596 resolveContentProvider(name,
7597 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007598 } catch (RemoteException ex) {
7599 }
7600 if (cpi == null) {
7601 return null;
7602 }
7603
7604 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7605 return new ContentProviderHolder(cpi,
7606 cpi.readPermission != null
7607 ? cpi.readPermission : cpi.writePermission);
7608 }
7609
7610 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7611 final boolean firstClass = cpr == null;
7612 if (firstClass) {
7613 try {
7614 ApplicationInfo ai =
7615 ActivityThread.getPackageManager().
7616 getApplicationInfo(
7617 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007618 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007619 if (ai == null) {
7620 Log.w(TAG, "No package info for content provider "
7621 + cpi.name);
7622 return null;
7623 }
7624 cpr = new ContentProviderRecord(cpi, ai);
7625 } catch (RemoteException ex) {
7626 // pm is in same process, this will never happen.
7627 }
7628 }
7629
7630 if (r != null && cpr.canRunHere(r)) {
7631 // If this is a multiprocess provider, then just return its
7632 // info and allow the caller to instantiate it. Only do
7633 // this if the provider is the same user as the caller's
7634 // process, or can run as root (so can be in any process).
7635 return cpr;
7636 }
7637
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007638 if (DEBUG_PROVIDER) {
7639 RuntimeException e = new RuntimeException("here");
7640 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7641 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007642 }
7643
7644 // This is single process, and our app is now connecting to it.
7645 // See if we are already in the process of launching this
7646 // provider.
7647 final int N = mLaunchingProviders.size();
7648 int i;
7649 for (i=0; i<N; i++) {
7650 if (mLaunchingProviders.get(i) == cpr) {
7651 break;
7652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007653 }
7654
7655 // If the provider is not already being launched, then get it
7656 // started.
7657 if (i >= N) {
7658 final long origId = Binder.clearCallingIdentity();
7659 ProcessRecord proc = startProcessLocked(cpi.processName,
7660 cpr.appInfo, false, 0, "content provider",
7661 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007662 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007663 if (proc == null) {
7664 Log.w(TAG, "Unable to launch app "
7665 + cpi.applicationInfo.packageName + "/"
7666 + cpi.applicationInfo.uid + " for provider "
7667 + name + ": process is bad");
7668 return null;
7669 }
7670 cpr.launchingApp = proc;
7671 mLaunchingProviders.add(cpr);
7672 Binder.restoreCallingIdentity(origId);
7673 }
7674
7675 // Make sure the provider is published (the same provider class
7676 // may be published under multiple names).
7677 if (firstClass) {
7678 mProvidersByClass.put(cpi.name, cpr);
7679 }
7680 mProvidersByName.put(name, cpr);
7681
7682 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007683 if (DEBUG_PROVIDER) Log.v(TAG,
7684 "Adding provider requested by "
7685 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007686 + cpr.info.processName);
7687 Integer cnt = r.conProviders.get(cpr);
7688 if (cnt == null) {
7689 r.conProviders.put(cpr, new Integer(1));
7690 } else {
7691 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7692 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007693 cpr.clients.add(r);
7694 } else {
7695 cpr.externals++;
7696 }
7697 }
7698 }
7699
7700 // Wait for the provider to be published...
7701 synchronized (cpr) {
7702 while (cpr.provider == null) {
7703 if (cpr.launchingApp == null) {
7704 Log.w(TAG, "Unable to launch app "
7705 + cpi.applicationInfo.packageName + "/"
7706 + cpi.applicationInfo.uid + " for provider "
7707 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007708 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007709 cpi.applicationInfo.packageName,
7710 cpi.applicationInfo.uid, name);
7711 return null;
7712 }
7713 try {
7714 cpr.wait();
7715 } catch (InterruptedException ex) {
7716 }
7717 }
7718 }
7719 return cpr;
7720 }
7721
7722 public final ContentProviderHolder getContentProvider(
7723 IApplicationThread caller, String name) {
7724 if (caller == null) {
7725 String msg = "null IApplicationThread when getting content provider "
7726 + name;
7727 Log.w(TAG, msg);
7728 throw new SecurityException(msg);
7729 }
7730
7731 return getContentProviderImpl(caller, name);
7732 }
7733
7734 private ContentProviderHolder getContentProviderExternal(String name) {
7735 return getContentProviderImpl(null, name);
7736 }
7737
7738 /**
7739 * Drop a content provider from a ProcessRecord's bookkeeping
7740 * @param cpr
7741 */
7742 public void removeContentProvider(IApplicationThread caller, String name) {
7743 synchronized (this) {
7744 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7745 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007746 // remove from mProvidersByClass
7747 if (DEBUG_PROVIDER) Log.v(TAG, name +
7748 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007749 return;
7750 }
7751 final ProcessRecord r = getRecordForAppLocked(caller);
7752 if (r == null) {
7753 throw new SecurityException(
7754 "Unable to find app for caller " + caller +
7755 " when removing content provider " + name);
7756 }
7757 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007758 ContentProviderRecord localCpr = (ContentProviderRecord)
7759 mProvidersByClass.get(cpr.info.name);
7760 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7761 + r.info.processName + " from process "
7762 + localCpr.appInfo.processName);
7763 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007764 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007765 Log.w(TAG, "removeContentProvider called on local provider: "
7766 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007767 return;
7768 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007769 Integer cnt = r.conProviders.get(localCpr);
7770 if (cnt == null || cnt.intValue() <= 1) {
7771 localCpr.clients.remove(r);
7772 r.conProviders.remove(localCpr);
7773 } else {
7774 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007776 }
7777 updateOomAdjLocked();
7778 }
7779 }
7780
7781 private void removeContentProviderExternal(String name) {
7782 synchronized (this) {
7783 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7784 if(cpr == null) {
7785 //remove from mProvidersByClass
7786 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7787 return;
7788 }
7789
7790 //update content provider record entry info
7791 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7792 localCpr.externals--;
7793 if (localCpr.externals < 0) {
7794 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7795 }
7796 updateOomAdjLocked();
7797 }
7798 }
7799
7800 public final void publishContentProviders(IApplicationThread caller,
7801 List<ContentProviderHolder> providers) {
7802 if (providers == null) {
7803 return;
7804 }
7805
7806 synchronized(this) {
7807 final ProcessRecord r = getRecordForAppLocked(caller);
7808 if (r == null) {
7809 throw new SecurityException(
7810 "Unable to find app for caller " + caller
7811 + " (pid=" + Binder.getCallingPid()
7812 + ") when publishing content providers");
7813 }
7814
7815 final long origId = Binder.clearCallingIdentity();
7816
7817 final int N = providers.size();
7818 for (int i=0; i<N; i++) {
7819 ContentProviderHolder src = providers.get(i);
7820 if (src == null || src.info == null || src.provider == null) {
7821 continue;
7822 }
7823 ContentProviderRecord dst =
7824 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7825 if (dst != null) {
7826 mProvidersByClass.put(dst.info.name, dst);
7827 String names[] = dst.info.authority.split(";");
7828 for (int j = 0; j < names.length; j++) {
7829 mProvidersByName.put(names[j], dst);
7830 }
7831
7832 int NL = mLaunchingProviders.size();
7833 int j;
7834 for (j=0; j<NL; j++) {
7835 if (mLaunchingProviders.get(j) == dst) {
7836 mLaunchingProviders.remove(j);
7837 j--;
7838 NL--;
7839 }
7840 }
7841 synchronized (dst) {
7842 dst.provider = src.provider;
7843 dst.app = r;
7844 dst.notifyAll();
7845 }
7846 updateOomAdjLocked(r);
7847 }
7848 }
7849
7850 Binder.restoreCallingIdentity(origId);
7851 }
7852 }
7853
7854 public static final void installSystemProviders() {
7855 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7856 List providers = mSelf.generateApplicationProvidersLocked(app);
7857 mSystemThread.installSystemProviders(providers);
7858 }
7859
7860 // =========================================================
7861 // GLOBAL MANAGEMENT
7862 // =========================================================
7863
7864 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7865 ApplicationInfo info, String customProcess) {
7866 String proc = customProcess != null ? customProcess : info.processName;
7867 BatteryStatsImpl.Uid.Proc ps = null;
7868 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7869 synchronized (stats) {
7870 ps = stats.getProcessStatsLocked(info.uid, proc);
7871 }
7872 return new ProcessRecord(ps, thread, info, proc);
7873 }
7874
7875 final ProcessRecord addAppLocked(ApplicationInfo info) {
7876 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7877
7878 if (app == null) {
7879 app = newProcessRecordLocked(null, info, null);
7880 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007881 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007882 }
7883
7884 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7885 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7886 app.persistent = true;
7887 app.maxAdj = CORE_SERVER_ADJ;
7888 }
7889 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7890 mPersistentStartingProcesses.add(app);
7891 startProcessLocked(app, "added application", app.processName);
7892 }
7893
7894 return app;
7895 }
7896
7897 public void unhandledBack() {
7898 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7899 "unhandledBack()");
7900
7901 synchronized(this) {
7902 int count = mHistory.size();
Dianne Hackborn03abb812010-01-04 18:43:19 -08007903 if (DEBUG_SWITCH) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007904 TAG, "Performing unhandledBack(): stack size = " + count);
7905 if (count > 1) {
7906 final long origId = Binder.clearCallingIdentity();
7907 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7908 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7909 Binder.restoreCallingIdentity(origId);
7910 }
7911 }
7912 }
7913
7914 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7915 String name = uri.getAuthority();
7916 ContentProviderHolder cph = getContentProviderExternal(name);
7917 ParcelFileDescriptor pfd = null;
7918 if (cph != null) {
7919 // We record the binder invoker's uid in thread-local storage before
7920 // going to the content provider to open the file. Later, in the code
7921 // that handles all permissions checks, we look for this uid and use
7922 // that rather than the Activity Manager's own uid. The effect is that
7923 // we do the check against the caller's permissions even though it looks
7924 // to the content provider like the Activity Manager itself is making
7925 // the request.
7926 sCallerIdentity.set(new Identity(
7927 Binder.getCallingPid(), Binder.getCallingUid()));
7928 try {
7929 pfd = cph.provider.openFile(uri, "r");
7930 } catch (FileNotFoundException e) {
7931 // do nothing; pfd will be returned null
7932 } finally {
7933 // Ensure that whatever happens, we clean up the identity state
7934 sCallerIdentity.remove();
7935 }
7936
7937 // We've got the fd now, so we're done with the provider.
7938 removeContentProviderExternal(name);
7939 } else {
7940 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7941 }
7942 return pfd;
7943 }
7944
7945 public void goingToSleep() {
7946 synchronized(this) {
7947 mSleeping = true;
7948 mWindowManager.setEventDispatching(false);
7949
7950 if (mResumedActivity != null) {
7951 pauseIfSleepingLocked();
7952 } else {
7953 Log.w(TAG, "goingToSleep with no resumed activity!");
7954 }
7955 }
7956 }
7957
Dianne Hackborn55280a92009-05-07 15:53:46 -07007958 public boolean shutdown(int timeout) {
7959 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7960 != PackageManager.PERMISSION_GRANTED) {
7961 throw new SecurityException("Requires permission "
7962 + android.Manifest.permission.SHUTDOWN);
7963 }
7964
7965 boolean timedout = false;
7966
7967 synchronized(this) {
7968 mShuttingDown = true;
7969 mWindowManager.setEventDispatching(false);
7970
7971 if (mResumedActivity != null) {
7972 pauseIfSleepingLocked();
7973 final long endTime = System.currentTimeMillis() + timeout;
7974 while (mResumedActivity != null || mPausingActivity != null) {
7975 long delay = endTime - System.currentTimeMillis();
7976 if (delay <= 0) {
7977 Log.w(TAG, "Activity manager shutdown timed out");
7978 timedout = true;
7979 break;
7980 }
7981 try {
7982 this.wait();
7983 } catch (InterruptedException e) {
7984 }
7985 }
7986 }
7987 }
7988
7989 mUsageStatsService.shutdown();
7990 mBatteryStatsService.shutdown();
7991
7992 return timedout;
7993 }
7994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007995 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007996 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007997 if (!mGoingToSleep.isHeld()) {
7998 mGoingToSleep.acquire();
7999 if (mLaunchingActivity.isHeld()) {
8000 mLaunchingActivity.release();
8001 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
8002 }
8003 }
8004
8005 // If we are not currently pausing an activity, get the current
8006 // one to pause. If we are pausing one, we will just let that stuff
8007 // run and release the wake lock when all done.
8008 if (mPausingActivity == null) {
8009 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8010 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8011 startPausingLocked(false, true);
8012 }
8013 }
8014 }
8015
8016 public void wakingUp() {
8017 synchronized(this) {
8018 if (mGoingToSleep.isHeld()) {
8019 mGoingToSleep.release();
8020 }
8021 mWindowManager.setEventDispatching(true);
8022 mSleeping = false;
8023 resumeTopActivityLocked(null);
8024 }
8025 }
8026
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008027 public void stopAppSwitches() {
8028 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8029 != PackageManager.PERMISSION_GRANTED) {
8030 throw new SecurityException("Requires permission "
8031 + android.Manifest.permission.STOP_APP_SWITCHES);
8032 }
8033
8034 synchronized(this) {
8035 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8036 + APP_SWITCH_DELAY_TIME;
8037 mDidAppSwitch = false;
8038 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8039 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8040 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8041 }
8042 }
8043
8044 public void resumeAppSwitches() {
8045 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8046 != PackageManager.PERMISSION_GRANTED) {
8047 throw new SecurityException("Requires permission "
8048 + android.Manifest.permission.STOP_APP_SWITCHES);
8049 }
8050
8051 synchronized(this) {
8052 // Note that we don't execute any pending app switches... we will
8053 // let those wait until either the timeout, or the next start
8054 // activity request.
8055 mAppSwitchesAllowedTime = 0;
8056 }
8057 }
8058
8059 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8060 String name) {
8061 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8062 return true;
8063 }
8064
8065 final int perm = checkComponentPermission(
8066 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8067 callingUid, -1);
8068 if (perm == PackageManager.PERMISSION_GRANTED) {
8069 return true;
8070 }
8071
8072 Log.w(TAG, name + " request from " + callingUid + " stopped");
8073 return false;
8074 }
8075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008076 public void setDebugApp(String packageName, boolean waitForDebugger,
8077 boolean persistent) {
8078 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8079 "setDebugApp()");
8080
8081 // Note that this is not really thread safe if there are multiple
8082 // callers into it at the same time, but that's not a situation we
8083 // care about.
8084 if (persistent) {
8085 final ContentResolver resolver = mContext.getContentResolver();
8086 Settings.System.putString(
8087 resolver, Settings.System.DEBUG_APP,
8088 packageName);
8089 Settings.System.putInt(
8090 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8091 waitForDebugger ? 1 : 0);
8092 }
8093
8094 synchronized (this) {
8095 if (!persistent) {
8096 mOrigDebugApp = mDebugApp;
8097 mOrigWaitForDebugger = mWaitForDebugger;
8098 }
8099 mDebugApp = packageName;
8100 mWaitForDebugger = waitForDebugger;
8101 mDebugTransient = !persistent;
8102 if (packageName != null) {
8103 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn03abb812010-01-04 18:43:19 -08008104 forceStopPackageLocked(packageName, -1, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008105 Binder.restoreCallingIdentity(origId);
8106 }
8107 }
8108 }
8109
8110 public void setAlwaysFinish(boolean enabled) {
8111 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8112 "setAlwaysFinish()");
8113
8114 Settings.System.putInt(
8115 mContext.getContentResolver(),
8116 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8117
8118 synchronized (this) {
8119 mAlwaysFinishActivities = enabled;
8120 }
8121 }
8122
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008123 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008124 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008125 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008126 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008127 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008128 }
8129 }
8130
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008131 public void registerActivityWatcher(IActivityWatcher watcher) {
8132 mWatchers.register(watcher);
8133 }
8134
8135 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8136 mWatchers.unregister(watcher);
8137 }
8138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008139 public final void enterSafeMode() {
8140 synchronized(this) {
8141 // It only makes sense to do this before the system is ready
8142 // and started launching other packages.
8143 if (!mSystemReady) {
8144 try {
8145 ActivityThread.getPackageManager().enterSafeMode();
8146 } catch (RemoteException e) {
8147 }
8148
8149 View v = LayoutInflater.from(mContext).inflate(
8150 com.android.internal.R.layout.safe_mode, null);
8151 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8152 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8153 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8154 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8155 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8156 lp.format = v.getBackground().getOpacity();
8157 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8158 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8159 ((WindowManager)mContext.getSystemService(
8160 Context.WINDOW_SERVICE)).addView(v, lp);
8161 }
8162 }
8163 }
8164
8165 public void noteWakeupAlarm(IIntentSender sender) {
8166 if (!(sender instanceof PendingIntentRecord)) {
8167 return;
8168 }
8169 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8170 synchronized (stats) {
8171 if (mBatteryStatsService.isOnBattery()) {
8172 mBatteryStatsService.enforceCallingPermission();
8173 PendingIntentRecord rec = (PendingIntentRecord)sender;
8174 int MY_UID = Binder.getCallingUid();
8175 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8176 BatteryStatsImpl.Uid.Pkg pkg =
8177 stats.getPackageStatsLocked(uid, rec.key.packageName);
8178 pkg.incWakeupsLocked();
8179 }
8180 }
8181 }
8182
8183 public boolean killPidsForMemory(int[] pids) {
8184 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8185 throw new SecurityException("killPidsForMemory only available to the system");
8186 }
8187
8188 // XXX Note: don't acquire main activity lock here, because the window
8189 // manager calls in with its locks held.
8190
8191 boolean killed = false;
8192 synchronized (mPidsSelfLocked) {
8193 int[] types = new int[pids.length];
8194 int worstType = 0;
8195 for (int i=0; i<pids.length; i++) {
8196 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8197 if (proc != null) {
8198 int type = proc.setAdj;
8199 types[i] = type;
8200 if (type > worstType) {
8201 worstType = type;
8202 }
8203 }
8204 }
8205
8206 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8207 // then constrain it so we will kill all hidden procs.
8208 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8209 worstType = HIDDEN_APP_MIN_ADJ;
8210 }
8211 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8212 for (int i=0; i<pids.length; i++) {
8213 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8214 if (proc == null) {
8215 continue;
8216 }
8217 int adj = proc.setAdj;
8218 if (adj >= worstType) {
8219 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8220 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008221 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008222 proc.processName, adj);
8223 killed = true;
8224 Process.killProcess(pids[i]);
8225 }
8226 }
8227 }
8228 return killed;
8229 }
8230
8231 public void reportPss(IApplicationThread caller, int pss) {
8232 Watchdog.PssRequestor req;
8233 String name;
8234 ProcessRecord callerApp;
8235 synchronized (this) {
8236 if (caller == null) {
8237 return;
8238 }
8239 callerApp = getRecordForAppLocked(caller);
8240 if (callerApp == null) {
8241 return;
8242 }
8243 callerApp.lastPss = pss;
8244 req = callerApp;
8245 name = callerApp.processName;
8246 }
8247 Watchdog.getInstance().reportPss(req, name, pss);
8248 if (!callerApp.persistent) {
8249 removeRequestedPss(callerApp);
8250 }
8251 }
8252
8253 public void requestPss(Runnable completeCallback) {
8254 ArrayList<ProcessRecord> procs;
8255 synchronized (this) {
8256 mRequestPssCallback = completeCallback;
8257 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008258 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8259 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008260 if (!proc.persistent) {
8261 mRequestPssList.add(proc);
8262 }
8263 }
8264 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8265 }
8266
8267 int oldPri = Process.getThreadPriority(Process.myTid());
8268 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8269 for (int i=procs.size()-1; i>=0; i--) {
8270 ProcessRecord proc = procs.get(i);
8271 proc.lastPss = 0;
8272 proc.requestPss();
8273 }
8274 Process.setThreadPriority(oldPri);
8275 }
8276
8277 void removeRequestedPss(ProcessRecord proc) {
8278 Runnable callback = null;
8279 synchronized (this) {
8280 if (mRequestPssList.remove(proc)) {
8281 if (mRequestPssList.size() == 0) {
8282 callback = mRequestPssCallback;
8283 mRequestPssCallback = null;
8284 }
8285 }
8286 }
8287
8288 if (callback != null) {
8289 callback.run();
8290 }
8291 }
8292
8293 public void collectPss(Watchdog.PssStats stats) {
8294 stats.mEmptyPss = 0;
8295 stats.mEmptyCount = 0;
8296 stats.mBackgroundPss = 0;
8297 stats.mBackgroundCount = 0;
8298 stats.mServicePss = 0;
8299 stats.mServiceCount = 0;
8300 stats.mVisiblePss = 0;
8301 stats.mVisibleCount = 0;
8302 stats.mForegroundPss = 0;
8303 stats.mForegroundCount = 0;
8304 stats.mNoPssCount = 0;
8305 synchronized (this) {
8306 int i;
8307 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8308 ? mProcDeaths.length : stats.mProcDeaths.length;
8309 int aggr = 0;
8310 for (i=0; i<NPD; i++) {
8311 aggr += mProcDeaths[i];
8312 stats.mProcDeaths[i] = aggr;
8313 }
8314 while (i<stats.mProcDeaths.length) {
8315 stats.mProcDeaths[i] = 0;
8316 i++;
8317 }
8318
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008319 for (i=mLruProcesses.size()-1; i>=0; i--) {
8320 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008321 if (proc.persistent) {
8322 continue;
8323 }
8324 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8325 if (proc.lastPss == 0) {
8326 stats.mNoPssCount++;
8327 continue;
8328 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008329 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8330 if (proc.empty) {
8331 stats.mEmptyPss += proc.lastPss;
8332 stats.mEmptyCount++;
8333 } else {
8334 stats.mBackgroundPss += proc.lastPss;
8335 stats.mBackgroundCount++;
8336 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008337 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8338 stats.mVisiblePss += proc.lastPss;
8339 stats.mVisibleCount++;
8340 } else {
8341 stats.mForegroundPss += proc.lastPss;
8342 stats.mForegroundCount++;
8343 }
8344 }
8345 }
8346 }
8347
8348 public final void startRunning(String pkg, String cls, String action,
8349 String data) {
8350 synchronized(this) {
8351 if (mStartRunning) {
8352 return;
8353 }
8354 mStartRunning = true;
8355 mTopComponent = pkg != null && cls != null
8356 ? new ComponentName(pkg, cls) : null;
8357 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8358 mTopData = data;
8359 if (!mSystemReady) {
8360 return;
8361 }
8362 }
8363
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008364 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008365 }
8366
8367 private void retrieveSettings() {
8368 final ContentResolver resolver = mContext.getContentResolver();
8369 String debugApp = Settings.System.getString(
8370 resolver, Settings.System.DEBUG_APP);
8371 boolean waitForDebugger = Settings.System.getInt(
8372 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8373 boolean alwaysFinishActivities = Settings.System.getInt(
8374 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8375
8376 Configuration configuration = new Configuration();
8377 Settings.System.getConfiguration(resolver, configuration);
8378
8379 synchronized (this) {
8380 mDebugApp = mOrigDebugApp = debugApp;
8381 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8382 mAlwaysFinishActivities = alwaysFinishActivities;
8383 // This happens before any activities are started, so we can
8384 // change mConfiguration in-place.
8385 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008386 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008387 }
8388 }
8389
8390 public boolean testIsSystemReady() {
8391 // no need to synchronize(this) just to read & return the value
8392 return mSystemReady;
8393 }
8394
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008395 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008396 // In the simulator, startRunning will never have been called, which
8397 // normally sets a few crucial variables. Do it here instead.
8398 if (!Process.supportsProcesses()) {
8399 mStartRunning = true;
8400 mTopAction = Intent.ACTION_MAIN;
8401 }
8402
8403 synchronized(this) {
8404 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008405 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008406 return;
8407 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008408
8409 // Check to see if there are any update receivers to run.
8410 if (!mDidUpdate) {
8411 if (mWaitingUpdate) {
8412 return;
8413 }
8414 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8415 List<ResolveInfo> ris = null;
8416 try {
8417 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8418 intent, null, 0);
8419 } catch (RemoteException e) {
8420 }
8421 if (ris != null) {
8422 for (int i=ris.size()-1; i>=0; i--) {
8423 if ((ris.get(i).activityInfo.applicationInfo.flags
8424 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8425 ris.remove(i);
8426 }
8427 }
8428 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8429 for (int i=0; i<ris.size(); i++) {
8430 ActivityInfo ai = ris.get(i).activityInfo;
8431 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8432 IIntentReceiver finisher = null;
8433 if (i == 0) {
8434 finisher = new IIntentReceiver.Stub() {
8435 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008436 String data, Bundle extras, boolean ordered,
8437 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008438 throws RemoteException {
8439 synchronized (ActivityManagerService.this) {
8440 mDidUpdate = true;
8441 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008442 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008443 }
8444 };
8445 }
8446 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8447 broadcastIntentLocked(null, null, intent, null, finisher,
8448 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8449 if (i == 0) {
8450 mWaitingUpdate = true;
8451 }
8452 }
8453 }
8454 if (mWaitingUpdate) {
8455 return;
8456 }
8457 mDidUpdate = true;
8458 }
8459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008460 mSystemReady = true;
8461 if (!mStartRunning) {
8462 return;
8463 }
8464 }
8465
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008466 ArrayList<ProcessRecord> procsToKill = null;
8467 synchronized(mPidsSelfLocked) {
8468 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8469 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8470 if (!isAllowedWhileBooting(proc.info)){
8471 if (procsToKill == null) {
8472 procsToKill = new ArrayList<ProcessRecord>();
8473 }
8474 procsToKill.add(proc);
8475 }
8476 }
8477 }
8478
8479 if (procsToKill != null) {
8480 synchronized(this) {
8481 for (int i=procsToKill.size()-1; i>=0; i--) {
8482 ProcessRecord proc = procsToKill.get(i);
8483 Log.i(TAG, "Removing system update proc: " + proc);
8484 removeProcessLocked(proc, true);
8485 }
8486 }
8487 }
8488
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008489 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008490 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008491 SystemClock.uptimeMillis());
8492
8493 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008494 // Make sure we have no pre-ready processes sitting around.
8495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008496 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8497 ResolveInfo ri = mContext.getPackageManager()
8498 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008499 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008500 CharSequence errorMsg = null;
8501 if (ri != null) {
8502 ActivityInfo ai = ri.activityInfo;
8503 ApplicationInfo app = ai.applicationInfo;
8504 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8505 mTopAction = Intent.ACTION_FACTORY_TEST;
8506 mTopData = null;
8507 mTopComponent = new ComponentName(app.packageName,
8508 ai.name);
8509 } else {
8510 errorMsg = mContext.getResources().getText(
8511 com.android.internal.R.string.factorytest_not_system);
8512 }
8513 } else {
8514 errorMsg = mContext.getResources().getText(
8515 com.android.internal.R.string.factorytest_no_action);
8516 }
8517 if (errorMsg != null) {
8518 mTopAction = null;
8519 mTopData = null;
8520 mTopComponent = null;
8521 Message msg = Message.obtain();
8522 msg.what = SHOW_FACTORY_ERROR_MSG;
8523 msg.getData().putCharSequence("msg", errorMsg);
8524 mHandler.sendMessage(msg);
8525 }
8526 }
8527 }
8528
8529 retrieveSettings();
8530
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008531 if (goingCallback != null) goingCallback.run();
8532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008533 synchronized (this) {
8534 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8535 try {
8536 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008537 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008538 if (apps != null) {
8539 int N = apps.size();
8540 int i;
8541 for (i=0; i<N; i++) {
8542 ApplicationInfo info
8543 = (ApplicationInfo)apps.get(i);
8544 if (info != null &&
8545 !info.packageName.equals("android")) {
8546 addAppLocked(info);
8547 }
8548 }
8549 }
8550 } catch (RemoteException ex) {
8551 // pm is in same process, this will never happen.
8552 }
8553 }
8554
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008555 // Start up initial activity.
8556 mBooting = true;
8557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008558 try {
8559 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8560 Message msg = Message.obtain();
8561 msg.what = SHOW_UID_ERROR_MSG;
8562 mHandler.sendMessage(msg);
8563 }
8564 } catch (RemoteException e) {
8565 }
8566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008567 resumeTopActivityLocked(null);
8568 }
8569 }
8570
Dan Egnorb7f03672009-12-09 16:22:32 -08008571 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008572 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008573 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008574 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008575 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008576 startAppProblemLocked(app);
8577 app.stopFreezingAllLocked();
8578 return handleAppCrashLocked(app);
8579 }
8580
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008581 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008582 // check if error reporting is enabled in Gservices
8583 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8584 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8585 if (enabled == 0) {
8586 return null;
8587 }
8588
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008589 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008590
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008591 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008592 // look for receiver in the installer package
8593 String candidate = pm.getInstallerPackageName(app.info.packageName);
8594 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8595 if (result != null) {
8596 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008597 }
8598
Jacek Surazski82a73df2009-06-17 14:33:18 +02008599 // if the error app is on the system image, look for system apps
8600 // error receiver
8601 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8602 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8603 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8604 if (result != null) {
8605 return result;
8606 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008607 }
8608
Jacek Surazski82a73df2009-06-17 14:33:18 +02008609 // if there is a default receiver, try that
8610 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8611 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008612 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008613 // should not happen
8614 Log.e(TAG, "error talking to PackageManager", e);
8615 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008616 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008617 }
8618
8619 /**
8620 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8621 *
8622 * @param pm PackageManager isntance
8623 * @param errorPackage package which caused the error
8624 * @param receiverPackage candidate package to receive the error
8625 * @return activity component within receiverPackage which handles
8626 * ACTION_APP_ERROR, or null if not found
8627 */
8628 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8629 String receiverPackage) throws RemoteException {
8630 if (receiverPackage == null || receiverPackage.length() == 0) {
8631 return null;
8632 }
8633
8634 // break the loop if it's the error report receiver package that crashed
8635 if (receiverPackage.equals(errorPackage)) {
8636 return null;
8637 }
8638
8639 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8640 intent.setPackage(receiverPackage);
8641 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8642 if (info == null || info.activityInfo == null) {
8643 return null;
8644 }
8645 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008646 }
8647
Dan Egnorb7f03672009-12-09 16:22:32 -08008648 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008649 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008650 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008651 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008652 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8653 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008654 startAppProblemLocked(app);
8655 app.stopFreezingAllLocked();
8656 }
8657
8658 /**
8659 * Generate a process error record, suitable for attachment to a ProcessRecord.
8660 *
8661 * @param app The ProcessRecord in which the error occurred.
8662 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8663 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008664 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008665 * @param shortMsg Short message describing the crash.
8666 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008667 * @param stackTrace Full crash stack trace, may be null.
8668 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008669 * @return Returns a fully-formed AppErrorStateInfo record.
8670 */
8671 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008672 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008673 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008675 report.condition = condition;
8676 report.processName = app.processName;
8677 report.pid = app.pid;
8678 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008679 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008680 report.shortMsg = shortMsg;
8681 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008682 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008683
8684 return report;
8685 }
8686
8687 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8688 boolean crashed) {
8689 synchronized (this) {
8690 app.crashing = false;
8691 app.crashingReport = null;
8692 app.notResponding = false;
8693 app.notRespondingReport = null;
8694 if (app.anrDialog == fromDialog) {
8695 app.anrDialog = null;
8696 }
8697 if (app.waitDialog == fromDialog) {
8698 app.waitDialog = null;
8699 }
8700 if (app.pid > 0 && app.pid != MY_PID) {
8701 if (crashed) {
8702 handleAppCrashLocked(app);
8703 }
8704 Log.i(ActivityManagerService.TAG, "Killing process "
8705 + app.processName
8706 + " (pid=" + app.pid + ") at user's request");
8707 Process.killProcess(app.pid);
8708 }
8709
8710 }
8711 }
8712
Dan Egnorb7f03672009-12-09 16:22:32 -08008713 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008714 long now = SystemClock.uptimeMillis();
8715
8716 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8717 app.info.uid);
8718 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8719 // This process loses!
8720 Log.w(TAG, "Process " + app.info.processName
8721 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008722 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008723 app.info.processName, app.info.uid);
8724 killServicesLocked(app, false);
8725 for (int i=mHistory.size()-1; i>=0; i--) {
8726 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8727 if (r.app == app) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08008728 Log.w(TAG, " Force finishing activity "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008729 + r.intent.getComponent().flattenToShortString());
8730 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8731 }
8732 }
8733 if (!app.persistent) {
8734 // We don't want to start this process again until the user
8735 // explicitly does so... but for persistent process, we really
8736 // need to keep it running. If a persistent process is actually
8737 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008738 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008739 app.info.processName);
8740 mBadProcesses.put(app.info.processName, app.info.uid, now);
8741 app.bad = true;
8742 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8743 app.removed = true;
8744 removeProcessLocked(app, false);
8745 return false;
8746 }
8747 }
8748
8749 // Bump up the crash count of any services currently running in the proc.
8750 if (app.services.size() != 0) {
8751 // Any services running in the application need to be placed
8752 // back in the pending list.
8753 Iterator it = app.services.iterator();
8754 while (it.hasNext()) {
8755 ServiceRecord sr = (ServiceRecord)it.next();
8756 sr.crashCount++;
8757 }
8758 }
8759
8760 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8761 return true;
8762 }
8763
8764 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008765 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008766 skipCurrentReceiverLocked(app);
8767 }
8768
8769 void skipCurrentReceiverLocked(ProcessRecord app) {
8770 boolean reschedule = false;
8771 BroadcastRecord r = app.curReceiver;
8772 if (r != null) {
8773 // The current broadcast is waiting for this app's receiver
8774 // to be finished. Looks like that's not going to happen, so
8775 // let the broadcast continue.
8776 logBroadcastReceiverDiscard(r);
8777 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8778 r.resultExtras, r.resultAbort, true);
8779 reschedule = true;
8780 }
8781 r = mPendingBroadcast;
8782 if (r != null && r.curApp == app) {
8783 if (DEBUG_BROADCAST) Log.v(TAG,
8784 "skip & discard pending app " + r);
8785 logBroadcastReceiverDiscard(r);
8786 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8787 r.resultExtras, r.resultAbort, true);
8788 reschedule = true;
8789 }
8790 if (reschedule) {
8791 scheduleBroadcastsLocked();
8792 }
8793 }
8794
Dan Egnor60d87622009-12-16 16:32:58 -08008795 /**
8796 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8797 * The application process will exit immediately after this call returns.
8798 * @param app object of the crashing app, null for the system server
8799 * @param crashInfo describing the exception
8800 */
8801 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8802 ProcessRecord r = findAppProcess(app);
8803
8804 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8805 app == null ? "system" : (r == null ? "unknown" : r.processName),
8806 crashInfo.exceptionClassName,
8807 crashInfo.exceptionMessage,
8808 crashInfo.throwFileName,
8809 crashInfo.throwLineNumber);
8810
8811 addExceptionToDropBox("crash", r, null, crashInfo);
8812
8813 crashApplication(r, crashInfo);
8814 }
8815
8816 /**
8817 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8818 * @param app object of the crashing app, null for the system server
8819 * @param tag reported by the caller
8820 * @param crashInfo describing the context of the error
8821 * @return true if the process should exit immediately (WTF is fatal)
8822 */
8823 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008824 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008825 ProcessRecord r = findAppProcess(app);
8826
8827 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8828 app == null ? "system" : (r == null ? "unknown" : r.processName),
8829 tag, crashInfo.exceptionMessage);
8830
8831 addExceptionToDropBox("wtf", r, tag, crashInfo);
8832
8833 if (Settings.Gservices.getInt(mContext.getContentResolver(),
8834 Settings.Gservices.WTF_IS_FATAL, 0) != 0) {
8835 crashApplication(r, crashInfo);
8836 return true;
8837 } else {
8838 return false;
8839 }
8840 }
8841
8842 /**
8843 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8844 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8845 */
8846 private ProcessRecord findAppProcess(IBinder app) {
8847 if (app == null) {
8848 return null;
8849 }
8850
8851 synchronized (this) {
8852 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8853 final int NA = apps.size();
8854 for (int ia=0; ia<NA; ia++) {
8855 ProcessRecord p = apps.valueAt(ia);
8856 if (p.thread != null && p.thread.asBinder() == app) {
8857 return p;
8858 }
8859 }
8860 }
8861
8862 Log.w(TAG, "Can't find mystery application: " + app);
8863 return null;
8864 }
8865 }
8866
8867 /**
8868 * Write a description of an exception (from a crash or WTF report) to the drop box.
8869 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
8870 * @param r the process which crashed, null for the system server
8871 * @param tag supplied by the application (in the case of WTF), or null
8872 * @param crashInfo describing the exception
8873 */
8874 private void addExceptionToDropBox(String eventType, ProcessRecord r, String tag,
8875 ApplicationErrorReport.CrashInfo crashInfo) {
8876 String dropboxTag, processName;
8877 if (r == null) {
8878 dropboxTag = "system_server_" + eventType;
8879 } else if ((r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
8880 dropboxTag = "system_app_" + eventType;
8881 } else {
8882 dropboxTag = "data_app_" + eventType;
8883 }
8884
8885 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8886 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8887 StringBuilder sb = new StringBuilder(1024);
8888 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8889 if (r == null) {
8890 sb.append("Process: system_server\n");
8891 } else {
8892 sb.append("Package: ").append(r.info.packageName).append("\n");
8893 if (!r.processName.equals(r.info.packageName)) {
8894 sb.append("Process: ").append(r.processName).append("\n");
8895 }
8896 }
8897 if (tag != null) {
8898 sb.append("Tag: ").append(tag).append("\n");
8899 }
8900 if (crashInfo != null && crashInfo.stackTrace != null) {
8901 sb.append("\n").append(crashInfo.stackTrace);
8902 }
8903 dbox.addText(dropboxTag, sb.toString());
8904 }
8905 }
8906
8907 /**
8908 * Bring up the "unexpected error" dialog box for a crashing app.
8909 * Deal with edge cases (intercepts from instrumented applications,
8910 * ActivityController, error intent receivers, that sort of thing).
8911 * @param r the application crashing
8912 * @param crashInfo describing the failure
8913 */
8914 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008915 long timeMillis = System.currentTimeMillis();
8916 String shortMsg = crashInfo.exceptionClassName;
8917 String longMsg = crashInfo.exceptionMessage;
8918 String stackTrace = crashInfo.stackTrace;
8919 if (shortMsg != null && longMsg != null) {
8920 longMsg = shortMsg + ": " + longMsg;
8921 } else if (shortMsg != null) {
8922 longMsg = shortMsg;
8923 }
8924
Dan Egnor60d87622009-12-16 16:32:58 -08008925 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008926 synchronized (this) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008927 if (r != null) {
8928 // The application has crashed. Send the SIGQUIT to the process so
8929 // that it can dump its state.
8930 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8931 //Log.i(TAG, "Current system threads:");
8932 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8933 }
8934
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008935 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008936 try {
8937 String name = r != null ? r.processName : null;
8938 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008939 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008940 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008941 Log.w(TAG, "Force-killing crashed app " + name
8942 + " at watcher's request");
8943 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008944 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008945 }
8946 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008947 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008948 }
8949 }
8950
8951 final long origId = Binder.clearCallingIdentity();
8952
8953 // If this process is running instrumentation, finish it.
8954 if (r != null && r.instrumentationClass != null) {
8955 Log.w(TAG, "Error in app " + r.processName
8956 + " running instrumentation " + r.instrumentationClass + ":");
8957 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8958 if (longMsg != null) Log.w(TAG, " " + longMsg);
8959 Bundle info = new Bundle();
8960 info.putString("shortMsg", shortMsg);
8961 info.putString("longMsg", longMsg);
8962 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8963 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008964 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008965 }
8966
Dan Egnor60d87622009-12-16 16:32:58 -08008967 // If we can't identify the process or it's already exceeded its crash quota,
8968 // quit right away without showing a crash dialog.
8969 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008971 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008972 }
8973
8974 Message msg = Message.obtain();
8975 msg.what = SHOW_ERROR_MSG;
8976 HashMap data = new HashMap();
8977 data.put("result", result);
8978 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008979 msg.obj = data;
8980 mHandler.sendMessage(msg);
8981
8982 Binder.restoreCallingIdentity(origId);
8983 }
8984
8985 int res = result.get();
8986
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008987 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008988 synchronized (this) {
8989 if (r != null) {
8990 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8991 SystemClock.uptimeMillis());
8992 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008993 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008994 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008995 }
8996 }
8997
8998 if (appErrorIntent != null) {
8999 try {
9000 mContext.startActivity(appErrorIntent);
9001 } catch (ActivityNotFoundException e) {
9002 Log.w(TAG, "bug report receiver dissappeared", e);
9003 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009005 }
Dan Egnorb7f03672009-12-09 16:22:32 -08009006
9007 Intent createAppErrorIntentLocked(ProcessRecord r,
9008 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
9009 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009010 if (report == null) {
9011 return null;
9012 }
9013 Intent result = new Intent(Intent.ACTION_APP_ERROR);
9014 result.setComponent(r.errorReportReceiver);
9015 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
9016 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
9017 return result;
9018 }
9019
Dan Egnorb7f03672009-12-09 16:22:32 -08009020 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
9021 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009022 if (r.errorReportReceiver == null) {
9023 return null;
9024 }
9025
9026 if (!r.crashing && !r.notResponding) {
9027 return null;
9028 }
9029
Dan Egnorb7f03672009-12-09 16:22:32 -08009030 ApplicationErrorReport report = new ApplicationErrorReport();
9031 report.packageName = r.info.packageName;
9032 report.installerPackageName = r.errorReportReceiver.getPackageName();
9033 report.processName = r.processName;
9034 report.time = timeMillis;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009035
Dan Egnorb7f03672009-12-09 16:22:32 -08009036 if (r.crashing) {
9037 report.type = ApplicationErrorReport.TYPE_CRASH;
9038 report.crashInfo = crashInfo;
9039 } else if (r.notResponding) {
9040 report.type = ApplicationErrorReport.TYPE_ANR;
9041 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009042
Dan Egnorb7f03672009-12-09 16:22:32 -08009043 report.anrInfo.activity = r.notRespondingReport.tag;
9044 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9045 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009046 }
9047
Dan Egnorb7f03672009-12-09 16:22:32 -08009048 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009049 }
9050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009051 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9052 // assume our apps are happy - lazy create the list
9053 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9054
9055 synchronized (this) {
9056
9057 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009058 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9059 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009060 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9061 // This one's in trouble, so we'll generate a report for it
9062 // crashes are higher priority (in case there's a crash *and* an anr)
9063 ActivityManager.ProcessErrorStateInfo report = null;
9064 if (app.crashing) {
9065 report = app.crashingReport;
9066 } else if (app.notResponding) {
9067 report = app.notRespondingReport;
9068 }
9069
9070 if (report != null) {
9071 if (errList == null) {
9072 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9073 }
9074 errList.add(report);
9075 } else {
9076 Log.w(TAG, "Missing app error report, app = " + app.processName +
9077 " crashing = " + app.crashing +
9078 " notResponding = " + app.notResponding);
9079 }
9080 }
9081 }
9082 }
9083
9084 return errList;
9085 }
9086
9087 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9088 // Lazy instantiation of list
9089 List<ActivityManager.RunningAppProcessInfo> runList = null;
9090 synchronized (this) {
9091 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009092 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9093 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009094 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9095 // Generate process state info for running application
9096 ActivityManager.RunningAppProcessInfo currApp =
9097 new ActivityManager.RunningAppProcessInfo(app.processName,
9098 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009099 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009100 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009101 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009102 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9103 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9104 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009105 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9106 } else if (adj >= HOME_APP_ADJ) {
9107 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9108 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009109 } else if (adj >= SECONDARY_SERVER_ADJ) {
9110 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9111 } else if (adj >= VISIBLE_APP_ADJ) {
9112 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9113 } else {
9114 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9115 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009116 currApp.importanceReasonCode = app.adjTypeCode;
9117 if (app.adjSource instanceof ProcessRecord) {
9118 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9119 } else if (app.adjSource instanceof HistoryRecord) {
9120 HistoryRecord r = (HistoryRecord)app.adjSource;
9121 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9122 }
9123 if (app.adjTarget instanceof ComponentName) {
9124 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9125 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009126 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9127 // + " lru=" + currApp.lru);
9128 if (runList == null) {
9129 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9130 }
9131 runList.add(currApp);
9132 }
9133 }
9134 }
9135 return runList;
9136 }
9137
9138 @Override
9139 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009140 if (checkCallingPermission(android.Manifest.permission.DUMP)
9141 != PackageManager.PERMISSION_GRANTED) {
9142 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9143 + Binder.getCallingPid()
9144 + ", uid=" + Binder.getCallingUid()
9145 + " without permission "
9146 + android.Manifest.permission.DUMP);
9147 return;
9148 }
9149
9150 boolean dumpAll = false;
9151
9152 int opti = 0;
9153 while (opti < args.length) {
9154 String opt = args[opti];
9155 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9156 break;
9157 }
9158 opti++;
9159 if ("-a".equals(opt)) {
9160 dumpAll = true;
9161 } else if ("-h".equals(opt)) {
9162 pw.println("Activity manager dump options:");
9163 pw.println(" [-a] [h- [cmd] ...");
9164 pw.println(" cmd may be one of:");
9165 pw.println(" activities: activity stack state");
9166 pw.println(" broadcasts: broadcast state");
9167 pw.println(" intents: pending intent state");
9168 pw.println(" processes: process state");
9169 pw.println(" providers: content provider state");
9170 pw.println(" services: service state");
9171 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009172 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009173 } else {
9174 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009175 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009176 }
9177
9178 // Is the caller requesting to dump a particular piece of data?
9179 if (opti < args.length) {
9180 String cmd = args[opti];
9181 opti++;
9182 if ("activities".equals(cmd) || "a".equals(cmd)) {
9183 synchronized (this) {
9184 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009185 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009186 return;
9187 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9188 synchronized (this) {
9189 dumpBroadcastsLocked(fd, pw, args, opti, true);
9190 }
9191 return;
9192 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9193 synchronized (this) {
9194 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9195 }
9196 return;
9197 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9198 synchronized (this) {
9199 dumpProcessesLocked(fd, pw, args, opti, true);
9200 }
9201 return;
9202 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9203 synchronized (this) {
9204 dumpProvidersLocked(fd, pw, args, opti, true);
9205 }
9206 return;
9207 } else if ("service".equals(cmd)) {
9208 dumpService(fd, pw, args, opti, true);
9209 return;
9210 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9211 synchronized (this) {
9212 dumpServicesLocked(fd, pw, args, opti, true);
9213 }
9214 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009215 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009216 }
9217
9218 // No piece of data specified, dump everything.
9219 synchronized (this) {
9220 boolean needSep;
9221 if (dumpAll) {
9222 pw.println("Providers in Current Activity Manager State:");
9223 }
9224 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9225 if (needSep) {
9226 pw.println(" ");
9227 }
9228 if (dumpAll) {
9229 pw.println("-------------------------------------------------------------------------------");
9230 pw.println("Broadcasts in Current Activity Manager State:");
9231 }
9232 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9233 if (needSep) {
9234 pw.println(" ");
9235 }
9236 if (dumpAll) {
9237 pw.println("-------------------------------------------------------------------------------");
9238 pw.println("Services in Current Activity Manager State:");
9239 }
9240 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9241 if (needSep) {
9242 pw.println(" ");
9243 }
9244 if (dumpAll) {
9245 pw.println("-------------------------------------------------------------------------------");
9246 pw.println("PendingIntents in Current Activity Manager State:");
9247 }
9248 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9249 if (needSep) {
9250 pw.println(" ");
9251 }
9252 if (dumpAll) {
9253 pw.println("-------------------------------------------------------------------------------");
9254 pw.println("Activities in Current Activity Manager State:");
9255 }
9256 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9257 if (needSep) {
9258 pw.println(" ");
9259 }
9260 if (dumpAll) {
9261 pw.println("-------------------------------------------------------------------------------");
9262 pw.println("Processes in Current Activity Manager State:");
9263 }
9264 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9265 }
9266 }
9267
9268 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9269 int opti, boolean dumpAll, boolean needHeader) {
9270 if (needHeader) {
9271 pw.println(" Activity stack:");
9272 }
9273 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9274 pw.println(" ");
9275 pw.println(" Running activities (most recent first):");
9276 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9277 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009278 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009279 pw.println(" Activities waiting for another to become visible:");
9280 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9281 }
9282 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009283 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009284 pw.println(" Activities waiting to stop:");
9285 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9286 }
9287 if (mFinishingActivities.size() > 0) {
9288 pw.println(" ");
9289 pw.println(" Activities waiting to finish:");
9290 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9291 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009292
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009293 pw.println(" ");
9294 pw.println(" mPausingActivity: " + mPausingActivity);
9295 pw.println(" mResumedActivity: " + mResumedActivity);
9296 pw.println(" mFocusedActivity: " + mFocusedActivity);
9297 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009298
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009299 if (dumpAll && mRecentTasks.size() > 0) {
9300 pw.println(" ");
9301 pw.println("Recent tasks in Current Activity Manager State:");
9302
9303 final int N = mRecentTasks.size();
9304 for (int i=0; i<N; i++) {
9305 TaskRecord tr = mRecentTasks.get(i);
9306 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9307 pw.println(tr);
9308 mRecentTasks.get(i).dump(pw, " ");
9309 }
9310 }
9311
9312 pw.println(" ");
9313 pw.println(" mCurTask: " + mCurTask);
9314
9315 return true;
9316 }
9317
9318 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9319 int opti, boolean dumpAll) {
9320 boolean needSep = false;
9321 int numPers = 0;
9322
9323 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009324 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9325 final int NA = procs.size();
9326 for (int ia=0; ia<NA; ia++) {
9327 if (!needSep) {
9328 pw.println(" All known processes:");
9329 needSep = true;
9330 }
9331 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009332 pw.print(r.persistent ? " *PERS*" : " *APP*");
9333 pw.print(" UID "); pw.print(procs.keyAt(ia));
9334 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009335 r.dump(pw, " ");
9336 if (r.persistent) {
9337 numPers++;
9338 }
9339 }
9340 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009341 }
9342
9343 if (mLruProcesses.size() > 0) {
9344 if (needSep) pw.println(" ");
9345 needSep = true;
9346 pw.println(" Running processes (most recent first):");
9347 dumpProcessList(pw, this, mLruProcesses, " ",
9348 "App ", "PERS", true);
9349 needSep = true;
9350 }
9351
9352 synchronized (mPidsSelfLocked) {
9353 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009354 if (needSep) pw.println(" ");
9355 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009356 pw.println(" PID mappings:");
9357 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9358 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9359 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009360 }
9361 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009362 }
9363
9364 if (mForegroundProcesses.size() > 0) {
9365 if (needSep) pw.println(" ");
9366 needSep = true;
9367 pw.println(" Foreground Processes:");
9368 for (int i=0; i<mForegroundProcesses.size(); i++) {
9369 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9370 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009371 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009372 }
9373
9374 if (mPersistentStartingProcesses.size() > 0) {
9375 if (needSep) pw.println(" ");
9376 needSep = true;
9377 pw.println(" Persisent processes that are starting:");
9378 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9379 "Starting Norm", "Restarting PERS", false);
9380 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009381
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009382 if (mStartingProcesses.size() > 0) {
9383 if (needSep) pw.println(" ");
9384 needSep = true;
9385 pw.println(" Processes that are starting:");
9386 dumpProcessList(pw, this, mStartingProcesses, " ",
9387 "Starting Norm", "Starting PERS", false);
9388 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009389
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009390 if (mRemovedProcesses.size() > 0) {
9391 if (needSep) pw.println(" ");
9392 needSep = true;
9393 pw.println(" Processes that are being removed:");
9394 dumpProcessList(pw, this, mRemovedProcesses, " ",
9395 "Removed Norm", "Removed PERS", false);
9396 }
9397
9398 if (mProcessesOnHold.size() > 0) {
9399 if (needSep) pw.println(" ");
9400 needSep = true;
9401 pw.println(" Processes that are on old until the system is ready:");
9402 dumpProcessList(pw, this, mProcessesOnHold, " ",
9403 "OnHold Norm", "OnHold PERS", false);
9404 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009405
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009406 if (mProcessesToGc.size() > 0) {
9407 if (needSep) pw.println(" ");
9408 needSep = true;
9409 pw.println(" Processes that are waiting to GC:");
9410 long now = SystemClock.uptimeMillis();
9411 for (int i=0; i<mProcessesToGc.size(); i++) {
9412 ProcessRecord proc = mProcessesToGc.get(i);
9413 pw.print(" Process "); pw.println(proc);
9414 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9415 pw.print(", last gced=");
9416 pw.print(now-proc.lastRequestedGc);
9417 pw.print(" ms ago, last lowMem=");
9418 pw.print(now-proc.lastLowMemory);
9419 pw.println(" ms ago");
9420
9421 }
9422 }
9423
9424 if (mProcessCrashTimes.getMap().size() > 0) {
9425 if (needSep) pw.println(" ");
9426 needSep = true;
9427 pw.println(" Time since processes crashed:");
9428 long now = SystemClock.uptimeMillis();
9429 for (Map.Entry<String, SparseArray<Long>> procs
9430 : mProcessCrashTimes.getMap().entrySet()) {
9431 SparseArray<Long> uids = procs.getValue();
9432 final int N = uids.size();
9433 for (int i=0; i<N; i++) {
9434 pw.print(" Process "); pw.print(procs.getKey());
9435 pw.print(" uid "); pw.print(uids.keyAt(i));
9436 pw.print(": last crashed ");
9437 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009438 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009439 }
9440 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009441 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009442
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009443 if (mBadProcesses.getMap().size() > 0) {
9444 if (needSep) pw.println(" ");
9445 needSep = true;
9446 pw.println(" Bad processes:");
9447 for (Map.Entry<String, SparseArray<Long>> procs
9448 : mBadProcesses.getMap().entrySet()) {
9449 SparseArray<Long> uids = procs.getValue();
9450 final int N = uids.size();
9451 for (int i=0; i<N; i++) {
9452 pw.print(" Bad process "); pw.print(procs.getKey());
9453 pw.print(" uid "); pw.print(uids.keyAt(i));
9454 pw.print(": crashed at time ");
9455 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009456 }
9457 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009459
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009460 pw.println(" ");
9461 pw.println(" mHomeProcess: " + mHomeProcess);
9462 pw.println(" mConfiguration: " + mConfiguration);
9463 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9464 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9465 || mOrigWaitForDebugger) {
9466 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9467 + " mDebugTransient=" + mDebugTransient
9468 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9469 }
9470 if (mAlwaysFinishActivities || mController != null) {
9471 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9472 + " mController=" + mController);
9473 }
9474 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009475 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009476 pw.println(" mStartRunning=" + mStartRunning
9477 + " mSystemReady=" + mSystemReady
9478 + " mBooting=" + mBooting
9479 + " mBooted=" + mBooted
9480 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009481 pw.println(" mGoingToSleep=" + mGoingToSleep);
9482 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009483 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009484
9485 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009486 }
9487
9488 /**
9489 * There are three ways to call this:
9490 * - no service specified: dump all the services
9491 * - a flattened component name that matched an existing service was specified as the
9492 * first arg: dump that one service
9493 * - the first arg isn't the flattened component name of an existing service:
9494 * dump all services whose component contains the first arg as a substring
9495 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009496 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9497 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009498 String[] newArgs;
9499 String componentNameString;
9500 ServiceRecord r;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009501 if (opti <= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009502 componentNameString = null;
9503 newArgs = EMPTY_STRING_ARRAY;
9504 r = null;
9505 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009506 componentNameString = args[opti];
9507 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009508 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9509 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009510 newArgs = new String[args.length - opti];
9511 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009512 }
9513
9514 if (r != null) {
9515 dumpService(fd, pw, r, newArgs);
9516 } else {
9517 for (ServiceRecord r1 : mServices.values()) {
9518 if (componentNameString == null
9519 || r1.name.flattenToString().contains(componentNameString)) {
9520 dumpService(fd, pw, r1, newArgs);
9521 }
9522 }
9523 }
9524 }
9525
9526 /**
9527 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9528 * there is a thread associated with the service.
9529 */
9530 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9531 pw.println(" Service " + r.name.flattenToString());
9532 if (r.app != null && r.app.thread != null) {
9533 try {
9534 // flush anything that is already in the PrintWriter since the thread is going
9535 // to write to the file descriptor directly
9536 pw.flush();
9537 r.app.thread.dumpService(fd, r, args);
9538 pw.print("\n");
9539 } catch (RemoteException e) {
9540 pw.println("got a RemoteException while dumping the service");
9541 }
9542 }
9543 }
9544
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009545 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9546 int opti, boolean dumpAll) {
9547 boolean needSep = false;
9548
9549 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009550 if (mRegisteredReceivers.size() > 0) {
9551 pw.println(" ");
9552 pw.println(" Registered Receivers:");
9553 Iterator it = mRegisteredReceivers.values().iterator();
9554 while (it.hasNext()) {
9555 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009556 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009557 r.dump(pw, " ");
9558 }
9559 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009561 pw.println(" ");
9562 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009563 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009564 needSep = true;
9565 }
9566
9567 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9568 || mPendingBroadcast != null) {
9569 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009570 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009571 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009572 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009573 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9574 pw.println(" Broadcast #" + i + ":");
9575 mParallelBroadcasts.get(i).dump(pw, " ");
9576 }
9577 if (mOrderedBroadcasts.size() > 0) {
9578 pw.println(" ");
9579 pw.println(" Active serialized broadcasts:");
9580 }
9581 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9582 pw.println(" Serialized Broadcast #" + i + ":");
9583 mOrderedBroadcasts.get(i).dump(pw, " ");
9584 }
9585 pw.println(" ");
9586 pw.println(" Pending broadcast:");
9587 if (mPendingBroadcast != null) {
9588 mPendingBroadcast.dump(pw, " ");
9589 } else {
9590 pw.println(" (null)");
9591 }
9592 needSep = true;
9593 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009594
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009595 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009596 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009597 pw.println(" Historical broadcasts:");
9598 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9599 BroadcastRecord r = mBroadcastHistory[i];
9600 if (r == null) {
9601 break;
9602 }
9603 pw.println(" Historical Broadcast #" + i + ":");
9604 r.dump(pw, " ");
9605 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009606 needSep = true;
9607 }
9608
9609 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009610 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009611 pw.println(" Sticky broadcasts:");
9612 StringBuilder sb = new StringBuilder(128);
9613 for (Map.Entry<String, ArrayList<Intent>> ent
9614 : mStickyBroadcasts.entrySet()) {
9615 pw.print(" * Sticky action "); pw.print(ent.getKey());
9616 pw.println(":");
9617 ArrayList<Intent> intents = ent.getValue();
9618 final int N = intents.size();
9619 for (int i=0; i<N; i++) {
9620 sb.setLength(0);
9621 sb.append(" Intent: ");
9622 intents.get(i).toShortString(sb, true, false);
9623 pw.println(sb.toString());
9624 Bundle bundle = intents.get(i).getExtras();
9625 if (bundle != null) {
9626 pw.print(" ");
9627 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009628 }
9629 }
9630 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009631 needSep = true;
9632 }
9633
9634 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009635 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009636 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009637 pw.println(" mHandler:");
9638 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009639 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009640 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009641
9642 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009643 }
9644
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009645 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9646 int opti, boolean dumpAll) {
9647 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009648
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009649 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009650 if (mServices.size() > 0) {
9651 pw.println(" Active services:");
9652 Iterator<ServiceRecord> it = mServices.values().iterator();
9653 while (it.hasNext()) {
9654 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009655 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009656 r.dump(pw, " ");
9657 }
9658 needSep = true;
9659 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009661
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009662 if (mPendingServices.size() > 0) {
9663 if (needSep) pw.println(" ");
9664 pw.println(" Pending services:");
9665 for (int i=0; i<mPendingServices.size(); i++) {
9666 ServiceRecord r = mPendingServices.get(i);
9667 pw.print(" * Pending "); pw.println(r);
9668 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009669 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009670 needSep = true;
9671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009672
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009673 if (mRestartingServices.size() > 0) {
9674 if (needSep) pw.println(" ");
9675 pw.println(" Restarting services:");
9676 for (int i=0; i<mRestartingServices.size(); i++) {
9677 ServiceRecord r = mRestartingServices.get(i);
9678 pw.print(" * Restarting "); pw.println(r);
9679 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009680 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009681 needSep = true;
9682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009683
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009684 if (mStoppingServices.size() > 0) {
9685 if (needSep) pw.println(" ");
9686 pw.println(" Stopping services:");
9687 for (int i=0; i<mStoppingServices.size(); i++) {
9688 ServiceRecord r = mStoppingServices.get(i);
9689 pw.print(" * Stopping "); pw.println(r);
9690 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009691 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009692 needSep = true;
9693 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009694
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009695 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009696 if (mServiceConnections.size() > 0) {
9697 if (needSep) pw.println(" ");
9698 pw.println(" Connection bindings to services:");
9699 Iterator<ConnectionRecord> it
9700 = mServiceConnections.values().iterator();
9701 while (it.hasNext()) {
9702 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009703 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009704 r.dump(pw, " ");
9705 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009706 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009707 }
9708 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009709
9710 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009711 }
9712
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009713 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9714 int opti, boolean dumpAll) {
9715 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009716
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009717 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009718 if (mProvidersByClass.size() > 0) {
9719 if (needSep) pw.println(" ");
9720 pw.println(" Published content providers (by class):");
9721 Iterator it = mProvidersByClass.entrySet().iterator();
9722 while (it.hasNext()) {
9723 Map.Entry e = (Map.Entry)it.next();
9724 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009725 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009726 r.dump(pw, " ");
9727 }
9728 needSep = true;
9729 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009730
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009731 if (mProvidersByName.size() > 0) {
9732 pw.println(" ");
9733 pw.println(" Authority to provider mappings:");
9734 Iterator it = mProvidersByName.entrySet().iterator();
9735 while (it.hasNext()) {
9736 Map.Entry e = (Map.Entry)it.next();
9737 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9738 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9739 pw.println(r);
9740 }
9741 needSep = true;
9742 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009743 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009744
9745 if (mLaunchingProviders.size() > 0) {
9746 if (needSep) pw.println(" ");
9747 pw.println(" Launching content providers:");
9748 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9749 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9750 pw.println(mLaunchingProviders.get(i));
9751 }
9752 needSep = true;
9753 }
9754
9755 if (mGrantedUriPermissions.size() > 0) {
9756 pw.println();
9757 pw.println("Granted Uri Permissions:");
9758 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9759 int uid = mGrantedUriPermissions.keyAt(i);
9760 HashMap<Uri, UriPermission> perms
9761 = mGrantedUriPermissions.valueAt(i);
9762 pw.print(" * UID "); pw.print(uid);
9763 pw.println(" holds:");
9764 for (UriPermission perm : perms.values()) {
9765 pw.print(" "); pw.println(perm);
9766 perm.dump(pw, " ");
9767 }
9768 }
9769 needSep = true;
9770 }
9771
9772 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009773 }
9774
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009775 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9776 int opti, boolean dumpAll) {
9777 boolean needSep = false;
9778
9779 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009780 if (this.mIntentSenderRecords.size() > 0) {
9781 Iterator<WeakReference<PendingIntentRecord>> it
9782 = mIntentSenderRecords.values().iterator();
9783 while (it.hasNext()) {
9784 WeakReference<PendingIntentRecord> ref = it.next();
9785 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009786 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009787 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009788 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009789 rec.dump(pw, " ");
9790 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009791 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009792 }
9793 }
9794 }
9795 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009796
9797 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009798 }
9799
9800 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009801 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009802 TaskRecord lastTask = null;
9803 for (int i=list.size()-1; i>=0; i--) {
9804 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009805 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009806 if (lastTask != r.task) {
9807 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009808 pw.print(prefix);
9809 pw.print(full ? "* " : " ");
9810 pw.println(lastTask);
9811 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009812 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009814 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009815 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9816 pw.print(" #"); pw.print(i); pw.print(": ");
9817 pw.println(r);
9818 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009819 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009820 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009821 }
9822 }
9823
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009824 private static String buildOomTag(String prefix, String space, int val, int base) {
9825 if (val == base) {
9826 if (space == null) return prefix;
9827 return prefix + " ";
9828 }
9829 return prefix + "+" + Integer.toString(val-base);
9830 }
9831
9832 private static final int dumpProcessList(PrintWriter pw,
9833 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009834 String prefix, String normalLabel, String persistentLabel,
9835 boolean inclOomAdj) {
9836 int numPers = 0;
9837 for (int i=list.size()-1; i>=0; i--) {
9838 ProcessRecord r = (ProcessRecord)list.get(i);
9839 if (false) {
9840 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9841 + " #" + i + ":");
9842 r.dump(pw, prefix + " ");
9843 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009844 String oomAdj;
9845 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009846 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009847 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009848 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9849 } else if (r.setAdj >= HOME_APP_ADJ) {
9850 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9851 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9852 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9853 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9854 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9855 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9856 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9857 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9858 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009859 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009860 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009861 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009862 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009863 } else {
9864 oomAdj = Integer.toString(r.setAdj);
9865 }
9866 String schedGroup;
9867 switch (r.setSchedGroup) {
9868 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9869 schedGroup = "B";
9870 break;
9871 case Process.THREAD_GROUP_DEFAULT:
9872 schedGroup = "F";
9873 break;
9874 default:
9875 schedGroup = Integer.toString(r.setSchedGroup);
9876 break;
9877 }
9878 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009879 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009880 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009881 if (r.adjSource != null || r.adjTarget != null) {
9882 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009883 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009884 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009885 } else {
9886 pw.println(String.format("%s%s #%2d: %s",
9887 prefix, (r.persistent ? persistentLabel : normalLabel),
9888 i, r.toString()));
9889 }
9890 if (r.persistent) {
9891 numPers++;
9892 }
9893 }
9894 return numPers;
9895 }
9896
9897 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9898 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009899 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009900 long uptime = SystemClock.uptimeMillis();
9901 long realtime = SystemClock.elapsedRealtime();
9902
9903 if (isCheckinRequest) {
9904 // short checkin version
9905 pw.println(uptime + "," + realtime);
9906 pw.flush();
9907 } else {
9908 pw.println("Applications Memory Usage (kB):");
9909 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9910 }
9911 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9912 ProcessRecord r = (ProcessRecord)list.get(i);
9913 if (r.thread != null) {
9914 if (!isCheckinRequest) {
9915 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9916 pw.flush();
9917 }
9918 try {
9919 r.thread.asBinder().dump(fd, args);
9920 } catch (RemoteException e) {
9921 if (!isCheckinRequest) {
9922 pw.println("Got RemoteException!");
9923 pw.flush();
9924 }
9925 }
9926 }
9927 }
9928 }
9929
9930 /**
9931 * Searches array of arguments for the specified string
9932 * @param args array of argument strings
9933 * @param value value to search for
9934 * @return true if the value is contained in the array
9935 */
9936 private static boolean scanArgs(String[] args, String value) {
9937 if (args != null) {
9938 for (String arg : args) {
9939 if (value.equals(arg)) {
9940 return true;
9941 }
9942 }
9943 }
9944 return false;
9945 }
9946
Dianne Hackborn75b03852009-06-12 15:43:26 -07009947 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009948 int count = mHistory.size();
9949
9950 // convert the token to an entry in the history.
9951 HistoryRecord r = null;
9952 int index = -1;
9953 for (int i=count-1; i>=0; i--) {
9954 Object o = mHistory.get(i);
9955 if (o == token) {
9956 r = (HistoryRecord)o;
9957 index = i;
9958 break;
9959 }
9960 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009961
9962 return index;
9963 }
9964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009965 private final void killServicesLocked(ProcessRecord app,
9966 boolean allowRestart) {
9967 // Report disconnected services.
9968 if (false) {
9969 // XXX we are letting the client link to the service for
9970 // death notifications.
9971 if (app.services.size() > 0) {
9972 Iterator it = app.services.iterator();
9973 while (it.hasNext()) {
9974 ServiceRecord r = (ServiceRecord)it.next();
9975 if (r.connections.size() > 0) {
9976 Iterator<ConnectionRecord> jt
9977 = r.connections.values().iterator();
9978 while (jt.hasNext()) {
9979 ConnectionRecord c = jt.next();
9980 if (c.binding.client != app) {
9981 try {
9982 //c.conn.connected(r.className, null);
9983 } catch (Exception e) {
9984 // todo: this should be asynchronous!
9985 Log.w(TAG, "Exception thrown disconnected servce "
9986 + r.shortName
9987 + " from app " + app.processName, e);
9988 }
9989 }
9990 }
9991 }
9992 }
9993 }
9994 }
9995
9996 // Clean up any connections this application has to other services.
9997 if (app.connections.size() > 0) {
9998 Iterator<ConnectionRecord> it = app.connections.iterator();
9999 while (it.hasNext()) {
10000 ConnectionRecord r = it.next();
10001 removeConnectionLocked(r, app, null);
10002 }
10003 }
10004 app.connections.clear();
10005
10006 if (app.services.size() != 0) {
10007 // Any services running in the application need to be placed
10008 // back in the pending list.
10009 Iterator it = app.services.iterator();
10010 while (it.hasNext()) {
10011 ServiceRecord sr = (ServiceRecord)it.next();
10012 synchronized (sr.stats.getBatteryStats()) {
10013 sr.stats.stopLaunchedLocked();
10014 }
10015 sr.app = null;
10016 sr.executeNesting = 0;
10017 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010018
10019 boolean hasClients = sr.bindings.size() > 0;
10020 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010021 Iterator<IntentBindRecord> bindings
10022 = sr.bindings.values().iterator();
10023 while (bindings.hasNext()) {
10024 IntentBindRecord b = bindings.next();
10025 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
10026 + ": shouldUnbind=" + b.hasBound);
10027 b.binder = null;
10028 b.requested = b.received = b.hasBound = false;
10029 }
10030 }
10031
10032 if (sr.crashCount >= 2) {
10033 Log.w(TAG, "Service crashed " + sr.crashCount
10034 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010035 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010036 sr.crashCount, sr.shortName, app.pid);
10037 bringDownServiceLocked(sr, true);
10038 } else if (!allowRestart) {
10039 bringDownServiceLocked(sr, true);
10040 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010041 boolean canceled = scheduleServiceRestartLocked(sr, true);
10042
10043 // Should the service remain running? Note that in the
10044 // extreme case of so many attempts to deliver a command
10045 // that it failed, that we also will stop it here.
10046 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10047 if (sr.pendingStarts.size() == 0) {
10048 sr.startRequested = false;
10049 if (!hasClients) {
10050 // Whoops, no reason to restart!
10051 bringDownServiceLocked(sr, true);
10052 }
10053 }
10054 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010055 }
10056 }
10057
10058 if (!allowRestart) {
10059 app.services.clear();
10060 }
10061 }
10062
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010063 // Make sure we have no more records on the stopping list.
10064 int i = mStoppingServices.size();
10065 while (i > 0) {
10066 i--;
10067 ServiceRecord sr = mStoppingServices.get(i);
10068 if (sr.app == app) {
10069 mStoppingServices.remove(i);
10070 }
10071 }
10072
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010073 app.executingServices.clear();
10074 }
10075
10076 private final void removeDyingProviderLocked(ProcessRecord proc,
10077 ContentProviderRecord cpr) {
10078 synchronized (cpr) {
10079 cpr.launchingApp = null;
10080 cpr.notifyAll();
10081 }
10082
10083 mProvidersByClass.remove(cpr.info.name);
10084 String names[] = cpr.info.authority.split(";");
10085 for (int j = 0; j < names.length; j++) {
10086 mProvidersByName.remove(names[j]);
10087 }
10088
10089 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10090 while (cit.hasNext()) {
10091 ProcessRecord capp = cit.next();
10092 if (!capp.persistent && capp.thread != null
10093 && capp.pid != 0
10094 && capp.pid != MY_PID) {
10095 Log.i(TAG, "Killing app " + capp.processName
10096 + " (pid " + capp.pid
10097 + ") because provider " + cpr.info.name
10098 + " is in dying process " + proc.processName);
10099 Process.killProcess(capp.pid);
10100 }
10101 }
10102
10103 mLaunchingProviders.remove(cpr);
10104 }
10105
10106 /**
10107 * Main code for cleaning up a process when it has gone away. This is
10108 * called both as a result of the process dying, or directly when stopping
10109 * a process when running in single process mode.
10110 */
10111 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10112 boolean restarting, int index) {
10113 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010114 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010115 }
10116
Dianne Hackborn36124872009-10-08 16:22:03 -070010117 mProcessesToGc.remove(app);
10118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010119 // Dismiss any open dialogs.
10120 if (app.crashDialog != null) {
10121 app.crashDialog.dismiss();
10122 app.crashDialog = null;
10123 }
10124 if (app.anrDialog != null) {
10125 app.anrDialog.dismiss();
10126 app.anrDialog = null;
10127 }
10128 if (app.waitDialog != null) {
10129 app.waitDialog.dismiss();
10130 app.waitDialog = null;
10131 }
10132
10133 app.crashing = false;
10134 app.notResponding = false;
10135
10136 app.resetPackageList();
10137 app.thread = null;
10138 app.forcingToForeground = null;
10139 app.foregroundServices = false;
10140
10141 killServicesLocked(app, true);
10142
10143 boolean restart = false;
10144
10145 int NL = mLaunchingProviders.size();
10146
10147 // Remove published content providers.
10148 if (!app.pubProviders.isEmpty()) {
10149 Iterator it = app.pubProviders.values().iterator();
10150 while (it.hasNext()) {
10151 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10152 cpr.provider = null;
10153 cpr.app = null;
10154
10155 // See if someone is waiting for this provider... in which
10156 // case we don't remove it, but just let it restart.
10157 int i = 0;
10158 if (!app.bad) {
10159 for (; i<NL; i++) {
10160 if (mLaunchingProviders.get(i) == cpr) {
10161 restart = true;
10162 break;
10163 }
10164 }
10165 } else {
10166 i = NL;
10167 }
10168
10169 if (i >= NL) {
10170 removeDyingProviderLocked(app, cpr);
10171 NL = mLaunchingProviders.size();
10172 }
10173 }
10174 app.pubProviders.clear();
10175 }
10176
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010177 // Take care of any launching providers waiting for this process.
10178 if (checkAppInLaunchingProvidersLocked(app, false)) {
10179 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010180 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010182 // Unregister from connected content providers.
10183 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010184 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010185 while (it.hasNext()) {
10186 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10187 cpr.clients.remove(app);
10188 }
10189 app.conProviders.clear();
10190 }
10191
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010192 // At this point there may be remaining entries in mLaunchingProviders
10193 // where we were the only one waiting, so they are no longer of use.
10194 // Look for these and clean up if found.
10195 // XXX Commented out for now. Trying to figure out a way to reproduce
10196 // the actual situation to identify what is actually going on.
10197 if (false) {
10198 for (int i=0; i<NL; i++) {
10199 ContentProviderRecord cpr = (ContentProviderRecord)
10200 mLaunchingProviders.get(i);
10201 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10202 synchronized (cpr) {
10203 cpr.launchingApp = null;
10204 cpr.notifyAll();
10205 }
10206 }
10207 }
10208 }
10209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010210 skipCurrentReceiverLocked(app);
10211
10212 // Unregister any receivers.
10213 if (app.receivers.size() > 0) {
10214 Iterator<ReceiverList> it = app.receivers.iterator();
10215 while (it.hasNext()) {
10216 removeReceiverLocked(it.next());
10217 }
10218 app.receivers.clear();
10219 }
10220
Christopher Tate181fafa2009-05-14 11:12:14 -070010221 // If the app is undergoing backup, tell the backup manager about it
10222 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10223 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10224 try {
10225 IBackupManager bm = IBackupManager.Stub.asInterface(
10226 ServiceManager.getService(Context.BACKUP_SERVICE));
10227 bm.agentDisconnected(app.info.packageName);
10228 } catch (RemoteException e) {
10229 // can't happen; backup manager is local
10230 }
10231 }
10232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010233 // If the caller is restarting this app, then leave it in its
10234 // current lists and let the caller take care of it.
10235 if (restarting) {
10236 return;
10237 }
10238
10239 if (!app.persistent) {
10240 if (DEBUG_PROCESSES) Log.v(TAG,
10241 "Removing non-persistent process during cleanup: " + app);
10242 mProcessNames.remove(app.processName, app.info.uid);
10243 } else if (!app.removed) {
10244 // This app is persistent, so we need to keep its record around.
10245 // If it is not already on the pending app list, add it there
10246 // and start a new process for it.
10247 app.thread = null;
10248 app.forcingToForeground = null;
10249 app.foregroundServices = false;
10250 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10251 mPersistentStartingProcesses.add(app);
10252 restart = true;
10253 }
10254 }
10255 mProcessesOnHold.remove(app);
10256
The Android Open Source Project4df24232009-03-05 14:34:35 -080010257 if (app == mHomeProcess) {
10258 mHomeProcess = null;
10259 }
10260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010261 if (restart) {
10262 // We have components that still need to be running in the
10263 // process, so re-launch it.
10264 mProcessNames.put(app.processName, app.info.uid, app);
10265 startProcessLocked(app, "restart", app.processName);
10266 } else if (app.pid > 0 && app.pid != MY_PID) {
10267 // Goodbye!
10268 synchronized (mPidsSelfLocked) {
10269 mPidsSelfLocked.remove(app.pid);
10270 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10271 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010272 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010273 }
10274 }
10275
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010276 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10277 // Look through the content providers we are waiting to have launched,
10278 // and if any run in this process then either schedule a restart of
10279 // the process or kill the client waiting for it if this process has
10280 // gone bad.
10281 int NL = mLaunchingProviders.size();
10282 boolean restart = false;
10283 for (int i=0; i<NL; i++) {
10284 ContentProviderRecord cpr = (ContentProviderRecord)
10285 mLaunchingProviders.get(i);
10286 if (cpr.launchingApp == app) {
10287 if (!alwaysBad && !app.bad) {
10288 restart = true;
10289 } else {
10290 removeDyingProviderLocked(app, cpr);
10291 NL = mLaunchingProviders.size();
10292 }
10293 }
10294 }
10295 return restart;
10296 }
10297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010298 // =========================================================
10299 // SERVICES
10300 // =========================================================
10301
10302 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10303 ActivityManager.RunningServiceInfo info =
10304 new ActivityManager.RunningServiceInfo();
10305 info.service = r.name;
10306 if (r.app != null) {
10307 info.pid = r.app.pid;
10308 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010309 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010310 info.process = r.processName;
10311 info.foreground = r.isForeground;
10312 info.activeSince = r.createTime;
10313 info.started = r.startRequested;
10314 info.clientCount = r.connections.size();
10315 info.crashCount = r.crashCount;
10316 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010317 if (r.isForeground) {
10318 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10319 }
10320 if (r.startRequested) {
10321 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10322 }
10323 if (r.app != null && r.app.pid == Process.myPid()) {
10324 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10325 }
10326 if (r.app != null && r.app.persistent) {
10327 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10328 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010329 for (ConnectionRecord conn : r.connections.values()) {
10330 if (conn.clientLabel != 0) {
10331 info.clientPackage = conn.binding.client.info.packageName;
10332 info.clientLabel = conn.clientLabel;
10333 break;
10334 }
10335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010336 return info;
10337 }
10338
10339 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10340 int flags) {
10341 synchronized (this) {
10342 ArrayList<ActivityManager.RunningServiceInfo> res
10343 = new ArrayList<ActivityManager.RunningServiceInfo>();
10344
10345 if (mServices.size() > 0) {
10346 Iterator<ServiceRecord> it = mServices.values().iterator();
10347 while (it.hasNext() && res.size() < maxNum) {
10348 res.add(makeRunningServiceInfoLocked(it.next()));
10349 }
10350 }
10351
10352 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10353 ServiceRecord r = mRestartingServices.get(i);
10354 ActivityManager.RunningServiceInfo info =
10355 makeRunningServiceInfoLocked(r);
10356 info.restarting = r.nextRestartTime;
10357 res.add(info);
10358 }
10359
10360 return res;
10361 }
10362 }
10363
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010364 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10365 synchronized (this) {
10366 ServiceRecord r = mServices.get(name);
10367 if (r != null) {
10368 for (ConnectionRecord conn : r.connections.values()) {
10369 if (conn.clientIntent != null) {
10370 return conn.clientIntent;
10371 }
10372 }
10373 }
10374 }
10375 return null;
10376 }
10377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010378 private final ServiceRecord findServiceLocked(ComponentName name,
10379 IBinder token) {
10380 ServiceRecord r = mServices.get(name);
10381 return r == token ? r : null;
10382 }
10383
10384 private final class ServiceLookupResult {
10385 final ServiceRecord record;
10386 final String permission;
10387
10388 ServiceLookupResult(ServiceRecord _record, String _permission) {
10389 record = _record;
10390 permission = _permission;
10391 }
10392 };
10393
10394 private ServiceLookupResult findServiceLocked(Intent service,
10395 String resolvedType) {
10396 ServiceRecord r = null;
10397 if (service.getComponent() != null) {
10398 r = mServices.get(service.getComponent());
10399 }
10400 if (r == null) {
10401 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10402 r = mServicesByIntent.get(filter);
10403 }
10404
10405 if (r == null) {
10406 try {
10407 ResolveInfo rInfo =
10408 ActivityThread.getPackageManager().resolveService(
10409 service, resolvedType, 0);
10410 ServiceInfo sInfo =
10411 rInfo != null ? rInfo.serviceInfo : null;
10412 if (sInfo == null) {
10413 return null;
10414 }
10415
10416 ComponentName name = new ComponentName(
10417 sInfo.applicationInfo.packageName, sInfo.name);
10418 r = mServices.get(name);
10419 } catch (RemoteException ex) {
10420 // pm is in same process, this will never happen.
10421 }
10422 }
10423 if (r != null) {
10424 int callingPid = Binder.getCallingPid();
10425 int callingUid = Binder.getCallingUid();
10426 if (checkComponentPermission(r.permission,
10427 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10428 != PackageManager.PERMISSION_GRANTED) {
10429 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10430 + " from pid=" + callingPid
10431 + ", uid=" + callingUid
10432 + " requires " + r.permission);
10433 return new ServiceLookupResult(null, r.permission);
10434 }
10435 return new ServiceLookupResult(r, null);
10436 }
10437 return null;
10438 }
10439
10440 private class ServiceRestarter implements Runnable {
10441 private ServiceRecord mService;
10442
10443 void setService(ServiceRecord service) {
10444 mService = service;
10445 }
10446
10447 public void run() {
10448 synchronized(ActivityManagerService.this) {
10449 performServiceRestartLocked(mService);
10450 }
10451 }
10452 }
10453
10454 private ServiceLookupResult retrieveServiceLocked(Intent service,
10455 String resolvedType, int callingPid, int callingUid) {
10456 ServiceRecord r = null;
10457 if (service.getComponent() != null) {
10458 r = mServices.get(service.getComponent());
10459 }
10460 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10461 r = mServicesByIntent.get(filter);
10462 if (r == null) {
10463 try {
10464 ResolveInfo rInfo =
10465 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010466 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010467 ServiceInfo sInfo =
10468 rInfo != null ? rInfo.serviceInfo : null;
10469 if (sInfo == null) {
10470 Log.w(TAG, "Unable to start service " + service +
10471 ": not found");
10472 return null;
10473 }
10474
10475 ComponentName name = new ComponentName(
10476 sInfo.applicationInfo.packageName, sInfo.name);
10477 r = mServices.get(name);
10478 if (r == null) {
10479 filter = new Intent.FilterComparison(service.cloneFilter());
10480 ServiceRestarter res = new ServiceRestarter();
10481 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10482 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10483 synchronized (stats) {
10484 ss = stats.getServiceStatsLocked(
10485 sInfo.applicationInfo.uid, sInfo.packageName,
10486 sInfo.name);
10487 }
10488 r = new ServiceRecord(ss, name, filter, sInfo, res);
10489 res.setService(r);
10490 mServices.put(name, r);
10491 mServicesByIntent.put(filter, r);
10492
10493 // Make sure this component isn't in the pending list.
10494 int N = mPendingServices.size();
10495 for (int i=0; i<N; i++) {
10496 ServiceRecord pr = mPendingServices.get(i);
10497 if (pr.name.equals(name)) {
10498 mPendingServices.remove(i);
10499 i--;
10500 N--;
10501 }
10502 }
10503 }
10504 } catch (RemoteException ex) {
10505 // pm is in same process, this will never happen.
10506 }
10507 }
10508 if (r != null) {
10509 if (checkComponentPermission(r.permission,
10510 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10511 != PackageManager.PERMISSION_GRANTED) {
10512 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10513 + " from pid=" + Binder.getCallingPid()
10514 + ", uid=" + Binder.getCallingUid()
10515 + " requires " + r.permission);
10516 return new ServiceLookupResult(null, r.permission);
10517 }
10518 return new ServiceLookupResult(r, null);
10519 }
10520 return null;
10521 }
10522
10523 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10524 long now = SystemClock.uptimeMillis();
10525 if (r.executeNesting == 0 && r.app != null) {
10526 if (r.app.executingServices.size() == 0) {
10527 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10528 msg.obj = r.app;
10529 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10530 }
10531 r.app.executingServices.add(r);
10532 }
10533 r.executeNesting++;
10534 r.executingStart = now;
10535 }
10536
10537 private final void sendServiceArgsLocked(ServiceRecord r,
10538 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010539 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010540 if (N == 0) {
10541 return;
10542 }
10543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010544 int i = 0;
10545 while (i < N) {
10546 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010547 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010548 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010549 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010550 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010551 // If somehow we got a dummy start at the front, then
10552 // just drop it here.
10553 i++;
10554 continue;
10555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010556 bumpServiceExecutingLocked(r);
10557 if (!oomAdjusted) {
10558 oomAdjusted = true;
10559 updateOomAdjLocked(r.app);
10560 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010561 int flags = 0;
10562 if (si.deliveryCount > 0) {
10563 flags |= Service.START_FLAG_RETRY;
10564 }
10565 if (si.doneExecutingCount > 0) {
10566 flags |= Service.START_FLAG_REDELIVERY;
10567 }
10568 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10569 si.deliveredTime = SystemClock.uptimeMillis();
10570 r.deliveredStarts.add(si);
10571 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010572 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010573 } catch (RemoteException e) {
10574 // Remote process gone... we'll let the normal cleanup take
10575 // care of this.
10576 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010577 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010578 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010579 break;
10580 }
10581 }
10582 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010583 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010584 } else {
10585 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010586 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010587 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010588 }
10589 }
10590 }
10591
10592 private final boolean requestServiceBindingLocked(ServiceRecord r,
10593 IntentBindRecord i, boolean rebind) {
10594 if (r.app == null || r.app.thread == null) {
10595 // If service is not currently running, can't yet bind.
10596 return false;
10597 }
10598 if ((!i.requested || rebind) && i.apps.size() > 0) {
10599 try {
10600 bumpServiceExecutingLocked(r);
10601 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10602 + ": shouldUnbind=" + i.hasBound);
10603 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10604 if (!rebind) {
10605 i.requested = true;
10606 }
10607 i.hasBound = true;
10608 i.doRebind = false;
10609 } catch (RemoteException e) {
10610 return false;
10611 }
10612 }
10613 return true;
10614 }
10615
10616 private final void requestServiceBindingsLocked(ServiceRecord r) {
10617 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10618 while (bindings.hasNext()) {
10619 IntentBindRecord i = bindings.next();
10620 if (!requestServiceBindingLocked(r, i, false)) {
10621 break;
10622 }
10623 }
10624 }
10625
10626 private final void realStartServiceLocked(ServiceRecord r,
10627 ProcessRecord app) throws RemoteException {
10628 if (app.thread == null) {
10629 throw new RemoteException();
10630 }
10631
10632 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010633 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010634
10635 app.services.add(r);
10636 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010637 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010638
10639 boolean created = false;
10640 try {
10641 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10642 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010643 mStringBuilder.setLength(0);
10644 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010645 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010646 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010647 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010648 synchronized (r.stats.getBatteryStats()) {
10649 r.stats.startLaunchedLocked();
10650 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010651 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010652 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010653 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010654 created = true;
10655 } finally {
10656 if (!created) {
10657 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010658 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010659 }
10660 }
10661
10662 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010663
10664 // If the service is in the started state, and there are no
10665 // pending arguments, then fake up one so its onStartCommand() will
10666 // be called.
10667 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10668 r.lastStartId++;
10669 if (r.lastStartId < 1) {
10670 r.lastStartId = 1;
10671 }
10672 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10673 }
10674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010675 sendServiceArgsLocked(r, true);
10676 }
10677
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010678 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10679 boolean allowCancel) {
10680 boolean canceled = false;
10681
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010682 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010683 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010684 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010685
10686 // Any delivered but not yet finished starts should be put back
10687 // on the pending list.
10688 final int N = r.deliveredStarts.size();
10689 if (N > 0) {
10690 for (int i=N-1; i>=0; i--) {
10691 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10692 if (si.intent == null) {
10693 // We'll generate this again if needed.
10694 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10695 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10696 r.pendingStarts.add(0, si);
10697 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10698 dur *= 2;
10699 if (minDuration < dur) minDuration = dur;
10700 if (resetTime < dur) resetTime = dur;
10701 } else {
10702 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10703 + r.name);
10704 canceled = true;
10705 }
10706 }
10707 r.deliveredStarts.clear();
10708 }
10709
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010710 r.totalRestartCount++;
10711 if (r.restartDelay == 0) {
10712 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010713 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010714 } else {
10715 // If it has been a "reasonably long time" since the service
10716 // was started, then reset our restart duration back to
10717 // the beginning, so we don't infinitely increase the duration
10718 // on a service that just occasionally gets killed (which is
10719 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010720 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010721 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010722 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010723 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010724 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010725 if (r.restartDelay < minDuration) {
10726 r.restartDelay = minDuration;
10727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010728 }
10729 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010730
10731 r.nextRestartTime = now + r.restartDelay;
10732
10733 // Make sure that we don't end up restarting a bunch of services
10734 // all at the same time.
10735 boolean repeat;
10736 do {
10737 repeat = false;
10738 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10739 ServiceRecord r2 = mRestartingServices.get(i);
10740 if (r2 != r && r.nextRestartTime
10741 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10742 && r.nextRestartTime
10743 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10744 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10745 r.restartDelay = r.nextRestartTime - now;
10746 repeat = true;
10747 break;
10748 }
10749 }
10750 } while (repeat);
10751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010752 if (!mRestartingServices.contains(r)) {
10753 mRestartingServices.add(r);
10754 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010755
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010756 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010758 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010759 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010760 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10761 Log.w(TAG, "Scheduling restart of crashed service "
10762 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010763 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010764 r.shortName, r.restartDelay);
10765
10766 Message msg = Message.obtain();
10767 msg.what = SERVICE_ERROR_MSG;
10768 msg.obj = r;
10769 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010770
10771 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010772 }
10773
10774 final void performServiceRestartLocked(ServiceRecord r) {
10775 if (!mRestartingServices.contains(r)) {
10776 return;
10777 }
10778 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10779 }
10780
10781 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10782 if (r.restartDelay == 0) {
10783 return false;
10784 }
10785 r.resetRestartCounter();
10786 mRestartingServices.remove(r);
10787 mHandler.removeCallbacks(r.restarter);
10788 return true;
10789 }
10790
10791 private final boolean bringUpServiceLocked(ServiceRecord r,
10792 int intentFlags, boolean whileRestarting) {
10793 //Log.i(TAG, "Bring up service:");
10794 //r.dump(" ");
10795
Dianne Hackborn36124872009-10-08 16:22:03 -070010796 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010797 sendServiceArgsLocked(r, false);
10798 return true;
10799 }
10800
10801 if (!whileRestarting && r.restartDelay > 0) {
10802 // If waiting for a restart, then do nothing.
10803 return true;
10804 }
10805
10806 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10807 + " " + r.intent);
10808
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010809 // We are now bringing the service up, so no longer in the
10810 // restarting state.
10811 mRestartingServices.remove(r);
10812
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010813 final String appName = r.processName;
10814 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10815 if (app != null && app.thread != null) {
10816 try {
10817 realStartServiceLocked(r, app);
10818 return true;
10819 } catch (RemoteException e) {
10820 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10821 }
10822
10823 // If a dead object exception was thrown -- fall through to
10824 // restart the application.
10825 }
10826
Dianne Hackborn36124872009-10-08 16:22:03 -070010827 // Not running -- get it started, and enqueue this service record
10828 // to be executed when the app comes up.
10829 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10830 "service", r.name, false) == null) {
10831 Log.w(TAG, "Unable to launch app "
10832 + r.appInfo.packageName + "/"
10833 + r.appInfo.uid + " for service "
10834 + r.intent.getIntent() + ": process is bad");
10835 bringDownServiceLocked(r, true);
10836 return false;
10837 }
10838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010839 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010840 mPendingServices.add(r);
10841 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010843 return true;
10844 }
10845
10846 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10847 //Log.i(TAG, "Bring down service:");
10848 //r.dump(" ");
10849
10850 // Does it still need to run?
10851 if (!force && r.startRequested) {
10852 return;
10853 }
10854 if (r.connections.size() > 0) {
10855 if (!force) {
10856 // XXX should probably keep a count of the number of auto-create
10857 // connections directly in the service.
10858 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10859 while (it.hasNext()) {
10860 ConnectionRecord cr = it.next();
10861 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10862 return;
10863 }
10864 }
10865 }
10866
10867 // Report to all of the connections that the service is no longer
10868 // available.
10869 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10870 while (it.hasNext()) {
10871 ConnectionRecord c = it.next();
10872 try {
10873 // todo: shouldn't be a synchronous call!
10874 c.conn.connected(r.name, null);
10875 } catch (Exception e) {
10876 Log.w(TAG, "Failure disconnecting service " + r.name +
10877 " to connection " + c.conn.asBinder() +
10878 " (in " + c.binding.client.processName + ")", e);
10879 }
10880 }
10881 }
10882
10883 // Tell the service that it has been unbound.
10884 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10885 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10886 while (it.hasNext()) {
10887 IntentBindRecord ibr = it.next();
10888 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10889 + ": hasBound=" + ibr.hasBound);
10890 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10891 try {
10892 bumpServiceExecutingLocked(r);
10893 updateOomAdjLocked(r.app);
10894 ibr.hasBound = false;
10895 r.app.thread.scheduleUnbindService(r,
10896 ibr.intent.getIntent());
10897 } catch (Exception e) {
10898 Log.w(TAG, "Exception when unbinding service "
10899 + r.shortName, e);
10900 serviceDoneExecutingLocked(r, true);
10901 }
10902 }
10903 }
10904 }
10905
10906 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10907 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010908 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010909 System.identityHashCode(r), r.shortName,
10910 (r.app != null) ? r.app.pid : -1);
10911
10912 mServices.remove(r.name);
10913 mServicesByIntent.remove(r.intent);
10914 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10915 r.totalRestartCount = 0;
10916 unscheduleServiceRestartLocked(r);
10917
10918 // Also make sure it is not on the pending list.
10919 int N = mPendingServices.size();
10920 for (int i=0; i<N; i++) {
10921 if (mPendingServices.get(i) == r) {
10922 mPendingServices.remove(i);
10923 if (DEBUG_SERVICE) Log.v(
10924 TAG, "Removed pending service: " + r.shortName);
10925 i--;
10926 N--;
10927 }
10928 }
10929
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010930 r.cancelNotification();
10931 r.isForeground = false;
10932 r.foregroundId = 0;
10933 r.foregroundNoti = null;
10934
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010935 // Clear start entries.
10936 r.deliveredStarts.clear();
10937 r.pendingStarts.clear();
10938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010939 if (r.app != null) {
10940 synchronized (r.stats.getBatteryStats()) {
10941 r.stats.stopLaunchedLocked();
10942 }
10943 r.app.services.remove(r);
10944 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010945 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010946 if (DEBUG_SERVICE) Log.v(TAG,
10947 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010948 bumpServiceExecutingLocked(r);
10949 mStoppingServices.add(r);
10950 updateOomAdjLocked(r.app);
10951 r.app.thread.scheduleStopService(r);
10952 } catch (Exception e) {
10953 Log.w(TAG, "Exception when stopping service "
10954 + r.shortName, e);
10955 serviceDoneExecutingLocked(r, true);
10956 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010957 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010958 } else {
10959 if (DEBUG_SERVICE) Log.v(
10960 TAG, "Removed service that has no process: " + r.shortName);
10961 }
10962 } else {
10963 if (DEBUG_SERVICE) Log.v(
10964 TAG, "Removed service that is not running: " + r.shortName);
10965 }
10966 }
10967
10968 ComponentName startServiceLocked(IApplicationThread caller,
10969 Intent service, String resolvedType,
10970 int callingPid, int callingUid) {
10971 synchronized(this) {
10972 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10973 + " type=" + resolvedType + " args=" + service.getExtras());
10974
10975 if (caller != null) {
10976 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10977 if (callerApp == null) {
10978 throw new SecurityException(
10979 "Unable to find app for caller " + caller
10980 + " (pid=" + Binder.getCallingPid()
10981 + ") when starting service " + service);
10982 }
10983 }
10984
10985 ServiceLookupResult res =
10986 retrieveServiceLocked(service, resolvedType,
10987 callingPid, callingUid);
10988 if (res == null) {
10989 return null;
10990 }
10991 if (res.record == null) {
10992 return new ComponentName("!", res.permission != null
10993 ? res.permission : "private to package");
10994 }
10995 ServiceRecord r = res.record;
10996 if (unscheduleServiceRestartLocked(r)) {
10997 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10998 + r.shortName);
10999 }
11000 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011001 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011002 r.lastStartId++;
11003 if (r.lastStartId < 1) {
11004 r.lastStartId = 1;
11005 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011006 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011007 r.lastActivity = SystemClock.uptimeMillis();
11008 synchronized (r.stats.getBatteryStats()) {
11009 r.stats.startRunningLocked();
11010 }
11011 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
11012 return new ComponentName("!", "Service process is bad");
11013 }
11014 return r.name;
11015 }
11016 }
11017
11018 public ComponentName startService(IApplicationThread caller, Intent service,
11019 String resolvedType) {
11020 // Refuse possible leaked file descriptors
11021 if (service != null && service.hasFileDescriptors() == true) {
11022 throw new IllegalArgumentException("File descriptors passed in Intent");
11023 }
11024
11025 synchronized(this) {
11026 final int callingPid = Binder.getCallingPid();
11027 final int callingUid = Binder.getCallingUid();
11028 final long origId = Binder.clearCallingIdentity();
11029 ComponentName res = startServiceLocked(caller, service,
11030 resolvedType, callingPid, callingUid);
11031 Binder.restoreCallingIdentity(origId);
11032 return res;
11033 }
11034 }
11035
11036 ComponentName startServiceInPackage(int uid,
11037 Intent service, String resolvedType) {
11038 synchronized(this) {
11039 final long origId = Binder.clearCallingIdentity();
11040 ComponentName res = startServiceLocked(null, service,
11041 resolvedType, -1, uid);
11042 Binder.restoreCallingIdentity(origId);
11043 return res;
11044 }
11045 }
11046
11047 public int stopService(IApplicationThread caller, Intent service,
11048 String resolvedType) {
11049 // Refuse possible leaked file descriptors
11050 if (service != null && service.hasFileDescriptors() == true) {
11051 throw new IllegalArgumentException("File descriptors passed in Intent");
11052 }
11053
11054 synchronized(this) {
11055 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11056 + " type=" + resolvedType);
11057
11058 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11059 if (caller != null && callerApp == null) {
11060 throw new SecurityException(
11061 "Unable to find app for caller " + caller
11062 + " (pid=" + Binder.getCallingPid()
11063 + ") when stopping service " + service);
11064 }
11065
11066 // If this service is active, make sure it is stopped.
11067 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11068 if (r != null) {
11069 if (r.record != null) {
11070 synchronized (r.record.stats.getBatteryStats()) {
11071 r.record.stats.stopRunningLocked();
11072 }
11073 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011074 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011075 final long origId = Binder.clearCallingIdentity();
11076 bringDownServiceLocked(r.record, false);
11077 Binder.restoreCallingIdentity(origId);
11078 return 1;
11079 }
11080 return -1;
11081 }
11082 }
11083
11084 return 0;
11085 }
11086
11087 public IBinder peekService(Intent service, String resolvedType) {
11088 // Refuse possible leaked file descriptors
11089 if (service != null && service.hasFileDescriptors() == true) {
11090 throw new IllegalArgumentException("File descriptors passed in Intent");
11091 }
11092
11093 IBinder ret = null;
11094
11095 synchronized(this) {
11096 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11097
11098 if (r != null) {
11099 // r.record is null if findServiceLocked() failed the caller permission check
11100 if (r.record == null) {
11101 throw new SecurityException(
11102 "Permission Denial: Accessing service " + r.record.name
11103 + " from pid=" + Binder.getCallingPid()
11104 + ", uid=" + Binder.getCallingUid()
11105 + " requires " + r.permission);
11106 }
11107 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11108 if (ib != null) {
11109 ret = ib.binder;
11110 }
11111 }
11112 }
11113
11114 return ret;
11115 }
11116
11117 public boolean stopServiceToken(ComponentName className, IBinder token,
11118 int startId) {
11119 synchronized(this) {
11120 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11121 + " " + token + " startId=" + startId);
11122 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011123 if (r != null) {
11124 if (startId >= 0) {
11125 // Asked to only stop if done with all work. Note that
11126 // to avoid leaks, we will take this as dropping all
11127 // start items up to and including this one.
11128 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11129 if (si != null) {
11130 while (r.deliveredStarts.size() > 0) {
11131 if (r.deliveredStarts.remove(0) == si) {
11132 break;
11133 }
11134 }
11135 }
11136
11137 if (r.lastStartId != startId) {
11138 return false;
11139 }
11140
11141 if (r.deliveredStarts.size() > 0) {
11142 Log.w(TAG, "stopServiceToken startId " + startId
11143 + " is last, but have " + r.deliveredStarts.size()
11144 + " remaining args");
11145 }
11146 }
11147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011148 synchronized (r.stats.getBatteryStats()) {
11149 r.stats.stopRunningLocked();
11150 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011151 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011152 }
11153 final long origId = Binder.clearCallingIdentity();
11154 bringDownServiceLocked(r, false);
11155 Binder.restoreCallingIdentity(origId);
11156 return true;
11157 }
11158 }
11159 return false;
11160 }
11161
11162 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011163 int id, Notification notification, boolean removeNotification) {
11164 final long origId = Binder.clearCallingIdentity();
11165 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011166 synchronized(this) {
11167 ServiceRecord r = findServiceLocked(className, token);
11168 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011169 if (id != 0) {
11170 if (notification == null) {
11171 throw new IllegalArgumentException("null notification");
11172 }
11173 if (r.foregroundId != id) {
11174 r.cancelNotification();
11175 r.foregroundId = id;
11176 }
11177 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11178 r.foregroundNoti = notification;
11179 r.isForeground = true;
11180 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011181 if (r.app != null) {
11182 updateServiceForegroundLocked(r.app, true);
11183 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011184 } else {
11185 if (r.isForeground) {
11186 r.isForeground = false;
11187 if (r.app != null) {
11188 updateServiceForegroundLocked(r.app, true);
11189 }
11190 }
11191 if (removeNotification) {
11192 r.cancelNotification();
11193 r.foregroundId = 0;
11194 r.foregroundNoti = null;
11195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011196 }
11197 }
11198 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011199 } finally {
11200 Binder.restoreCallingIdentity(origId);
11201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011202 }
11203
11204 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11205 boolean anyForeground = false;
11206 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11207 if (sr.isForeground) {
11208 anyForeground = true;
11209 break;
11210 }
11211 }
11212 if (anyForeground != proc.foregroundServices) {
11213 proc.foregroundServices = anyForeground;
11214 if (oomAdj) {
11215 updateOomAdjLocked();
11216 }
11217 }
11218 }
11219
11220 public int bindService(IApplicationThread caller, IBinder token,
11221 Intent service, String resolvedType,
11222 IServiceConnection connection, int flags) {
11223 // Refuse possible leaked file descriptors
11224 if (service != null && service.hasFileDescriptors() == true) {
11225 throw new IllegalArgumentException("File descriptors passed in Intent");
11226 }
11227
11228 synchronized(this) {
11229 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11230 + " type=" + resolvedType + " conn=" + connection.asBinder()
11231 + " flags=0x" + Integer.toHexString(flags));
11232 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11233 if (callerApp == null) {
11234 throw new SecurityException(
11235 "Unable to find app for caller " + caller
11236 + " (pid=" + Binder.getCallingPid()
11237 + ") when binding service " + service);
11238 }
11239
11240 HistoryRecord activity = null;
11241 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011242 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011243 if (aindex < 0) {
11244 Log.w(TAG, "Binding with unknown activity: " + token);
11245 return 0;
11246 }
11247 activity = (HistoryRecord)mHistory.get(aindex);
11248 }
11249
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011250 int clientLabel = 0;
11251 PendingIntent clientIntent = null;
11252
11253 if (callerApp.info.uid == Process.SYSTEM_UID) {
11254 // Hacky kind of thing -- allow system stuff to tell us
11255 // what they are, so we can report this elsewhere for
11256 // others to know why certain services are running.
11257 try {
11258 clientIntent = (PendingIntent)service.getParcelableExtra(
11259 Intent.EXTRA_CLIENT_INTENT);
11260 } catch (RuntimeException e) {
11261 }
11262 if (clientIntent != null) {
11263 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11264 if (clientLabel != 0) {
11265 // There are no useful extras in the intent, trash them.
11266 // System code calling with this stuff just needs to know
11267 // this will happen.
11268 service = service.cloneFilter();
11269 }
11270 }
11271 }
11272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011273 ServiceLookupResult res =
11274 retrieveServiceLocked(service, resolvedType,
11275 Binder.getCallingPid(), Binder.getCallingUid());
11276 if (res == null) {
11277 return 0;
11278 }
11279 if (res.record == null) {
11280 return -1;
11281 }
11282 ServiceRecord s = res.record;
11283
11284 final long origId = Binder.clearCallingIdentity();
11285
11286 if (unscheduleServiceRestartLocked(s)) {
11287 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11288 + s.shortName);
11289 }
11290
11291 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11292 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011293 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011294
11295 IBinder binder = connection.asBinder();
11296 s.connections.put(binder, c);
11297 b.connections.add(c);
11298 if (activity != null) {
11299 if (activity.connections == null) {
11300 activity.connections = new HashSet<ConnectionRecord>();
11301 }
11302 activity.connections.add(c);
11303 }
11304 b.client.connections.add(c);
11305 mServiceConnections.put(binder, c);
11306
11307 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11308 s.lastActivity = SystemClock.uptimeMillis();
11309 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11310 return 0;
11311 }
11312 }
11313
11314 if (s.app != null) {
11315 // This could have made the service more important.
11316 updateOomAdjLocked(s.app);
11317 }
11318
11319 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11320 + ": received=" + b.intent.received
11321 + " apps=" + b.intent.apps.size()
11322 + " doRebind=" + b.intent.doRebind);
11323
11324 if (s.app != null && b.intent.received) {
11325 // Service is already running, so we can immediately
11326 // publish the connection.
11327 try {
11328 c.conn.connected(s.name, b.intent.binder);
11329 } catch (Exception e) {
11330 Log.w(TAG, "Failure sending service " + s.shortName
11331 + " to connection " + c.conn.asBinder()
11332 + " (in " + c.binding.client.processName + ")", e);
11333 }
11334
11335 // If this is the first app connected back to this binding,
11336 // and the service had previously asked to be told when
11337 // rebound, then do so.
11338 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11339 requestServiceBindingLocked(s, b.intent, true);
11340 }
11341 } else if (!b.intent.requested) {
11342 requestServiceBindingLocked(s, b.intent, false);
11343 }
11344
11345 Binder.restoreCallingIdentity(origId);
11346 }
11347
11348 return 1;
11349 }
11350
11351 private void removeConnectionLocked(
11352 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11353 IBinder binder = c.conn.asBinder();
11354 AppBindRecord b = c.binding;
11355 ServiceRecord s = b.service;
11356 s.connections.remove(binder);
11357 b.connections.remove(c);
11358 if (c.activity != null && c.activity != skipAct) {
11359 if (c.activity.connections != null) {
11360 c.activity.connections.remove(c);
11361 }
11362 }
11363 if (b.client != skipApp) {
11364 b.client.connections.remove(c);
11365 }
11366 mServiceConnections.remove(binder);
11367
11368 if (b.connections.size() == 0) {
11369 b.intent.apps.remove(b.client);
11370 }
11371
11372 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11373 + ": shouldUnbind=" + b.intent.hasBound);
11374 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11375 && b.intent.hasBound) {
11376 try {
11377 bumpServiceExecutingLocked(s);
11378 updateOomAdjLocked(s.app);
11379 b.intent.hasBound = false;
11380 // Assume the client doesn't want to know about a rebind;
11381 // we will deal with that later if it asks for one.
11382 b.intent.doRebind = false;
11383 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11384 } catch (Exception e) {
11385 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11386 serviceDoneExecutingLocked(s, true);
11387 }
11388 }
11389
11390 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11391 bringDownServiceLocked(s, false);
11392 }
11393 }
11394
11395 public boolean unbindService(IServiceConnection connection) {
11396 synchronized (this) {
11397 IBinder binder = connection.asBinder();
11398 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11399 ConnectionRecord r = mServiceConnections.get(binder);
11400 if (r == null) {
11401 Log.w(TAG, "Unbind failed: could not find connection for "
11402 + connection.asBinder());
11403 return false;
11404 }
11405
11406 final long origId = Binder.clearCallingIdentity();
11407
11408 removeConnectionLocked(r, null, null);
11409
11410 if (r.binding.service.app != null) {
11411 // This could have made the service less important.
11412 updateOomAdjLocked(r.binding.service.app);
11413 }
11414
11415 Binder.restoreCallingIdentity(origId);
11416 }
11417
11418 return true;
11419 }
11420
11421 public void publishService(IBinder token, Intent intent, IBinder service) {
11422 // Refuse possible leaked file descriptors
11423 if (intent != null && intent.hasFileDescriptors() == true) {
11424 throw new IllegalArgumentException("File descriptors passed in Intent");
11425 }
11426
11427 synchronized(this) {
11428 if (!(token instanceof ServiceRecord)) {
11429 throw new IllegalArgumentException("Invalid service token");
11430 }
11431 ServiceRecord r = (ServiceRecord)token;
11432
11433 final long origId = Binder.clearCallingIdentity();
11434
11435 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11436 + " " + intent + ": " + service);
11437 if (r != null) {
11438 Intent.FilterComparison filter
11439 = new Intent.FilterComparison(intent);
11440 IntentBindRecord b = r.bindings.get(filter);
11441 if (b != null && !b.received) {
11442 b.binder = service;
11443 b.requested = true;
11444 b.received = true;
11445 if (r.connections.size() > 0) {
11446 Iterator<ConnectionRecord> it
11447 = r.connections.values().iterator();
11448 while (it.hasNext()) {
11449 ConnectionRecord c = it.next();
11450 if (!filter.equals(c.binding.intent.intent)) {
11451 if (DEBUG_SERVICE) Log.v(
11452 TAG, "Not publishing to: " + c);
11453 if (DEBUG_SERVICE) Log.v(
11454 TAG, "Bound intent: " + c.binding.intent.intent);
11455 if (DEBUG_SERVICE) Log.v(
11456 TAG, "Published intent: " + intent);
11457 continue;
11458 }
11459 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11460 try {
11461 c.conn.connected(r.name, service);
11462 } catch (Exception e) {
11463 Log.w(TAG, "Failure sending service " + r.name +
11464 " to connection " + c.conn.asBinder() +
11465 " (in " + c.binding.client.processName + ")", e);
11466 }
11467 }
11468 }
11469 }
11470
11471 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11472
11473 Binder.restoreCallingIdentity(origId);
11474 }
11475 }
11476 }
11477
11478 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11479 // Refuse possible leaked file descriptors
11480 if (intent != null && intent.hasFileDescriptors() == true) {
11481 throw new IllegalArgumentException("File descriptors passed in Intent");
11482 }
11483
11484 synchronized(this) {
11485 if (!(token instanceof ServiceRecord)) {
11486 throw new IllegalArgumentException("Invalid service token");
11487 }
11488 ServiceRecord r = (ServiceRecord)token;
11489
11490 final long origId = Binder.clearCallingIdentity();
11491
11492 if (r != null) {
11493 Intent.FilterComparison filter
11494 = new Intent.FilterComparison(intent);
11495 IntentBindRecord b = r.bindings.get(filter);
11496 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11497 + " at " + b + ": apps="
11498 + (b != null ? b.apps.size() : 0));
11499 if (b != null) {
11500 if (b.apps.size() > 0) {
11501 // Applications have already bound since the last
11502 // unbind, so just rebind right here.
11503 requestServiceBindingLocked(r, b, true);
11504 } else {
11505 // Note to tell the service the next time there is
11506 // a new client.
11507 b.doRebind = true;
11508 }
11509 }
11510
11511 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11512
11513 Binder.restoreCallingIdentity(origId);
11514 }
11515 }
11516 }
11517
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011518 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011519 synchronized(this) {
11520 if (!(token instanceof ServiceRecord)) {
11521 throw new IllegalArgumentException("Invalid service token");
11522 }
11523 ServiceRecord r = (ServiceRecord)token;
11524 boolean inStopping = mStoppingServices.contains(token);
11525 if (r != null) {
11526 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11527 + ": nesting=" + r.executeNesting
11528 + ", inStopping=" + inStopping);
11529 if (r != token) {
11530 Log.w(TAG, "Done executing service " + r.name
11531 + " with incorrect token: given " + token
11532 + ", expected " + r);
11533 return;
11534 }
11535
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011536 if (type == 1) {
11537 // This is a call from a service start... take care of
11538 // book-keeping.
11539 r.callStart = true;
11540 switch (res) {
11541 case Service.START_STICKY_COMPATIBILITY:
11542 case Service.START_STICKY: {
11543 // We are done with the associated start arguments.
11544 r.findDeliveredStart(startId, true);
11545 // Don't stop if killed.
11546 r.stopIfKilled = false;
11547 break;
11548 }
11549 case Service.START_NOT_STICKY: {
11550 // We are done with the associated start arguments.
11551 r.findDeliveredStart(startId, true);
11552 if (r.lastStartId == startId) {
11553 // There is no more work, and this service
11554 // doesn't want to hang around if killed.
11555 r.stopIfKilled = true;
11556 }
11557 break;
11558 }
11559 case Service.START_REDELIVER_INTENT: {
11560 // We'll keep this item until they explicitly
11561 // call stop for it, but keep track of the fact
11562 // that it was delivered.
11563 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11564 if (si != null) {
11565 si.deliveryCount = 0;
11566 si.doneExecutingCount++;
11567 // Don't stop if killed.
11568 r.stopIfKilled = true;
11569 }
11570 break;
11571 }
11572 default:
11573 throw new IllegalArgumentException(
11574 "Unknown service start result: " + res);
11575 }
11576 if (res == Service.START_STICKY_COMPATIBILITY) {
11577 r.callStart = false;
11578 }
11579 }
11580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011581 final long origId = Binder.clearCallingIdentity();
11582 serviceDoneExecutingLocked(r, inStopping);
11583 Binder.restoreCallingIdentity(origId);
11584 } else {
11585 Log.w(TAG, "Done executing unknown service " + r.name
11586 + " with token " + token);
11587 }
11588 }
11589 }
11590
11591 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11592 r.executeNesting--;
11593 if (r.executeNesting <= 0 && r.app != null) {
11594 r.app.executingServices.remove(r);
11595 if (r.app.executingServices.size() == 0) {
11596 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11597 }
11598 if (inStopping) {
11599 mStoppingServices.remove(r);
11600 }
11601 updateOomAdjLocked(r.app);
11602 }
11603 }
11604
11605 void serviceTimeout(ProcessRecord proc) {
11606 synchronized(this) {
11607 if (proc.executingServices.size() == 0 || proc.thread == null) {
11608 return;
11609 }
11610 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11611 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11612 ServiceRecord timeout = null;
11613 long nextTime = 0;
11614 while (it.hasNext()) {
11615 ServiceRecord sr = it.next();
11616 if (sr.executingStart < maxTime) {
11617 timeout = sr;
11618 break;
11619 }
11620 if (sr.executingStart > nextTime) {
11621 nextTime = sr.executingStart;
11622 }
11623 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011624 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011625 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnorb7f03672009-12-09 16:22:32 -080011626 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011627 } else {
11628 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11629 msg.obj = proc;
11630 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11631 }
11632 }
11633 }
11634
11635 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011636 // BACKUP AND RESTORE
11637 // =========================================================
11638
11639 // Cause the target app to be launched if necessary and its backup agent
11640 // instantiated. The backup agent will invoke backupAgentCreated() on the
11641 // activity manager to announce its creation.
11642 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11643 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11644 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11645
11646 synchronized(this) {
11647 // !!! TODO: currently no check here that we're already bound
11648 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11649 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11650 synchronized (stats) {
11651 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11652 }
11653
11654 BackupRecord r = new BackupRecord(ss, app, backupMode);
11655 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11656 // startProcessLocked() returns existing proc's record if it's already running
11657 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011658 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011659 if (proc == null) {
11660 Log.e(TAG, "Unable to start backup agent process " + r);
11661 return false;
11662 }
11663
11664 r.app = proc;
11665 mBackupTarget = r;
11666 mBackupAppName = app.packageName;
11667
Christopher Tate6fa95972009-06-05 18:43:55 -070011668 // Try not to kill the process during backup
11669 updateOomAdjLocked(proc);
11670
Christopher Tate181fafa2009-05-14 11:12:14 -070011671 // If the process is already attached, schedule the creation of the backup agent now.
11672 // If it is not yet live, this will be done when it attaches to the framework.
11673 if (proc.thread != null) {
11674 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11675 try {
11676 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11677 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011678 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011679 }
11680 } else {
11681 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11682 }
11683 // Invariants: at this point, the target app process exists and the application
11684 // is either already running or in the process of coming up. mBackupTarget and
11685 // mBackupAppName describe the app, so that when it binds back to the AM we
11686 // know that it's scheduled for a backup-agent operation.
11687 }
11688
11689 return true;
11690 }
11691
11692 // A backup agent has just come up
11693 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11694 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11695 + " = " + agent);
11696
11697 synchronized(this) {
11698 if (!agentPackageName.equals(mBackupAppName)) {
11699 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11700 return;
11701 }
11702
Christopher Tate043dadc2009-06-02 16:11:00 -070011703 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011704 try {
11705 IBackupManager bm = IBackupManager.Stub.asInterface(
11706 ServiceManager.getService(Context.BACKUP_SERVICE));
11707 bm.agentConnected(agentPackageName, agent);
11708 } catch (RemoteException e) {
11709 // can't happen; the backup manager service is local
11710 } catch (Exception e) {
11711 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11712 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011713 } finally {
11714 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011715 }
11716 }
11717 }
11718
11719 // done with this agent
11720 public void unbindBackupAgent(ApplicationInfo appInfo) {
11721 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011722 if (appInfo == null) {
11723 Log.w(TAG, "unbind backup agent for null app");
11724 return;
11725 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011726
11727 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011728 if (mBackupAppName == null) {
11729 Log.w(TAG, "Unbinding backup agent with no active backup");
11730 return;
11731 }
11732
Christopher Tate181fafa2009-05-14 11:12:14 -070011733 if (!mBackupAppName.equals(appInfo.packageName)) {
11734 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11735 return;
11736 }
11737
Christopher Tate6fa95972009-06-05 18:43:55 -070011738 ProcessRecord proc = mBackupTarget.app;
11739 mBackupTarget = null;
11740 mBackupAppName = null;
11741
11742 // Not backing this app up any more; reset its OOM adjustment
11743 updateOomAdjLocked(proc);
11744
Christopher Tatec7b31e32009-06-10 15:49:30 -070011745 // If the app crashed during backup, 'thread' will be null here
11746 if (proc.thread != null) {
11747 try {
11748 proc.thread.scheduleDestroyBackupAgent(appInfo);
11749 } catch (Exception e) {
11750 Log.e(TAG, "Exception when unbinding backup agent:");
11751 e.printStackTrace();
11752 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011753 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011754 }
11755 }
11756 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011757 // BROADCASTS
11758 // =========================================================
11759
11760 private final List getStickies(String action, IntentFilter filter,
11761 List cur) {
11762 final ContentResolver resolver = mContext.getContentResolver();
11763 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11764 if (list == null) {
11765 return cur;
11766 }
11767 int N = list.size();
11768 for (int i=0; i<N; i++) {
11769 Intent intent = list.get(i);
11770 if (filter.match(resolver, intent, true, TAG) >= 0) {
11771 if (cur == null) {
11772 cur = new ArrayList<Intent>();
11773 }
11774 cur.add(intent);
11775 }
11776 }
11777 return cur;
11778 }
11779
11780 private final void scheduleBroadcastsLocked() {
11781 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11782 + mBroadcastsScheduled);
11783
11784 if (mBroadcastsScheduled) {
11785 return;
11786 }
11787 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11788 mBroadcastsScheduled = true;
11789 }
11790
11791 public Intent registerReceiver(IApplicationThread caller,
11792 IIntentReceiver receiver, IntentFilter filter, String permission) {
11793 synchronized(this) {
11794 ProcessRecord callerApp = null;
11795 if (caller != null) {
11796 callerApp = getRecordForAppLocked(caller);
11797 if (callerApp == null) {
11798 throw new SecurityException(
11799 "Unable to find app for caller " + caller
11800 + " (pid=" + Binder.getCallingPid()
11801 + ") when registering receiver " + receiver);
11802 }
11803 }
11804
11805 List allSticky = null;
11806
11807 // Look for any matching sticky broadcasts...
11808 Iterator actions = filter.actionsIterator();
11809 if (actions != null) {
11810 while (actions.hasNext()) {
11811 String action = (String)actions.next();
11812 allSticky = getStickies(action, filter, allSticky);
11813 }
11814 } else {
11815 allSticky = getStickies(null, filter, allSticky);
11816 }
11817
11818 // The first sticky in the list is returned directly back to
11819 // the client.
11820 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11821
11822 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11823 + ": " + sticky);
11824
11825 if (receiver == null) {
11826 return sticky;
11827 }
11828
11829 ReceiverList rl
11830 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11831 if (rl == null) {
11832 rl = new ReceiverList(this, callerApp,
11833 Binder.getCallingPid(),
11834 Binder.getCallingUid(), receiver);
11835 if (rl.app != null) {
11836 rl.app.receivers.add(rl);
11837 } else {
11838 try {
11839 receiver.asBinder().linkToDeath(rl, 0);
11840 } catch (RemoteException e) {
11841 return sticky;
11842 }
11843 rl.linkedToDeath = true;
11844 }
11845 mRegisteredReceivers.put(receiver.asBinder(), rl);
11846 }
11847 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11848 rl.add(bf);
11849 if (!bf.debugCheck()) {
11850 Log.w(TAG, "==> For Dynamic broadast");
11851 }
11852 mReceiverResolver.addFilter(bf);
11853
11854 // Enqueue broadcasts for all existing stickies that match
11855 // this filter.
11856 if (allSticky != null) {
11857 ArrayList receivers = new ArrayList();
11858 receivers.add(bf);
11859
11860 int N = allSticky.size();
11861 for (int i=0; i<N; i++) {
11862 Intent intent = (Intent)allSticky.get(i);
11863 BroadcastRecord r = new BroadcastRecord(intent, null,
11864 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011865 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011866 if (mParallelBroadcasts.size() == 0) {
11867 scheduleBroadcastsLocked();
11868 }
11869 mParallelBroadcasts.add(r);
11870 }
11871 }
11872
11873 return sticky;
11874 }
11875 }
11876
11877 public void unregisterReceiver(IIntentReceiver receiver) {
11878 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11879
11880 boolean doNext = false;
11881
11882 synchronized(this) {
11883 ReceiverList rl
11884 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11885 if (rl != null) {
11886 if (rl.curBroadcast != null) {
11887 BroadcastRecord r = rl.curBroadcast;
11888 doNext = finishReceiverLocked(
11889 receiver.asBinder(), r.resultCode, r.resultData,
11890 r.resultExtras, r.resultAbort, true);
11891 }
11892
11893 if (rl.app != null) {
11894 rl.app.receivers.remove(rl);
11895 }
11896 removeReceiverLocked(rl);
11897 if (rl.linkedToDeath) {
11898 rl.linkedToDeath = false;
11899 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11900 }
11901 }
11902 }
11903
11904 if (!doNext) {
11905 return;
11906 }
11907
11908 final long origId = Binder.clearCallingIdentity();
11909 processNextBroadcast(false);
11910 trimApplications();
11911 Binder.restoreCallingIdentity(origId);
11912 }
11913
11914 void removeReceiverLocked(ReceiverList rl) {
11915 mRegisteredReceivers.remove(rl.receiver.asBinder());
11916 int N = rl.size();
11917 for (int i=0; i<N; i++) {
11918 mReceiverResolver.removeFilter(rl.get(i));
11919 }
11920 }
11921
11922 private final int broadcastIntentLocked(ProcessRecord callerApp,
11923 String callerPackage, Intent intent, String resolvedType,
11924 IIntentReceiver resultTo, int resultCode, String resultData,
11925 Bundle map, String requiredPermission,
11926 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11927 intent = new Intent(intent);
11928
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011929 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011930 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11931 + " ordered=" + ordered);
11932 if ((resultTo != null) && !ordered) {
11933 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11934 }
11935
11936 // Handle special intents: if this broadcast is from the package
11937 // manager about a package being removed, we need to remove all of
11938 // its activities from the history stack.
11939 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11940 intent.getAction());
11941 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11942 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11943 || uidRemoved) {
11944 if (checkComponentPermission(
11945 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11946 callingPid, callingUid, -1)
11947 == PackageManager.PERMISSION_GRANTED) {
11948 if (uidRemoved) {
11949 final Bundle intentExtras = intent.getExtras();
11950 final int uid = intentExtras != null
11951 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11952 if (uid >= 0) {
11953 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11954 synchronized (bs) {
11955 bs.removeUidStatsLocked(uid);
11956 }
11957 }
11958 } else {
11959 Uri data = intent.getData();
11960 String ssp;
11961 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11962 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -080011963 forceStopPackageLocked(ssp,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011964 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011965 AttributeCache ac = AttributeCache.instance();
11966 if (ac != null) {
11967 ac.removePackage(ssp);
11968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011969 }
11970 }
11971 }
11972 } else {
11973 String msg = "Permission Denial: " + intent.getAction()
11974 + " broadcast from " + callerPackage + " (pid=" + callingPid
11975 + ", uid=" + callingUid + ")"
11976 + " requires "
11977 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11978 Log.w(TAG, msg);
11979 throw new SecurityException(msg);
11980 }
11981 }
11982
11983 /*
11984 * If this is the time zone changed action, queue up a message that will reset the timezone
11985 * of all currently running processes. This message will get queued up before the broadcast
11986 * happens.
11987 */
11988 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11989 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11990 }
11991
Dianne Hackborn854060af2009-07-09 18:14:31 -070011992 /*
11993 * Prevent non-system code (defined here to be non-persistent
11994 * processes) from sending protected broadcasts.
11995 */
11996 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11997 || callingUid == Process.SHELL_UID || callingUid == 0) {
11998 // Always okay.
11999 } else if (callerApp == null || !callerApp.persistent) {
12000 try {
12001 if (ActivityThread.getPackageManager().isProtectedBroadcast(
12002 intent.getAction())) {
12003 String msg = "Permission Denial: not allowed to send broadcast "
12004 + intent.getAction() + " from pid="
12005 + callingPid + ", uid=" + callingUid;
12006 Log.w(TAG, msg);
12007 throw new SecurityException(msg);
12008 }
12009 } catch (RemoteException e) {
12010 Log.w(TAG, "Remote exception", e);
12011 return BROADCAST_SUCCESS;
12012 }
12013 }
12014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012015 // Add to the sticky list if requested.
12016 if (sticky) {
12017 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
12018 callingPid, callingUid)
12019 != PackageManager.PERMISSION_GRANTED) {
12020 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
12021 + callingPid + ", uid=" + callingUid
12022 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12023 Log.w(TAG, msg);
12024 throw new SecurityException(msg);
12025 }
12026 if (requiredPermission != null) {
12027 Log.w(TAG, "Can't broadcast sticky intent " + intent
12028 + " and enforce permission " + requiredPermission);
12029 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
12030 }
12031 if (intent.getComponent() != null) {
12032 throw new SecurityException(
12033 "Sticky broadcasts can't target a specific component");
12034 }
12035 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12036 if (list == null) {
12037 list = new ArrayList<Intent>();
12038 mStickyBroadcasts.put(intent.getAction(), list);
12039 }
12040 int N = list.size();
12041 int i;
12042 for (i=0; i<N; i++) {
12043 if (intent.filterEquals(list.get(i))) {
12044 // This sticky already exists, replace it.
12045 list.set(i, new Intent(intent));
12046 break;
12047 }
12048 }
12049 if (i >= N) {
12050 list.add(new Intent(intent));
12051 }
12052 }
12053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012054 // Figure out who all will receive this broadcast.
12055 List receivers = null;
12056 List<BroadcastFilter> registeredReceivers = null;
12057 try {
12058 if (intent.getComponent() != null) {
12059 // Broadcast is going to one specific receiver class...
12060 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012061 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012062 if (ai != null) {
12063 receivers = new ArrayList();
12064 ResolveInfo ri = new ResolveInfo();
12065 ri.activityInfo = ai;
12066 receivers.add(ri);
12067 }
12068 } else {
12069 // Need to resolve the intent to interested receivers...
12070 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12071 == 0) {
12072 receivers =
12073 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012074 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012075 }
Mihai Preda074edef2009-05-18 17:13:31 +020012076 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012077 }
12078 } catch (RemoteException ex) {
12079 // pm is in same process, this will never happen.
12080 }
12081
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012082 final boolean replacePending =
12083 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12084
12085 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12086 + " replacePending=" + replacePending);
12087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012088 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12089 if (!ordered && NR > 0) {
12090 // If we are not serializing this broadcast, then send the
12091 // registered receivers separately so they don't wait for the
12092 // components to be launched.
12093 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12094 callerPackage, callingPid, callingUid, requiredPermission,
12095 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012096 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012097 if (DEBUG_BROADCAST) Log.v(
12098 TAG, "Enqueueing parallel broadcast " + r
12099 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012100 boolean replaced = false;
12101 if (replacePending) {
12102 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12103 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12104 if (DEBUG_BROADCAST) Log.v(TAG,
12105 "***** DROPPING PARALLEL: " + intent);
12106 mParallelBroadcasts.set(i, r);
12107 replaced = true;
12108 break;
12109 }
12110 }
12111 }
12112 if (!replaced) {
12113 mParallelBroadcasts.add(r);
12114 scheduleBroadcastsLocked();
12115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012116 registeredReceivers = null;
12117 NR = 0;
12118 }
12119
12120 // Merge into one list.
12121 int ir = 0;
12122 if (receivers != null) {
12123 // A special case for PACKAGE_ADDED: do not allow the package
12124 // being added to see this broadcast. This prevents them from
12125 // using this as a back door to get run as soon as they are
12126 // installed. Maybe in the future we want to have a special install
12127 // broadcast or such for apps, but we'd like to deliberately make
12128 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070012129 boolean skip = false;
12130 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070012131 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070012132 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
12133 skip = true;
12134 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12135 skip = true;
12136 }
12137 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012138 ? intent.getData().getSchemeSpecificPart()
12139 : null;
12140 if (skipPackage != null && receivers != null) {
12141 int NT = receivers.size();
12142 for (int it=0; it<NT; it++) {
12143 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12144 if (curt.activityInfo.packageName.equals(skipPackage)) {
12145 receivers.remove(it);
12146 it--;
12147 NT--;
12148 }
12149 }
12150 }
12151
12152 int NT = receivers != null ? receivers.size() : 0;
12153 int it = 0;
12154 ResolveInfo curt = null;
12155 BroadcastFilter curr = null;
12156 while (it < NT && ir < NR) {
12157 if (curt == null) {
12158 curt = (ResolveInfo)receivers.get(it);
12159 }
12160 if (curr == null) {
12161 curr = registeredReceivers.get(ir);
12162 }
12163 if (curr.getPriority() >= curt.priority) {
12164 // Insert this broadcast record into the final list.
12165 receivers.add(it, curr);
12166 ir++;
12167 curr = null;
12168 it++;
12169 NT++;
12170 } else {
12171 // Skip to the next ResolveInfo in the final list.
12172 it++;
12173 curt = null;
12174 }
12175 }
12176 }
12177 while (ir < NR) {
12178 if (receivers == null) {
12179 receivers = new ArrayList();
12180 }
12181 receivers.add(registeredReceivers.get(ir));
12182 ir++;
12183 }
12184
12185 if ((receivers != null && receivers.size() > 0)
12186 || resultTo != null) {
12187 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12188 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012189 receivers, resultTo, resultCode, resultData, map, ordered,
12190 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012191 if (DEBUG_BROADCAST) Log.v(
12192 TAG, "Enqueueing ordered broadcast " + r
12193 + ": prev had " + mOrderedBroadcasts.size());
12194 if (DEBUG_BROADCAST) {
12195 int seq = r.intent.getIntExtra("seq", -1);
12196 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12197 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012198 boolean replaced = false;
12199 if (replacePending) {
12200 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12201 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12202 if (DEBUG_BROADCAST) Log.v(TAG,
12203 "***** DROPPING ORDERED: " + intent);
12204 mOrderedBroadcasts.set(i, r);
12205 replaced = true;
12206 break;
12207 }
12208 }
12209 }
12210 if (!replaced) {
12211 mOrderedBroadcasts.add(r);
12212 scheduleBroadcastsLocked();
12213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012214 }
12215
12216 return BROADCAST_SUCCESS;
12217 }
12218
12219 public final int broadcastIntent(IApplicationThread caller,
12220 Intent intent, String resolvedType, IIntentReceiver resultTo,
12221 int resultCode, String resultData, Bundle map,
12222 String requiredPermission, boolean serialized, boolean sticky) {
12223 // Refuse possible leaked file descriptors
12224 if (intent != null && intent.hasFileDescriptors() == true) {
12225 throw new IllegalArgumentException("File descriptors passed in Intent");
12226 }
12227
12228 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012229 int flags = intent.getFlags();
12230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012231 if (!mSystemReady) {
12232 // if the caller really truly claims to know what they're doing, go
12233 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012234 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12235 intent = new Intent(intent);
12236 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12237 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12238 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12239 + " before boot completion");
12240 throw new IllegalStateException("Cannot broadcast before boot completed");
12241 }
12242 }
12243
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012244 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12245 throw new IllegalArgumentException(
12246 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12247 }
12248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012249 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12250 final int callingPid = Binder.getCallingPid();
12251 final int callingUid = Binder.getCallingUid();
12252 final long origId = Binder.clearCallingIdentity();
12253 int res = broadcastIntentLocked(callerApp,
12254 callerApp != null ? callerApp.info.packageName : null,
12255 intent, resolvedType, resultTo,
12256 resultCode, resultData, map, requiredPermission, serialized,
12257 sticky, callingPid, callingUid);
12258 Binder.restoreCallingIdentity(origId);
12259 return res;
12260 }
12261 }
12262
12263 int broadcastIntentInPackage(String packageName, int uid,
12264 Intent intent, String resolvedType, IIntentReceiver resultTo,
12265 int resultCode, String resultData, Bundle map,
12266 String requiredPermission, boolean serialized, boolean sticky) {
12267 synchronized(this) {
12268 final long origId = Binder.clearCallingIdentity();
12269 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12270 resultTo, resultCode, resultData, map, requiredPermission,
12271 serialized, sticky, -1, uid);
12272 Binder.restoreCallingIdentity(origId);
12273 return res;
12274 }
12275 }
12276
12277 public final void unbroadcastIntent(IApplicationThread caller,
12278 Intent intent) {
12279 // Refuse possible leaked file descriptors
12280 if (intent != null && intent.hasFileDescriptors() == true) {
12281 throw new IllegalArgumentException("File descriptors passed in Intent");
12282 }
12283
12284 synchronized(this) {
12285 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12286 != PackageManager.PERMISSION_GRANTED) {
12287 String msg = "Permission Denial: unbroadcastIntent() from pid="
12288 + Binder.getCallingPid()
12289 + ", uid=" + Binder.getCallingUid()
12290 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12291 Log.w(TAG, msg);
12292 throw new SecurityException(msg);
12293 }
12294 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12295 if (list != null) {
12296 int N = list.size();
12297 int i;
12298 for (i=0; i<N; i++) {
12299 if (intent.filterEquals(list.get(i))) {
12300 list.remove(i);
12301 break;
12302 }
12303 }
12304 }
12305 }
12306 }
12307
12308 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12309 String resultData, Bundle resultExtras, boolean resultAbort,
12310 boolean explicit) {
12311 if (mOrderedBroadcasts.size() == 0) {
12312 if (explicit) {
12313 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12314 }
12315 return false;
12316 }
12317 BroadcastRecord r = mOrderedBroadcasts.get(0);
12318 if (r.receiver == null) {
12319 if (explicit) {
12320 Log.w(TAG, "finishReceiver called but none active");
12321 }
12322 return false;
12323 }
12324 if (r.receiver != receiver) {
12325 Log.w(TAG, "finishReceiver called but active receiver is different");
12326 return false;
12327 }
12328 int state = r.state;
12329 r.state = r.IDLE;
12330 if (state == r.IDLE) {
12331 if (explicit) {
12332 Log.w(TAG, "finishReceiver called but state is IDLE");
12333 }
12334 }
12335 r.receiver = null;
12336 r.intent.setComponent(null);
12337 if (r.curApp != null) {
12338 r.curApp.curReceiver = null;
12339 }
12340 if (r.curFilter != null) {
12341 r.curFilter.receiverList.curBroadcast = null;
12342 }
12343 r.curFilter = null;
12344 r.curApp = null;
12345 r.curComponent = null;
12346 r.curReceiver = null;
12347 mPendingBroadcast = null;
12348
12349 r.resultCode = resultCode;
12350 r.resultData = resultData;
12351 r.resultExtras = resultExtras;
12352 r.resultAbort = resultAbort;
12353
12354 // We will process the next receiver right now if this is finishing
12355 // an app receiver (which is always asynchronous) or after we have
12356 // come back from calling a receiver.
12357 return state == BroadcastRecord.APP_RECEIVE
12358 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12359 }
12360
12361 public void finishReceiver(IBinder who, int resultCode, String resultData,
12362 Bundle resultExtras, boolean resultAbort) {
12363 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12364
12365 // Refuse possible leaked file descriptors
12366 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12367 throw new IllegalArgumentException("File descriptors passed in Bundle");
12368 }
12369
12370 boolean doNext;
12371
12372 final long origId = Binder.clearCallingIdentity();
12373
12374 synchronized(this) {
12375 doNext = finishReceiverLocked(
12376 who, resultCode, resultData, resultExtras, resultAbort, true);
12377 }
12378
12379 if (doNext) {
12380 processNextBroadcast(false);
12381 }
12382 trimApplications();
12383
12384 Binder.restoreCallingIdentity(origId);
12385 }
12386
12387 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12388 if (r.nextReceiver > 0) {
12389 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12390 if (curReceiver instanceof BroadcastFilter) {
12391 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012392 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012393 System.identityHashCode(r),
12394 r.intent.getAction(),
12395 r.nextReceiver - 1,
12396 System.identityHashCode(bf));
12397 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012398 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012399 System.identityHashCode(r),
12400 r.intent.getAction(),
12401 r.nextReceiver - 1,
12402 ((ResolveInfo)curReceiver).toString());
12403 }
12404 } else {
12405 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12406 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012407 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012408 System.identityHashCode(r),
12409 r.intent.getAction(),
12410 r.nextReceiver,
12411 "NONE");
12412 }
12413 }
12414
12415 private final void broadcastTimeout() {
12416 synchronized (this) {
12417 if (mOrderedBroadcasts.size() == 0) {
12418 return;
12419 }
12420 long now = SystemClock.uptimeMillis();
12421 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012422 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012423 if (DEBUG_BROADCAST) Log.v(TAG,
12424 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012425 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012426 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012427 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012428 return;
12429 }
12430
12431 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012432 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012433 r.anrCount++;
12434
12435 // Current receiver has passed its expiration date.
12436 if (r.nextReceiver <= 0) {
12437 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12438 return;
12439 }
12440
12441 ProcessRecord app = null;
12442
12443 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12444 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12445 logBroadcastReceiverDiscard(r);
12446 if (curReceiver instanceof BroadcastFilter) {
12447 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12448 if (bf.receiverList.pid != 0
12449 && bf.receiverList.pid != MY_PID) {
12450 synchronized (this.mPidsSelfLocked) {
12451 app = this.mPidsSelfLocked.get(
12452 bf.receiverList.pid);
12453 }
12454 }
12455 } else {
12456 app = r.curApp;
12457 }
12458
12459 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012460 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012461 }
12462
12463 if (mPendingBroadcast == r) {
12464 mPendingBroadcast = null;
12465 }
12466
12467 // Move on to the next receiver.
12468 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12469 r.resultExtras, r.resultAbort, true);
12470 scheduleBroadcastsLocked();
12471 }
12472 }
12473
12474 private final void processCurBroadcastLocked(BroadcastRecord r,
12475 ProcessRecord app) throws RemoteException {
12476 if (app.thread == null) {
12477 throw new RemoteException();
12478 }
12479 r.receiver = app.thread.asBinder();
12480 r.curApp = app;
12481 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012482 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012483
12484 // Tell the application to launch this receiver.
12485 r.intent.setComponent(r.curComponent);
12486
12487 boolean started = false;
12488 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012489 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012490 "Delivering to component " + r.curComponent
12491 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012492 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012493 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12494 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12495 started = true;
12496 } finally {
12497 if (!started) {
12498 r.receiver = null;
12499 r.curApp = null;
12500 app.curReceiver = null;
12501 }
12502 }
12503
12504 }
12505
12506 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012507 Intent intent, int resultCode, String data, Bundle extras,
12508 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012509 if (app != null && app.thread != null) {
12510 // If we have an app thread, do the call through that so it is
12511 // correctly ordered with other one-way calls.
12512 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012513 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012514 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012515 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012516 }
12517 }
12518
12519 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12520 BroadcastFilter filter, boolean ordered) {
12521 boolean skip = false;
12522 if (filter.requiredPermission != null) {
12523 int perm = checkComponentPermission(filter.requiredPermission,
12524 r.callingPid, r.callingUid, -1);
12525 if (perm != PackageManager.PERMISSION_GRANTED) {
12526 Log.w(TAG, "Permission Denial: broadcasting "
12527 + r.intent.toString()
12528 + " from " + r.callerPackage + " (pid="
12529 + r.callingPid + ", uid=" + r.callingUid + ")"
12530 + " requires " + filter.requiredPermission
12531 + " due to registered receiver " + filter);
12532 skip = true;
12533 }
12534 }
12535 if (r.requiredPermission != null) {
12536 int perm = checkComponentPermission(r.requiredPermission,
12537 filter.receiverList.pid, filter.receiverList.uid, -1);
12538 if (perm != PackageManager.PERMISSION_GRANTED) {
12539 Log.w(TAG, "Permission Denial: receiving "
12540 + r.intent.toString()
12541 + " to " + filter.receiverList.app
12542 + " (pid=" + filter.receiverList.pid
12543 + ", uid=" + filter.receiverList.uid + ")"
12544 + " requires " + r.requiredPermission
12545 + " due to sender " + r.callerPackage
12546 + " (uid " + r.callingUid + ")");
12547 skip = true;
12548 }
12549 }
12550
12551 if (!skip) {
12552 // If this is not being sent as an ordered broadcast, then we
12553 // don't want to touch the fields that keep track of the current
12554 // state of ordered broadcasts.
12555 if (ordered) {
12556 r.receiver = filter.receiverList.receiver.asBinder();
12557 r.curFilter = filter;
12558 filter.receiverList.curBroadcast = r;
12559 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012560 if (filter.receiverList.app != null) {
12561 // Bump hosting application to no longer be in background
12562 // scheduling class. Note that we can't do that if there
12563 // isn't an app... but we can only be in that case for
12564 // things that directly call the IActivityManager API, which
12565 // are already core system stuff so don't matter for this.
12566 r.curApp = filter.receiverList.app;
12567 filter.receiverList.app.curReceiver = r;
12568 updateOomAdjLocked();
12569 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012570 }
12571 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012572 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012573 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012574 Log.i(TAG, "Delivering to " + filter.receiverList.app
12575 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012576 }
12577 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12578 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012579 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012580 if (ordered) {
12581 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12582 }
12583 } catch (RemoteException e) {
12584 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12585 if (ordered) {
12586 r.receiver = null;
12587 r.curFilter = null;
12588 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012589 if (filter.receiverList.app != null) {
12590 filter.receiverList.app.curReceiver = null;
12591 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012592 }
12593 }
12594 }
12595 }
12596
Dianne Hackborn12527f92009-11-11 17:39:50 -080012597 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12598 if (r.callingUid < 0) {
12599 // This was from a registerReceiver() call; ignore it.
12600 return;
12601 }
12602 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12603 MAX_BROADCAST_HISTORY-1);
12604 r.finishTime = SystemClock.uptimeMillis();
12605 mBroadcastHistory[0] = r;
12606 }
12607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012608 private final void processNextBroadcast(boolean fromMsg) {
12609 synchronized(this) {
12610 BroadcastRecord r;
12611
12612 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12613 + mParallelBroadcasts.size() + " broadcasts, "
12614 + mOrderedBroadcasts.size() + " serialized broadcasts");
12615
12616 updateCpuStats();
12617
12618 if (fromMsg) {
12619 mBroadcastsScheduled = false;
12620 }
12621
12622 // First, deliver any non-serialized broadcasts right away.
12623 while (mParallelBroadcasts.size() > 0) {
12624 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012625 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012626 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012627 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12628 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012629 for (int i=0; i<N; i++) {
12630 Object target = r.receivers.get(i);
12631 if (DEBUG_BROADCAST) Log.v(TAG,
12632 "Delivering non-serialized to registered "
12633 + target + ": " + r);
12634 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12635 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012636 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012637 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12638 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012639 }
12640
12641 // Now take care of the next serialized one...
12642
12643 // If we are waiting for a process to come up to handle the next
12644 // broadcast, then do nothing at this point. Just in case, we
12645 // check that the process we're waiting for still exists.
12646 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012647 if (DEBUG_BROADCAST_LIGHT) {
12648 Log.v(TAG, "processNextBroadcast: waiting for "
12649 + mPendingBroadcast.curApp);
12650 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012651
12652 boolean isDead;
12653 synchronized (mPidsSelfLocked) {
12654 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12655 }
12656 if (!isDead) {
12657 // It's still alive, so keep waiting
12658 return;
12659 } else {
12660 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12661 + " died before responding to broadcast");
12662 mPendingBroadcast = null;
12663 }
12664 }
12665
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012666 boolean looped = false;
12667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012668 do {
12669 if (mOrderedBroadcasts.size() == 0) {
12670 // No more broadcasts pending, so all done!
12671 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012672 if (looped) {
12673 // If we had finished the last ordered broadcast, then
12674 // make sure all processes have correct oom and sched
12675 // adjustments.
12676 updateOomAdjLocked();
12677 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012678 return;
12679 }
12680 r = mOrderedBroadcasts.get(0);
12681 boolean forceReceive = false;
12682
12683 // Ensure that even if something goes awry with the timeout
12684 // detection, we catch "hung" broadcasts here, discard them,
12685 // and continue to make progress.
12686 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12687 long now = SystemClock.uptimeMillis();
12688 if (r.dispatchTime > 0) {
12689 if ((numReceivers > 0) &&
12690 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12691 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12692 + " now=" + now
12693 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012694 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012695 + " intent=" + r.intent
12696 + " numReceivers=" + numReceivers
12697 + " nextReceiver=" + r.nextReceiver
12698 + " state=" + r.state);
12699 broadcastTimeout(); // forcibly finish this broadcast
12700 forceReceive = true;
12701 r.state = BroadcastRecord.IDLE;
12702 }
12703 }
12704
12705 if (r.state != BroadcastRecord.IDLE) {
12706 if (DEBUG_BROADCAST) Log.d(TAG,
12707 "processNextBroadcast() called when not idle (state="
12708 + r.state + ")");
12709 return;
12710 }
12711
12712 if (r.receivers == null || r.nextReceiver >= numReceivers
12713 || r.resultAbort || forceReceive) {
12714 // No more receivers for this broadcast! Send the final
12715 // result if requested...
12716 if (r.resultTo != null) {
12717 try {
12718 if (DEBUG_BROADCAST) {
12719 int seq = r.intent.getIntExtra("seq", -1);
12720 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12721 + " seq=" + seq + " app=" + r.callerApp);
12722 }
12723 performReceive(r.callerApp, r.resultTo,
12724 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012725 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012726 } catch (RemoteException e) {
12727 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12728 }
12729 }
12730
12731 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12732 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12733
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012734 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12735 + r);
12736
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012737 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012738 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012739 mOrderedBroadcasts.remove(0);
12740 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012741 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012742 continue;
12743 }
12744 } while (r == null);
12745
12746 // Get the next receiver...
12747 int recIdx = r.nextReceiver++;
12748
12749 // Keep track of when this receiver started, and make sure there
12750 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012751 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012752 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012753 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012754
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012755 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12756 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012757 if (DEBUG_BROADCAST) Log.v(TAG,
12758 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012759 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012760 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012761 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012762 }
12763
12764 Object nextReceiver = r.receivers.get(recIdx);
12765 if (nextReceiver instanceof BroadcastFilter) {
12766 // Simple case: this is a registered receiver who gets
12767 // a direct call.
12768 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12769 if (DEBUG_BROADCAST) Log.v(TAG,
12770 "Delivering serialized to registered "
12771 + filter + ": " + r);
12772 deliverToRegisteredReceiver(r, filter, r.ordered);
12773 if (r.receiver == null || !r.ordered) {
12774 // The receiver has already finished, so schedule to
12775 // process the next one.
12776 r.state = BroadcastRecord.IDLE;
12777 scheduleBroadcastsLocked();
12778 }
12779 return;
12780 }
12781
12782 // Hard case: need to instantiate the receiver, possibly
12783 // starting its application process to host it.
12784
12785 ResolveInfo info =
12786 (ResolveInfo)nextReceiver;
12787
12788 boolean skip = false;
12789 int perm = checkComponentPermission(info.activityInfo.permission,
12790 r.callingPid, r.callingUid,
12791 info.activityInfo.exported
12792 ? -1 : info.activityInfo.applicationInfo.uid);
12793 if (perm != PackageManager.PERMISSION_GRANTED) {
12794 Log.w(TAG, "Permission Denial: broadcasting "
12795 + r.intent.toString()
12796 + " from " + r.callerPackage + " (pid=" + r.callingPid
12797 + ", uid=" + r.callingUid + ")"
12798 + " requires " + info.activityInfo.permission
12799 + " due to receiver " + info.activityInfo.packageName
12800 + "/" + info.activityInfo.name);
12801 skip = true;
12802 }
12803 if (r.callingUid != Process.SYSTEM_UID &&
12804 r.requiredPermission != null) {
12805 try {
12806 perm = ActivityThread.getPackageManager().
12807 checkPermission(r.requiredPermission,
12808 info.activityInfo.applicationInfo.packageName);
12809 } catch (RemoteException e) {
12810 perm = PackageManager.PERMISSION_DENIED;
12811 }
12812 if (perm != PackageManager.PERMISSION_GRANTED) {
12813 Log.w(TAG, "Permission Denial: receiving "
12814 + r.intent + " to "
12815 + info.activityInfo.applicationInfo.packageName
12816 + " requires " + r.requiredPermission
12817 + " due to sender " + r.callerPackage
12818 + " (uid " + r.callingUid + ")");
12819 skip = true;
12820 }
12821 }
12822 if (r.curApp != null && r.curApp.crashing) {
12823 // If the target process is crashing, just skip it.
12824 skip = true;
12825 }
12826
12827 if (skip) {
12828 r.receiver = null;
12829 r.curFilter = null;
12830 r.state = BroadcastRecord.IDLE;
12831 scheduleBroadcastsLocked();
12832 return;
12833 }
12834
12835 r.state = BroadcastRecord.APP_RECEIVE;
12836 String targetProcess = info.activityInfo.processName;
12837 r.curComponent = new ComponentName(
12838 info.activityInfo.applicationInfo.packageName,
12839 info.activityInfo.name);
12840 r.curReceiver = info.activityInfo;
12841
12842 // Is this receiver's application already running?
12843 ProcessRecord app = getProcessRecordLocked(targetProcess,
12844 info.activityInfo.applicationInfo.uid);
12845 if (app != null && app.thread != null) {
12846 try {
12847 processCurBroadcastLocked(r, app);
12848 return;
12849 } catch (RemoteException e) {
12850 Log.w(TAG, "Exception when sending broadcast to "
12851 + r.curComponent, e);
12852 }
12853
12854 // If a dead object exception was thrown -- fall through to
12855 // restart the application.
12856 }
12857
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012858 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012859 if ((r.curApp=startProcessLocked(targetProcess,
12860 info.activityInfo.applicationInfo, true,
12861 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012862 "broadcast", r.curComponent,
12863 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12864 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012865 // Ah, this recipient is unavailable. Finish it if necessary,
12866 // and mark the broadcast record as ready for the next.
12867 Log.w(TAG, "Unable to launch app "
12868 + info.activityInfo.applicationInfo.packageName + "/"
12869 + info.activityInfo.applicationInfo.uid + " for broadcast "
12870 + r.intent + ": process is bad");
12871 logBroadcastReceiverDiscard(r);
12872 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12873 r.resultExtras, r.resultAbort, true);
12874 scheduleBroadcastsLocked();
12875 r.state = BroadcastRecord.IDLE;
12876 return;
12877 }
12878
12879 mPendingBroadcast = r;
12880 }
12881 }
12882
12883 // =========================================================
12884 // INSTRUMENTATION
12885 // =========================================================
12886
12887 public boolean startInstrumentation(ComponentName className,
12888 String profileFile, int flags, Bundle arguments,
12889 IInstrumentationWatcher watcher) {
12890 // Refuse possible leaked file descriptors
12891 if (arguments != null && arguments.hasFileDescriptors()) {
12892 throw new IllegalArgumentException("File descriptors passed in Bundle");
12893 }
12894
12895 synchronized(this) {
12896 InstrumentationInfo ii = null;
12897 ApplicationInfo ai = null;
12898 try {
12899 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012900 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012901 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012902 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012903 } catch (PackageManager.NameNotFoundException e) {
12904 }
12905 if (ii == null) {
12906 reportStartInstrumentationFailure(watcher, className,
12907 "Unable to find instrumentation info for: " + className);
12908 return false;
12909 }
12910 if (ai == null) {
12911 reportStartInstrumentationFailure(watcher, className,
12912 "Unable to find instrumentation target package: " + ii.targetPackage);
12913 return false;
12914 }
12915
12916 int match = mContext.getPackageManager().checkSignatures(
12917 ii.targetPackage, ii.packageName);
12918 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12919 String msg = "Permission Denial: starting instrumentation "
12920 + className + " from pid="
12921 + Binder.getCallingPid()
12922 + ", uid=" + Binder.getCallingPid()
12923 + " not allowed because package " + ii.packageName
12924 + " does not have a signature matching the target "
12925 + ii.targetPackage;
12926 reportStartInstrumentationFailure(watcher, className, msg);
12927 throw new SecurityException(msg);
12928 }
12929
12930 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn03abb812010-01-04 18:43:19 -080012931 forceStopPackageLocked(ii.targetPackage, -1, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012932 ProcessRecord app = addAppLocked(ai);
12933 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012934 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012935 app.instrumentationProfileFile = profileFile;
12936 app.instrumentationArguments = arguments;
12937 app.instrumentationWatcher = watcher;
12938 app.instrumentationResultClass = className;
12939 Binder.restoreCallingIdentity(origId);
12940 }
12941
12942 return true;
12943 }
12944
12945 /**
12946 * Report errors that occur while attempting to start Instrumentation. Always writes the
12947 * error to the logs, but if somebody is watching, send the report there too. This enables
12948 * the "am" command to report errors with more information.
12949 *
12950 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12951 * @param cn The component name of the instrumentation.
12952 * @param report The error report.
12953 */
12954 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12955 ComponentName cn, String report) {
12956 Log.w(TAG, report);
12957 try {
12958 if (watcher != null) {
12959 Bundle results = new Bundle();
12960 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12961 results.putString("Error", report);
12962 watcher.instrumentationStatus(cn, -1, results);
12963 }
12964 } catch (RemoteException e) {
12965 Log.w(TAG, e);
12966 }
12967 }
12968
12969 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12970 if (app.instrumentationWatcher != null) {
12971 try {
12972 // NOTE: IInstrumentationWatcher *must* be oneway here
12973 app.instrumentationWatcher.instrumentationFinished(
12974 app.instrumentationClass,
12975 resultCode,
12976 results);
12977 } catch (RemoteException e) {
12978 }
12979 }
12980 app.instrumentationWatcher = null;
12981 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012982 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012983 app.instrumentationProfileFile = null;
12984 app.instrumentationArguments = null;
12985
Dianne Hackborn03abb812010-01-04 18:43:19 -080012986 forceStopPackageLocked(app.processName, -1, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012987 }
12988
12989 public void finishInstrumentation(IApplicationThread target,
12990 int resultCode, Bundle results) {
12991 // Refuse possible leaked file descriptors
12992 if (results != null && results.hasFileDescriptors()) {
12993 throw new IllegalArgumentException("File descriptors passed in Intent");
12994 }
12995
12996 synchronized(this) {
12997 ProcessRecord app = getRecordForAppLocked(target);
12998 if (app == null) {
12999 Log.w(TAG, "finishInstrumentation: no app for " + target);
13000 return;
13001 }
13002 final long origId = Binder.clearCallingIdentity();
13003 finishInstrumentationLocked(app, resultCode, results);
13004 Binder.restoreCallingIdentity(origId);
13005 }
13006 }
13007
13008 // =========================================================
13009 // CONFIGURATION
13010 // =========================================================
13011
13012 public ConfigurationInfo getDeviceConfigurationInfo() {
13013 ConfigurationInfo config = new ConfigurationInfo();
13014 synchronized (this) {
13015 config.reqTouchScreen = mConfiguration.touchscreen;
13016 config.reqKeyboardType = mConfiguration.keyboard;
13017 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013018 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
13019 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013020 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
13021 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013022 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
13023 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013024 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
13025 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070013026 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013027 }
13028 return config;
13029 }
13030
13031 public Configuration getConfiguration() {
13032 Configuration ci;
13033 synchronized(this) {
13034 ci = new Configuration(mConfiguration);
13035 }
13036 return ci;
13037 }
13038
13039 public void updateConfiguration(Configuration values) {
13040 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13041 "updateConfiguration()");
13042
13043 synchronized(this) {
13044 if (values == null && mWindowManager != null) {
13045 // sentinel: fetch the current configuration from the window manager
13046 values = mWindowManager.computeNewConfiguration();
13047 }
13048
13049 final long origId = Binder.clearCallingIdentity();
13050 updateConfigurationLocked(values, null);
13051 Binder.restoreCallingIdentity(origId);
13052 }
13053 }
13054
13055 /**
13056 * Do either or both things: (1) change the current configuration, and (2)
13057 * make sure the given activity is running with the (now) current
13058 * configuration. Returns true if the activity has been left running, or
13059 * false if <var>starting</var> is being destroyed to match the new
13060 * configuration.
13061 */
13062 public boolean updateConfigurationLocked(Configuration values,
13063 HistoryRecord starting) {
13064 int changes = 0;
13065
13066 boolean kept = true;
13067
13068 if (values != null) {
13069 Configuration newConfig = new Configuration(mConfiguration);
13070 changes = newConfig.updateFrom(values);
13071 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013072 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013073 Log.i(TAG, "Updating configuration to: " + values);
13074 }
13075
Doug Zongker2bec3d42009-12-04 12:52:44 -080013076 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013077
13078 if (values.locale != null) {
13079 saveLocaleLocked(values.locale,
13080 !values.locale.equals(mConfiguration.locale),
13081 values.userSetLocale);
13082 }
13083
13084 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013085 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013086
13087 AttributeCache ac = AttributeCache.instance();
13088 if (ac != null) {
13089 ac.updateConfiguration(mConfiguration);
13090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013091
13092 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13093 msg.obj = new Configuration(mConfiguration);
13094 mHandler.sendMessage(msg);
13095
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013096 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13097 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013098 try {
13099 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013100 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13101 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013102 app.thread.scheduleConfigurationChanged(mConfiguration);
13103 }
13104 } catch (Exception e) {
13105 }
13106 }
13107 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013108 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13109 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013110 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13111 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013112 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13113 broadcastIntentLocked(null, null,
13114 new Intent(Intent.ACTION_LOCALE_CHANGED),
13115 null, null, 0, null, null,
13116 null, false, false, MY_PID, Process.SYSTEM_UID);
13117 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013118 }
13119 }
13120
13121 if (changes != 0 && starting == null) {
13122 // If the configuration changed, and the caller is not already
13123 // in the process of starting an activity, then find the top
13124 // activity to check if its configuration needs to change.
13125 starting = topRunningActivityLocked(null);
13126 }
13127
13128 if (starting != null) {
13129 kept = ensureActivityConfigurationLocked(starting, changes);
13130 if (kept) {
13131 // If this didn't result in the starting activity being
13132 // destroyed, then we need to make sure at this point that all
13133 // other activities are made visible.
13134 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13135 + ", ensuring others are correct.");
13136 ensureActivitiesVisibleLocked(starting, changes);
13137 }
13138 }
13139
13140 return kept;
13141 }
13142
13143 private final boolean relaunchActivityLocked(HistoryRecord r,
13144 int changes, boolean andResume) {
13145 List<ResultInfo> results = null;
13146 List<Intent> newIntents = null;
13147 if (andResume) {
13148 results = r.results;
13149 newIntents = r.newIntents;
13150 }
13151 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13152 + " with results=" + results + " newIntents=" + newIntents
13153 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013154 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13155 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013156 r.task.taskId, r.shortComponentName);
13157
13158 r.startFreezingScreenLocked(r.app, 0);
13159
13160 try {
13161 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13162 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013163 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013164 // Note: don't need to call pauseIfSleepingLocked() here, because
13165 // the caller will only pass in 'andResume' if this activity is
13166 // currently resumed, which implies we aren't sleeping.
13167 } catch (RemoteException e) {
13168 return false;
13169 }
13170
13171 if (andResume) {
13172 r.results = null;
13173 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013174 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013175 }
13176
13177 return true;
13178 }
13179
13180 /**
13181 * Make sure the given activity matches the current configuration. Returns
13182 * false if the activity had to be destroyed. Returns true if the
13183 * configuration is the same, or the activity will remain running as-is
13184 * for whatever reason. Ensures the HistoryRecord is updated with the
13185 * correct configuration and all other bookkeeping is handled.
13186 */
13187 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13188 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013189 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13190 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013191
13192 // Short circuit: if the two configurations are the exact same
13193 // object (the common case), then there is nothing to do.
13194 Configuration newConfig = mConfiguration;
13195 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013196 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13197 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013198 return true;
13199 }
13200
13201 // We don't worry about activities that are finishing.
13202 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013203 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013204 "Configuration doesn't matter in finishing " + r);
13205 r.stopFreezingScreenLocked(false);
13206 return true;
13207 }
13208
13209 // Okay we now are going to make this activity have the new config.
13210 // But then we need to figure out how it needs to deal with that.
13211 Configuration oldConfig = r.configuration;
13212 r.configuration = newConfig;
13213
13214 // If the activity isn't currently running, just leave the new
13215 // configuration and it will pick that up next time it starts.
13216 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013217 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013218 "Configuration doesn't matter not running " + r);
13219 r.stopFreezingScreenLocked(false);
13220 return true;
13221 }
13222
13223 // If the activity isn't persistent, there is a chance we will
13224 // need to restart it.
13225 if (!r.persistent) {
13226
13227 // Figure out what has changed between the two configurations.
13228 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013229 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13230 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013231 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013232 + Integer.toHexString(r.info.configChanges)
13233 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013234 }
13235 if ((changes&(~r.info.configChanges)) != 0) {
13236 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13237 r.configChangeFlags |= changes;
13238 r.startFreezingScreenLocked(r.app, globalChanges);
13239 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013240 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13241 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013242 destroyActivityLocked(r, true);
13243 } else if (r.state == ActivityState.PAUSING) {
13244 // A little annoying: we are waiting for this activity to
13245 // finish pausing. Let's not do anything now, but just
13246 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013247 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13248 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013249 r.configDestroy = true;
13250 return true;
13251 } else if (r.state == ActivityState.RESUMED) {
13252 // Try to optimize this case: the configuration is changing
13253 // and we need to restart the top, resumed activity.
13254 // Instead of doing the normal handshaking, just say
13255 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013256 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13257 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013258 relaunchActivityLocked(r, r.configChangeFlags, true);
13259 r.configChangeFlags = 0;
13260 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013261 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13262 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013263 relaunchActivityLocked(r, r.configChangeFlags, false);
13264 r.configChangeFlags = 0;
13265 }
13266
13267 // All done... tell the caller we weren't able to keep this
13268 // activity around.
13269 return false;
13270 }
13271 }
13272
13273 // Default case: the activity can handle this new configuration, so
13274 // hand it over. Note that we don't need to give it the new
13275 // configuration, since we always send configuration changes to all
13276 // process when they happen so it can just use whatever configuration
13277 // it last got.
13278 if (r.app != null && r.app.thread != null) {
13279 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013280 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013281 r.app.thread.scheduleActivityConfigurationChanged(r);
13282 } catch (RemoteException e) {
13283 // If process died, whatever.
13284 }
13285 }
13286 r.stopFreezingScreenLocked(false);
13287
13288 return true;
13289 }
13290
13291 /**
13292 * Save the locale. You must be inside a synchronized (this) block.
13293 */
13294 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13295 if(isDiff) {
13296 SystemProperties.set("user.language", l.getLanguage());
13297 SystemProperties.set("user.region", l.getCountry());
13298 }
13299
13300 if(isPersist) {
13301 SystemProperties.set("persist.sys.language", l.getLanguage());
13302 SystemProperties.set("persist.sys.country", l.getCountry());
13303 SystemProperties.set("persist.sys.localevar", l.getVariant());
13304 }
13305 }
13306
13307 // =========================================================
13308 // LIFETIME MANAGEMENT
13309 // =========================================================
13310
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013311 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13312 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013313 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013314 // This adjustment has already been computed. If we are calling
13315 // from the top, we may have already computed our adjustment with
13316 // an earlier hidden adjustment that isn't really for us... if
13317 // so, use the new hidden adjustment.
13318 if (!recursed && app.hidden) {
13319 app.curAdj = hiddenAdj;
13320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013321 return app.curAdj;
13322 }
13323
13324 if (app.thread == null) {
13325 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013326 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013327 return (app.curAdj=EMPTY_APP_ADJ);
13328 }
13329
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013330 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13331 // The max adjustment doesn't allow this app to be anything
13332 // below foreground, so it is not worth doing work for it.
13333 app.adjType = "fixed";
13334 app.adjSeq = mAdjSeq;
13335 app.curRawAdj = app.maxAdj;
13336 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13337 return (app.curAdj=app.maxAdj);
13338 }
13339
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013340 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013341 app.adjSource = null;
13342 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013343 app.empty = false;
13344 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013345
The Android Open Source Project4df24232009-03-05 14:34:35 -080013346 // Determine the importance of the process, starting with most
13347 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013348 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013349 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013350 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013351 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013352 // The last app on the list is the foreground app.
13353 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013354 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013355 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013356 } else if (app.instrumentationClass != null) {
13357 // Don't want to kill running instrumentation.
13358 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013359 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013360 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013361 } else if (app.persistentActivities > 0) {
13362 // Special persistent activities... shouldn't be used these days.
13363 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013364 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013365 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013366 } else if (app.curReceiver != null ||
13367 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13368 // An app that is currently receiving a broadcast also
13369 // counts as being in the foreground.
13370 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013371 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013372 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013373 } else if (app.executingServices.size() > 0) {
13374 // An app that is currently executing a service callback also
13375 // counts as being in the foreground.
13376 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013377 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013378 app.adjType = "exec-service";
13379 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013380 // The user is aware of this app, so make it visible.
13381 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013382 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013383 app.adjType = "foreground-service";
13384 } else if (app.forcingToForeground != null) {
13385 // The user is aware of this app, so make it visible.
13386 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013387 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013388 app.adjType = "force-foreground";
13389 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013390 } else if (app == mHomeProcess) {
13391 // This process is hosting what we currently consider to be the
13392 // home app, so we don't want to let it go into the background.
13393 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013394 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013395 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013396 } else if ((N=app.activities.size()) != 0) {
13397 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013398 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013399 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013400 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013401 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013402 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013403 for (int j=0; j<N; j++) {
13404 if (((HistoryRecord)app.activities.get(j)).visible) {
13405 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013406 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013407 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013408 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013409 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013410 break;
13411 }
13412 }
13413 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013414 // A very not-needed process. If this is lower in the lru list,
13415 // we will push it in to the empty bucket.
13416 app.hidden = true;
13417 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013418 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013419 adj = hiddenAdj;
13420 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013421 }
13422
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013423 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13424
The Android Open Source Project4df24232009-03-05 14:34:35 -080013425 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013426 // there are applications dependent on our services or providers, but
13427 // this gives us a baseline and makes sure we don't get into an
13428 // infinite recursion.
13429 app.adjSeq = mAdjSeq;
13430 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013431
Christopher Tate6fa95972009-06-05 18:43:55 -070013432 if (mBackupTarget != null && app == mBackupTarget.app) {
13433 // If possible we want to avoid killing apps while they're being backed up
13434 if (adj > BACKUP_APP_ADJ) {
13435 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13436 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013437 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013438 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013439 }
13440 }
13441
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013442 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13443 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013444 final long now = SystemClock.uptimeMillis();
13445 // This process is more important if the top activity is
13446 // bound to the service.
13447 Iterator jt = app.services.iterator();
13448 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13449 ServiceRecord s = (ServiceRecord)jt.next();
13450 if (s.startRequested) {
13451 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13452 // This service has seen some activity within
13453 // recent memory, so we will keep its process ahead
13454 // of the background processes.
13455 if (adj > SECONDARY_SERVER_ADJ) {
13456 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013457 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013458 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013459 }
13460 }
13461 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013462 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13463 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013464 Iterator<ConnectionRecord> kt
13465 = s.connections.values().iterator();
13466 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13467 // XXX should compute this based on the max of
13468 // all connected clients.
13469 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013470 if (cr.binding.client == app) {
13471 // Binding to ourself is not interesting.
13472 continue;
13473 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013474 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13475 ProcessRecord client = cr.binding.client;
13476 int myHiddenAdj = hiddenAdj;
13477 if (myHiddenAdj > client.hiddenAdj) {
13478 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13479 myHiddenAdj = client.hiddenAdj;
13480 } else {
13481 myHiddenAdj = VISIBLE_APP_ADJ;
13482 }
13483 }
13484 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013485 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013486 if (adj > clientAdj) {
13487 adj = clientAdj > VISIBLE_APP_ADJ
13488 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013489 if (!client.hidden) {
13490 app.hidden = false;
13491 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013492 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013493 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13494 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013495 app.adjSource = cr.binding.client;
13496 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013497 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013498 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13499 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13500 schedGroup = Process.THREAD_GROUP_DEFAULT;
13501 }
13502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013503 }
13504 HistoryRecord a = cr.activity;
13505 //if (a != null) {
13506 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13507 //}
13508 if (a != null && adj > FOREGROUND_APP_ADJ &&
13509 (a.state == ActivityState.RESUMED
13510 || a.state == ActivityState.PAUSING)) {
13511 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013512 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013513 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013514 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013515 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13516 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013517 app.adjSource = a;
13518 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013519 }
13520 }
13521 }
13522 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013523
13524 // Finally, f this process has active services running in it, we
13525 // would like to avoid killing it unless it would prevent the current
13526 // application from running. By default we put the process in
13527 // with the rest of the background processes; as we scan through
13528 // its services we may bump it up from there.
13529 if (adj > hiddenAdj) {
13530 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013531 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013532 app.adjType = "bg-services";
13533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013534 }
13535
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013536 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13537 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013538 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013539 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13540 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013541 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13542 if (cpr.clients.size() != 0) {
13543 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13544 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13545 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013546 if (client == app) {
13547 // Being our own client is not interesting.
13548 continue;
13549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013550 int myHiddenAdj = hiddenAdj;
13551 if (myHiddenAdj > client.hiddenAdj) {
13552 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13553 myHiddenAdj = client.hiddenAdj;
13554 } else {
13555 myHiddenAdj = FOREGROUND_APP_ADJ;
13556 }
13557 }
13558 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013559 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013560 if (adj > clientAdj) {
13561 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013562 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013563 if (!client.hidden) {
13564 app.hidden = false;
13565 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013566 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013567 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13568 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013569 app.adjSource = client;
13570 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013571 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013572 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13573 schedGroup = Process.THREAD_GROUP_DEFAULT;
13574 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013575 }
13576 }
13577 // If the provider has external (non-framework) process
13578 // dependencies, ensure that its adjustment is at least
13579 // FOREGROUND_APP_ADJ.
13580 if (cpr.externals != 0) {
13581 if (adj > FOREGROUND_APP_ADJ) {
13582 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013583 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013584 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013585 app.adjType = "provider";
13586 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013587 }
13588 }
13589 }
13590 }
13591
13592 app.curRawAdj = adj;
13593
13594 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13595 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13596 if (adj > app.maxAdj) {
13597 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013598 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13599 schedGroup = Process.THREAD_GROUP_DEFAULT;
13600 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013601 }
13602
13603 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013604 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013606 return adj;
13607 }
13608
13609 /**
13610 * Ask a given process to GC right now.
13611 */
13612 final void performAppGcLocked(ProcessRecord app) {
13613 try {
13614 app.lastRequestedGc = SystemClock.uptimeMillis();
13615 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013616 if (app.reportLowMemory) {
13617 app.reportLowMemory = false;
13618 app.thread.scheduleLowMemory();
13619 } else {
13620 app.thread.processInBackground();
13621 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013622 }
13623 } catch (Exception e) {
13624 // whatever.
13625 }
13626 }
13627
13628 /**
13629 * Returns true if things are idle enough to perform GCs.
13630 */
13631 private final boolean canGcNow() {
13632 return mParallelBroadcasts.size() == 0
13633 && mOrderedBroadcasts.size() == 0
13634 && (mSleeping || (mResumedActivity != null &&
13635 mResumedActivity.idle));
13636 }
13637
13638 /**
13639 * Perform GCs on all processes that are waiting for it, but only
13640 * if things are idle.
13641 */
13642 final void performAppGcsLocked() {
13643 final int N = mProcessesToGc.size();
13644 if (N <= 0) {
13645 return;
13646 }
13647 if (canGcNow()) {
13648 while (mProcessesToGc.size() > 0) {
13649 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013650 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13651 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13652 <= SystemClock.uptimeMillis()) {
13653 // To avoid spamming the system, we will GC processes one
13654 // at a time, waiting a few seconds between each.
13655 performAppGcLocked(proc);
13656 scheduleAppGcsLocked();
13657 return;
13658 } else {
13659 // It hasn't been long enough since we last GCed this
13660 // process... put it in the list to wait for its time.
13661 addProcessToGcListLocked(proc);
13662 break;
13663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013664 }
13665 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013666
13667 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013668 }
13669 }
13670
13671 /**
13672 * If all looks good, perform GCs on all processes waiting for them.
13673 */
13674 final void performAppGcsIfAppropriateLocked() {
13675 if (canGcNow()) {
13676 performAppGcsLocked();
13677 return;
13678 }
13679 // Still not idle, wait some more.
13680 scheduleAppGcsLocked();
13681 }
13682
13683 /**
13684 * Schedule the execution of all pending app GCs.
13685 */
13686 final void scheduleAppGcsLocked() {
13687 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013688
13689 if (mProcessesToGc.size() > 0) {
13690 // Schedule a GC for the time to the next process.
13691 ProcessRecord proc = mProcessesToGc.get(0);
13692 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13693
13694 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13695 long now = SystemClock.uptimeMillis();
13696 if (when < (now+GC_TIMEOUT)) {
13697 when = now + GC_TIMEOUT;
13698 }
13699 mHandler.sendMessageAtTime(msg, when);
13700 }
13701 }
13702
13703 /**
13704 * Add a process to the array of processes waiting to be GCed. Keeps the
13705 * list in sorted order by the last GC time. The process can't already be
13706 * on the list.
13707 */
13708 final void addProcessToGcListLocked(ProcessRecord proc) {
13709 boolean added = false;
13710 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13711 if (mProcessesToGc.get(i).lastRequestedGc <
13712 proc.lastRequestedGc) {
13713 added = true;
13714 mProcessesToGc.add(i+1, proc);
13715 break;
13716 }
13717 }
13718 if (!added) {
13719 mProcessesToGc.add(0, proc);
13720 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013721 }
13722
13723 /**
13724 * Set up to ask a process to GC itself. This will either do it
13725 * immediately, or put it on the list of processes to gc the next
13726 * time things are idle.
13727 */
13728 final void scheduleAppGcLocked(ProcessRecord app) {
13729 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013730 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013731 return;
13732 }
13733 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013734 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013735 scheduleAppGcsLocked();
13736 }
13737 }
13738
13739 private final boolean updateOomAdjLocked(
13740 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13741 app.hiddenAdj = hiddenAdj;
13742
13743 if (app.thread == null) {
13744 return true;
13745 }
13746
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013747 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013748
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013749 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013750 if (app.curRawAdj != app.setRawAdj) {
13751 if (app.curRawAdj > FOREGROUND_APP_ADJ
13752 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13753 // If this app is transitioning from foreground to
13754 // non-foreground, have it do a gc.
13755 scheduleAppGcLocked(app);
13756 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13757 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13758 // Likewise do a gc when an app is moving in to the
13759 // background (such as a service stopping).
13760 scheduleAppGcLocked(app);
13761 }
13762 app.setRawAdj = app.curRawAdj;
13763 }
13764 if (adj != app.setAdj) {
13765 if (Process.setOomAdj(app.pid, adj)) {
13766 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13767 TAG, "Set app " + app.processName +
13768 " oom adj to " + adj);
13769 app.setAdj = adj;
13770 } else {
13771 return false;
13772 }
13773 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013774 if (app.setSchedGroup != app.curSchedGroup) {
13775 app.setSchedGroup = app.curSchedGroup;
13776 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13777 "Setting process group of " + app.processName
13778 + " to " + app.curSchedGroup);
13779 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013780 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013781 try {
13782 Process.setProcessGroup(app.pid, app.curSchedGroup);
13783 } catch (Exception e) {
13784 Log.w(TAG, "Failed setting process group of " + app.pid
13785 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013786 e.printStackTrace();
13787 } finally {
13788 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013789 }
13790 }
13791 if (false) {
13792 if (app.thread != null) {
13793 try {
13794 app.thread.setSchedulingGroup(app.curSchedGroup);
13795 } catch (RemoteException e) {
13796 }
13797 }
13798 }
13799 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013800 }
13801
13802 return true;
13803 }
13804
13805 private final HistoryRecord resumedAppLocked() {
13806 HistoryRecord resumedActivity = mResumedActivity;
13807 if (resumedActivity == null || resumedActivity.app == null) {
13808 resumedActivity = mPausingActivity;
13809 if (resumedActivity == null || resumedActivity.app == null) {
13810 resumedActivity = topRunningActivityLocked(null);
13811 }
13812 }
13813 return resumedActivity;
13814 }
13815
13816 private final boolean updateOomAdjLocked(ProcessRecord app) {
13817 final HistoryRecord TOP_ACT = resumedAppLocked();
13818 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13819 int curAdj = app.curAdj;
13820 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13821 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13822
13823 mAdjSeq++;
13824
13825 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13826 if (res) {
13827 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13828 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13829 if (nowHidden != wasHidden) {
13830 // Changed to/from hidden state, so apps after it in the LRU
13831 // list may also be changed.
13832 updateOomAdjLocked();
13833 }
13834 }
13835 return res;
13836 }
13837
13838 private final boolean updateOomAdjLocked() {
13839 boolean didOomAdj = true;
13840 final HistoryRecord TOP_ACT = resumedAppLocked();
13841 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13842
13843 if (false) {
13844 RuntimeException e = new RuntimeException();
13845 e.fillInStackTrace();
13846 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13847 }
13848
13849 mAdjSeq++;
13850
13851 // First try updating the OOM adjustment for each of the
13852 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013853 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013854 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13855 while (i > 0) {
13856 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013857 ProcessRecord app = mLruProcesses.get(i);
13858 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013859 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013860 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013861 && app.curAdj == curHiddenAdj) {
13862 curHiddenAdj++;
13863 }
13864 } else {
13865 didOomAdj = false;
13866 }
13867 }
13868
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013869 // If we return false, we will fall back on killing processes to
13870 // have a fixed limit. Do this if a limit has been requested; else
13871 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013872 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13873 }
13874
13875 private final void trimApplications() {
13876 synchronized (this) {
13877 int i;
13878
13879 // First remove any unused application processes whose package
13880 // has been removed.
13881 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13882 final ProcessRecord app = mRemovedProcesses.get(i);
13883 if (app.activities.size() == 0
13884 && app.curReceiver == null && app.services.size() == 0) {
13885 Log.i(
13886 TAG, "Exiting empty application process "
13887 + app.processName + " ("
13888 + (app.thread != null ? app.thread.asBinder() : null)
13889 + ")\n");
13890 if (app.pid > 0 && app.pid != MY_PID) {
13891 Process.killProcess(app.pid);
13892 } else {
13893 try {
13894 app.thread.scheduleExit();
13895 } catch (Exception e) {
13896 // Ignore exceptions.
13897 }
13898 }
13899 cleanUpApplicationRecordLocked(app, false, -1);
13900 mRemovedProcesses.remove(i);
13901
13902 if (app.persistent) {
13903 if (app.persistent) {
13904 addAppLocked(app.info);
13905 }
13906 }
13907 }
13908 }
13909
13910 // Now try updating the OOM adjustment for each of the
13911 // application processes based on their current state.
13912 // If the setOomAdj() API is not supported, then go with our
13913 // back-up plan...
13914 if (!updateOomAdjLocked()) {
13915
13916 // Count how many processes are running services.
13917 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013918 for (i=mLruProcesses.size()-1; i>=0; i--) {
13919 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013920
13921 if (app.persistent || app.services.size() != 0
13922 || app.curReceiver != null
13923 || app.persistentActivities > 0) {
13924 // Don't count processes holding services against our
13925 // maximum process count.
13926 if (localLOGV) Log.v(
13927 TAG, "Not trimming app " + app + " with services: "
13928 + app.services);
13929 numServiceProcs++;
13930 }
13931 }
13932
13933 int curMaxProcs = mProcessLimit;
13934 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13935 if (mAlwaysFinishActivities) {
13936 curMaxProcs = 1;
13937 }
13938 curMaxProcs += numServiceProcs;
13939
13940 // Quit as many processes as we can to get down to the desired
13941 // process count. First remove any processes that no longer
13942 // have activites running in them.
13943 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013944 i<mLruProcesses.size()
13945 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013946 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013947 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013948 // Quit an application only if it is not currently
13949 // running any activities.
13950 if (!app.persistent && app.activities.size() == 0
13951 && app.curReceiver == null && app.services.size() == 0) {
13952 Log.i(
13953 TAG, "Exiting empty application process "
13954 + app.processName + " ("
13955 + (app.thread != null ? app.thread.asBinder() : null)
13956 + ")\n");
13957 if (app.pid > 0 && app.pid != MY_PID) {
13958 Process.killProcess(app.pid);
13959 } else {
13960 try {
13961 app.thread.scheduleExit();
13962 } catch (Exception e) {
13963 // Ignore exceptions.
13964 }
13965 }
13966 // todo: For now we assume the application is not buggy
13967 // or evil, and will quit as a result of our request.
13968 // Eventually we need to drive this off of the death
13969 // notification, and kill the process if it takes too long.
13970 cleanUpApplicationRecordLocked(app, false, i);
13971 i--;
13972 }
13973 }
13974
13975 // If we still have too many processes, now from the least
13976 // recently used process we start finishing activities.
13977 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013978 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013979 " of " + curMaxProcs + " processes");
13980 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013981 i<mLruProcesses.size()
13982 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013983 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013984 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013985 // Quit the application only if we have a state saved for
13986 // all of its activities.
13987 boolean canQuit = !app.persistent && app.curReceiver == null
13988 && app.services.size() == 0
13989 && app.persistentActivities == 0;
13990 int NUMA = app.activities.size();
13991 int j;
13992 if (Config.LOGV) Log.v(
13993 TAG, "Looking to quit " + app.processName);
13994 for (j=0; j<NUMA && canQuit; j++) {
13995 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13996 if (Config.LOGV) Log.v(
13997 TAG, " " + r.intent.getComponent().flattenToShortString()
13998 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13999 canQuit = (r.haveState || !r.stateNotNeeded)
14000 && !r.visible && r.stopped;
14001 }
14002 if (canQuit) {
14003 // Finish all of the activities, and then the app itself.
14004 for (j=0; j<NUMA; j++) {
14005 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14006 if (!r.finishing) {
14007 destroyActivityLocked(r, false);
14008 }
14009 r.resultTo = null;
14010 }
14011 Log.i(TAG, "Exiting application process "
14012 + app.processName + " ("
14013 + (app.thread != null ? app.thread.asBinder() : null)
14014 + ")\n");
14015 if (app.pid > 0 && app.pid != MY_PID) {
14016 Process.killProcess(app.pid);
14017 } else {
14018 try {
14019 app.thread.scheduleExit();
14020 } catch (Exception e) {
14021 // Ignore exceptions.
14022 }
14023 }
14024 // todo: For now we assume the application is not buggy
14025 // or evil, and will quit as a result of our request.
14026 // Eventually we need to drive this off of the death
14027 // notification, and kill the process if it takes too long.
14028 cleanUpApplicationRecordLocked(app, false, i);
14029 i--;
14030 //dump();
14031 }
14032 }
14033
14034 }
14035
14036 int curMaxActivities = MAX_ACTIVITIES;
14037 if (mAlwaysFinishActivities) {
14038 curMaxActivities = 1;
14039 }
14040
14041 // Finally, if there are too many activities now running, try to
14042 // finish as many as we can to get back down to the limit.
14043 for ( i=0;
14044 i<mLRUActivities.size()
14045 && mLRUActivities.size() > curMaxActivities;
14046 i++) {
14047 final HistoryRecord r
14048 = (HistoryRecord)mLRUActivities.get(i);
14049
14050 // We can finish this one if we have its icicle saved and
14051 // it is not persistent.
14052 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14053 && r.stopped && !r.persistent && !r.finishing) {
14054 final int origSize = mLRUActivities.size();
14055 destroyActivityLocked(r, true);
14056
14057 // This will remove it from the LRU list, so keep
14058 // our index at the same value. Note that this check to
14059 // see if the size changes is just paranoia -- if
14060 // something unexpected happens, we don't want to end up
14061 // in an infinite loop.
14062 if (origSize > mLRUActivities.size()) {
14063 i--;
14064 }
14065 }
14066 }
14067 }
14068 }
14069
14070 /** This method sends the specified signal to each of the persistent apps */
14071 public void signalPersistentProcesses(int sig) throws RemoteException {
14072 if (sig != Process.SIGNAL_USR1) {
14073 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14074 }
14075
14076 synchronized (this) {
14077 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14078 != PackageManager.PERMISSION_GRANTED) {
14079 throw new SecurityException("Requires permission "
14080 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14081 }
14082
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014083 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14084 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014085 if (r.thread != null && r.persistent) {
14086 Process.sendSignal(r.pid, sig);
14087 }
14088 }
14089 }
14090 }
14091
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014092 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014093 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014094
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014095 try {
14096 synchronized (this) {
14097 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14098 // its own permission.
14099 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14100 != PackageManager.PERMISSION_GRANTED) {
14101 throw new SecurityException("Requires permission "
14102 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014103 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014104
14105 if (start && fd == null) {
14106 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014107 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014108
14109 ProcessRecord proc = null;
14110 try {
14111 int pid = Integer.parseInt(process);
14112 synchronized (mPidsSelfLocked) {
14113 proc = mPidsSelfLocked.get(pid);
14114 }
14115 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014116 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014117
14118 if (proc == null) {
14119 HashMap<String, SparseArray<ProcessRecord>> all
14120 = mProcessNames.getMap();
14121 SparseArray<ProcessRecord> procs = all.get(process);
14122 if (procs != null && procs.size() > 0) {
14123 proc = procs.valueAt(0);
14124 }
14125 }
14126
14127 if (proc == null || proc.thread == null) {
14128 throw new IllegalArgumentException("Unknown process: " + process);
14129 }
14130
14131 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14132 if (isSecure) {
14133 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14134 throw new SecurityException("Process not debuggable: " + proc);
14135 }
14136 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014137
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014138 proc.thread.profilerControl(start, path, fd);
14139 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014140 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014141 }
14142 } catch (RemoteException e) {
14143 throw new IllegalStateException("Process disappeared");
14144 } finally {
14145 if (fd != null) {
14146 try {
14147 fd.close();
14148 } catch (IOException e) {
14149 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014150 }
14151 }
14152 }
14153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014154 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14155 public void monitor() {
14156 synchronized (this) { }
14157 }
14158}