blob: 31edaf26a35c798873f9c07745eba6e6e9d24637 [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;
1197 uninstallPackageLocked(pkg, uid, restart);
1198 }
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 }
1213 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1214 ServiceManager.addService("activity.services", new ServicesBinder(m));
1215 ServiceManager.addService("activity.senders", new SendersBinder(m));
1216 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1217 ServiceManager.addService("permission", new PermissionController(m));
1218
1219 ApplicationInfo info =
1220 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001221 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001222 mSystemThread.installSystemApplicationInfo(info);
1223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 synchronized (mSelf) {
1225 ProcessRecord app = mSelf.newProcessRecordLocked(
1226 mSystemThread.getApplicationThread(), info,
1227 info.processName);
1228 app.persistent = true;
1229 app.pid = Process.myPid();
1230 app.maxAdj = SYSTEM_ADJ;
1231 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1232 synchronized (mSelf.mPidsSelfLocked) {
1233 mSelf.mPidsSelfLocked.put(app.pid, app);
1234 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001235 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 }
1237 } catch (PackageManager.NameNotFoundException e) {
1238 throw new RuntimeException(
1239 "Unable to find android system package", e);
1240 }
1241 }
1242
1243 public void setWindowManager(WindowManagerService wm) {
1244 mWindowManager = wm;
1245 }
1246
1247 public static final Context main(int factoryTest) {
1248 AThread thr = new AThread();
1249 thr.start();
1250
1251 synchronized (thr) {
1252 while (thr.mService == null) {
1253 try {
1254 thr.wait();
1255 } catch (InterruptedException e) {
1256 }
1257 }
1258 }
1259
1260 ActivityManagerService m = thr.mService;
1261 mSelf = m;
1262 ActivityThread at = ActivityThread.systemMain();
1263 mSystemThread = at;
1264 Context context = at.getSystemContext();
1265 m.mContext = context;
1266 m.mFactoryTest = factoryTest;
1267 PowerManager pm =
1268 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1269 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1270 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1271 m.mLaunchingActivity.setReferenceCounted(false);
1272
1273 m.mBatteryStatsService.publish(context);
1274 m.mUsageStatsService.publish(context);
1275
1276 synchronized (thr) {
1277 thr.mReady = true;
1278 thr.notifyAll();
1279 }
1280
1281 m.startRunning(null, null, null, null);
1282
1283 return context;
1284 }
1285
1286 public static ActivityManagerService self() {
1287 return mSelf;
1288 }
1289
1290 static class AThread extends Thread {
1291 ActivityManagerService mService;
1292 boolean mReady = false;
1293
1294 public AThread() {
1295 super("ActivityManager");
1296 }
1297
1298 public void run() {
1299 Looper.prepare();
1300
1301 android.os.Process.setThreadPriority(
1302 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1303
1304 ActivityManagerService m = new ActivityManagerService();
1305
1306 synchronized (this) {
1307 mService = m;
1308 notifyAll();
1309 }
1310
1311 synchronized (this) {
1312 while (!mReady) {
1313 try {
1314 wait();
1315 } catch (InterruptedException e) {
1316 }
1317 }
1318 }
1319
1320 Looper.loop();
1321 }
1322 }
1323
1324 static class BroadcastsBinder extends Binder {
1325 ActivityManagerService mActivityManagerService;
1326 BroadcastsBinder(ActivityManagerService activityManagerService) {
1327 mActivityManagerService = activityManagerService;
1328 }
1329
1330 @Override
1331 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1332 mActivityManagerService.dumpBroadcasts(pw);
1333 }
1334 }
1335
1336 static class ServicesBinder extends Binder {
1337 ActivityManagerService mActivityManagerService;
1338 ServicesBinder(ActivityManagerService activityManagerService) {
1339 mActivityManagerService = activityManagerService;
1340 }
1341
1342 @Override
1343 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1344 mActivityManagerService.dumpServices(pw);
1345 }
1346 }
1347
1348 static class SendersBinder extends Binder {
1349 ActivityManagerService mActivityManagerService;
1350 SendersBinder(ActivityManagerService activityManagerService) {
1351 mActivityManagerService = activityManagerService;
1352 }
1353
1354 @Override
1355 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1356 mActivityManagerService.dumpSenders(pw);
1357 }
1358 }
1359
1360 static class ProvidersBinder extends Binder {
1361 ActivityManagerService mActivityManagerService;
1362 ProvidersBinder(ActivityManagerService activityManagerService) {
1363 mActivityManagerService = activityManagerService;
1364 }
1365
1366 @Override
1367 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1368 mActivityManagerService.dumpProviders(pw);
1369 }
1370 }
1371
1372 static class MemBinder extends Binder {
1373 ActivityManagerService mActivityManagerService;
1374 MemBinder(ActivityManagerService activityManagerService) {
1375 mActivityManagerService = activityManagerService;
1376 }
1377
1378 @Override
1379 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1380 ActivityManagerService service = mActivityManagerService;
1381 ArrayList<ProcessRecord> procs;
1382 synchronized (mActivityManagerService) {
1383 if (args != null && args.length > 0
1384 && args[0].charAt(0) != '-') {
1385 procs = new ArrayList<ProcessRecord>();
1386 int pid = -1;
1387 try {
1388 pid = Integer.parseInt(args[0]);
1389 } catch (NumberFormatException e) {
1390
1391 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001392 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1393 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 if (proc.pid == pid) {
1395 procs.add(proc);
1396 } else if (proc.processName.equals(args[0])) {
1397 procs.add(proc);
1398 }
1399 }
1400 if (procs.size() <= 0) {
1401 pw.println("No process found for: " + args[0]);
1402 return;
1403 }
1404 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001405 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 }
1407 }
1408 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1409 }
1410 }
1411
1412 static class CpuBinder extends Binder {
1413 ActivityManagerService mActivityManagerService;
1414 CpuBinder(ActivityManagerService activityManagerService) {
1415 mActivityManagerService = activityManagerService;
1416 }
1417
1418 @Override
1419 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1420 synchronized (mActivityManagerService.mProcessStatsThread) {
1421 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1422 }
1423 }
1424 }
1425
1426 private ActivityManagerService() {
1427 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1428 if (v != null && Integer.getInteger(v) != 0) {
1429 mSimpleProcessManagement = true;
1430 }
1431 v = System.getenv("ANDROID_DEBUG_APP");
1432 if (v != null) {
1433 mSimpleProcessManagement = true;
1434 }
1435
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001436 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 MY_PID = Process.myPid();
1439
1440 File dataDir = Environment.getDataDirectory();
1441 File systemDir = new File(dataDir, "system");
1442 systemDir.mkdirs();
1443 mBatteryStatsService = new BatteryStatsService(new File(
1444 systemDir, "batterystats.bin").toString());
1445 mBatteryStatsService.getActiveStatistics().readLocked();
1446 mBatteryStatsService.getActiveStatistics().writeLocked();
1447
1448 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001449 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450
Jack Palevichb90d28c2009-07-22 15:35:24 -07001451 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1452 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 mConfiguration.makeDefault();
1455 mProcessStats.init();
1456
1457 // Add ourself to the Watchdog monitors.
1458 Watchdog.getInstance().addMonitor(this);
1459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 mProcessStatsThread = new Thread("ProcessStats") {
1461 public void run() {
1462 while (true) {
1463 try {
1464 try {
1465 synchronized(this) {
1466 final long now = SystemClock.uptimeMillis();
1467 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1468 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1469 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1470 // + ", write delay=" + nextWriteDelay);
1471 if (nextWriteDelay < nextCpuDelay) {
1472 nextCpuDelay = nextWriteDelay;
1473 }
1474 if (nextCpuDelay > 0) {
1475 this.wait(nextCpuDelay);
1476 }
1477 }
1478 } catch (InterruptedException e) {
1479 }
1480
1481 updateCpuStatsNow();
1482 } catch (Exception e) {
1483 Log.e(TAG, "Unexpected exception collecting process stats", e);
1484 }
1485 }
1486 }
1487 };
1488 mProcessStatsThread.start();
1489 }
1490
1491 @Override
1492 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1493 throws RemoteException {
1494 try {
1495 return super.onTransact(code, data, reply, flags);
1496 } catch (RuntimeException e) {
1497 // The activity manager only throws security exceptions, so let's
1498 // log all others.
1499 if (!(e instanceof SecurityException)) {
1500 Log.e(TAG, "Activity Manager Crash", e);
1501 }
1502 throw e;
1503 }
1504 }
1505
1506 void updateCpuStats() {
1507 synchronized (mProcessStatsThread) {
1508 final long now = SystemClock.uptimeMillis();
1509 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1510 mProcessStatsThread.notify();
1511 }
1512 }
1513 }
1514
1515 void updateCpuStatsNow() {
1516 synchronized (mProcessStatsThread) {
1517 final long now = SystemClock.uptimeMillis();
1518 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 if (MONITOR_CPU_USAGE &&
1521 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1522 mLastCpuTime = now;
1523 haveNewCpuStats = true;
1524 mProcessStats.update();
1525 //Log.i(TAG, mProcessStats.printCurrentState());
1526 //Log.i(TAG, "Total CPU usage: "
1527 // + mProcessStats.getTotalCpuPercent() + "%");
1528
1529 // Log the cpu usage if the property is set.
1530 if ("true".equals(SystemProperties.get("events.cpu"))) {
1531 int user = mProcessStats.getLastUserTime();
1532 int system = mProcessStats.getLastSystemTime();
1533 int iowait = mProcessStats.getLastIoWaitTime();
1534 int irq = mProcessStats.getLastIrqTime();
1535 int softIrq = mProcessStats.getLastSoftIrqTime();
1536 int idle = mProcessStats.getLastIdleTime();
1537
1538 int total = user + system + iowait + irq + softIrq + idle;
1539 if (total == 0) total = 1;
1540
Doug Zongker2bec3d42009-12-04 12:52:44 -08001541 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 ((user+system+iowait+irq+softIrq) * 100) / total,
1543 (user * 100) / total,
1544 (system * 100) / total,
1545 (iowait * 100) / total,
1546 (irq * 100) / total,
1547 (softIrq * 100) / total);
1548 }
1549 }
1550
Amith Yamasanie43530a2009-08-21 13:11:37 -07001551 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001552 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001553 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 synchronized(mPidsSelfLocked) {
1555 if (haveNewCpuStats) {
1556 if (mBatteryStatsService.isOnBattery()) {
1557 final int N = mProcessStats.countWorkingStats();
1558 for (int i=0; i<N; i++) {
1559 ProcessStats.Stats st
1560 = mProcessStats.getWorkingStats(i);
1561 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1562 if (pr != null) {
1563 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1564 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001565 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001566 } else {
1567 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001568 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001569 if (ps != null) {
1570 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001571 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 }
1574 }
1575 }
1576 }
1577 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1580 mLastWriteTime = now;
1581 mBatteryStatsService.getActiveStatistics().writeLocked();
1582 }
1583 }
1584 }
1585 }
1586
1587 /**
1588 * Initialize the application bind args. These are passed to each
1589 * process when the bindApplication() IPC is sent to the process. They're
1590 * lazily setup to make sure the services are running when they're asked for.
1591 */
1592 private HashMap<String, IBinder> getCommonServicesLocked() {
1593 if (mAppBindArgs == null) {
1594 mAppBindArgs = new HashMap<String, IBinder>();
1595
1596 // Setup the application init args
1597 mAppBindArgs.put("package", ServiceManager.getService("package"));
1598 mAppBindArgs.put("window", ServiceManager.getService("window"));
1599 mAppBindArgs.put(Context.ALARM_SERVICE,
1600 ServiceManager.getService(Context.ALARM_SERVICE));
1601 }
1602 return mAppBindArgs;
1603 }
1604
1605 private final void setFocusedActivityLocked(HistoryRecord r) {
1606 if (mFocusedActivity != r) {
1607 mFocusedActivity = r;
1608 mWindowManager.setFocusedApp(r, true);
1609 }
1610 }
1611
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001612 private final void updateLruProcessLocked(ProcessRecord app,
1613 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001615 int lrui = mLruProcesses.indexOf(app);
1616 if (lrui >= 0) mLruProcesses.remove(lrui);
1617
1618 int i = mLruProcesses.size()-1;
1619 int skipTop = 0;
1620
1621 // compute the new weight for this process.
1622 if (updateActivityTime) {
1623 app.lastActivityTime = SystemClock.uptimeMillis();
1624 }
1625 if (app.activities.size() > 0) {
1626 // If this process has activities, we more strongly want to keep
1627 // it around.
1628 app.lruWeight = app.lastActivityTime;
1629 } else if (app.pubProviders.size() > 0) {
1630 // If this process contains content providers, we want to keep
1631 // it a little more strongly.
1632 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1633 // Also don't let it kick out the first few "real" hidden processes.
1634 skipTop = MIN_HIDDEN_APPS;
1635 } else {
1636 // If this process doesn't have activities, we less strongly
1637 // want to keep it around, and generally want to avoid getting
1638 // in front of any very recently used activities.
1639 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1640 // Also don't let it kick out the first few "real" hidden processes.
1641 skipTop = MIN_HIDDEN_APPS;
1642 }
1643 while (i >= 0) {
1644 ProcessRecord p = mLruProcesses.get(i);
1645 // If this app shouldn't be in front of the first N background
1646 // apps, then skip over that many that are currently hidden.
1647 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1648 skipTop--;
1649 }
1650 if (p.lruWeight <= app.lruWeight){
1651 mLruProcesses.add(i+1, app);
1652 break;
1653 }
1654 i--;
1655 }
1656 if (i < 0) {
1657 mLruProcesses.add(0, app);
1658 }
1659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 //Log.i(TAG, "Putting proc to front: " + app.processName);
1661 if (oomAdj) {
1662 updateOomAdjLocked();
1663 }
1664 }
1665
1666 private final boolean updateLRUListLocked(HistoryRecord r) {
1667 final boolean hadit = mLRUActivities.remove(r);
1668 mLRUActivities.add(r);
1669 return hadit;
1670 }
1671
1672 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1673 int i = mHistory.size()-1;
1674 while (i >= 0) {
1675 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1676 if (!r.finishing && r != notTop) {
1677 return r;
1678 }
1679 i--;
1680 }
1681 return null;
1682 }
1683
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001684 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1685 int i = mHistory.size()-1;
1686 while (i >= 0) {
1687 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1688 if (!r.finishing && !r.delayedResume && r != notTop) {
1689 return r;
1690 }
1691 i--;
1692 }
1693 return null;
1694 }
1695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 /**
1697 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001698 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 *
1700 * @param token If non-null, any history records matching this token will be skipped.
1701 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1702 *
1703 * @return Returns the HistoryRecord of the next activity on the stack.
1704 */
1705 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1706 int i = mHistory.size()-1;
1707 while (i >= 0) {
1708 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1709 // Note: the taskId check depends on real taskId fields being non-zero
1710 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1711 return r;
1712 }
1713 i--;
1714 }
1715 return null;
1716 }
1717
1718 private final ProcessRecord getProcessRecordLocked(
1719 String processName, int uid) {
1720 if (uid == Process.SYSTEM_UID) {
1721 // The system gets to run in any process. If there are multiple
1722 // processes with the same uid, just pick the first (this
1723 // should never happen).
1724 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1725 processName);
1726 return procs != null ? procs.valueAt(0) : null;
1727 }
1728 ProcessRecord proc = mProcessNames.get(processName, uid);
1729 return proc;
1730 }
1731
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001732 private void ensurePackageDexOpt(String packageName) {
1733 IPackageManager pm = ActivityThread.getPackageManager();
1734 try {
1735 if (pm.performDexOpt(packageName)) {
1736 mDidDexOpt = true;
1737 }
1738 } catch (RemoteException e) {
1739 }
1740 }
1741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 private boolean isNextTransitionForward() {
1743 int transit = mWindowManager.getPendingAppTransition();
1744 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1745 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1746 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1747 }
1748
1749 private final boolean realStartActivityLocked(HistoryRecord r,
1750 ProcessRecord app, boolean andResume, boolean checkConfig)
1751 throws RemoteException {
1752
1753 r.startFreezingScreenLocked(app, 0);
1754 mWindowManager.setAppVisibility(r, true);
1755
1756 // Have the window manager re-evaluate the orientation of
1757 // the screen based on the new activity order. Note that
1758 // as a result of this, it can call back into the activity
1759 // manager with a new orientation. We don't care about that,
1760 // because the activity is not currently running so we are
1761 // just restarting it anyway.
1762 if (checkConfig) {
1763 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001764 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 r.mayFreezeScreenLocked(app) ? r : null);
1766 updateConfigurationLocked(config, r);
1767 }
1768
1769 r.app = app;
1770
1771 if (localLOGV) Log.v(TAG, "Launching: " + r);
1772
1773 int idx = app.activities.indexOf(r);
1774 if (idx < 0) {
1775 app.activities.add(r);
1776 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001777 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778
1779 try {
1780 if (app.thread == null) {
1781 throw new RemoteException();
1782 }
1783 List<ResultInfo> results = null;
1784 List<Intent> newIntents = null;
1785 if (andResume) {
1786 results = r.results;
1787 newIntents = r.newIntents;
1788 }
1789 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1790 + " icicle=" + r.icicle
1791 + " with results=" + results + " newIntents=" + newIntents
1792 + " andResume=" + andResume);
1793 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001794 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 System.identityHashCode(r),
1796 r.task.taskId, r.shortComponentName);
1797 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001798 if (r.isHomeActivity) {
1799 mHomeProcess = app;
1800 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001801 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001803 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 r.info, r.icicle, results, newIntents, !andResume,
1805 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 } catch (RemoteException e) {
1807 if (r.launchFailed) {
1808 // This is the second time we failed -- finish activity
1809 // and give up.
1810 Log.e(TAG, "Second failure launching "
1811 + r.intent.getComponent().flattenToShortString()
1812 + ", giving up", e);
1813 appDiedLocked(app, app.pid, app.thread);
1814 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1815 "2nd-crash");
1816 return false;
1817 }
1818
1819 // This is the first time we failed -- restart process and
1820 // retry.
1821 app.activities.remove(r);
1822 throw e;
1823 }
1824
1825 r.launchFailed = false;
1826 if (updateLRUListLocked(r)) {
1827 Log.w(TAG, "Activity " + r
1828 + " being launched, but already in LRU list");
1829 }
1830
1831 if (andResume) {
1832 // As part of the process of launching, ActivityThread also performs
1833 // a resume.
1834 r.state = ActivityState.RESUMED;
1835 r.icicle = null;
1836 r.haveState = false;
1837 r.stopped = false;
1838 mResumedActivity = r;
1839 r.task.touchActiveTime();
1840 completeResumeLocked(r);
1841 pauseIfSleepingLocked();
1842 } else {
1843 // This activity is not starting in the resumed state... which
1844 // should look like we asked it to pause+stop (but remain visible),
1845 // and it has done so and reported back the current icicle and
1846 // other state.
1847 r.state = ActivityState.STOPPED;
1848 r.stopped = true;
1849 }
1850
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001851 // Launch the new version setup screen if needed. We do this -after-
1852 // launching the initial activity (that is, home), so that it can have
1853 // a chance to initialize itself while in the background, making the
1854 // switch back to it faster and look better.
1855 startSetupActivityLocked();
1856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 return true;
1858 }
1859
1860 private final void startSpecificActivityLocked(HistoryRecord r,
1861 boolean andResume, boolean checkConfig) {
1862 // Is this activity's application already running?
1863 ProcessRecord app = getProcessRecordLocked(r.processName,
1864 r.info.applicationInfo.uid);
1865
1866 if (r.startTime == 0) {
1867 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001868 if (mInitialStartTime == 0) {
1869 mInitialStartTime = r.startTime;
1870 }
1871 } else if (mInitialStartTime == 0) {
1872 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 }
1874
1875 if (app != null && app.thread != null) {
1876 try {
1877 realStartActivityLocked(r, app, andResume, checkConfig);
1878 return;
1879 } catch (RemoteException e) {
1880 Log.w(TAG, "Exception when starting activity "
1881 + r.intent.getComponent().flattenToShortString(), e);
1882 }
1883
1884 // If a dead object exception was thrown -- fall through to
1885 // restart the application.
1886 }
1887
1888 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001889 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 }
1891
1892 private final ProcessRecord startProcessLocked(String processName,
1893 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001894 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1896 // We don't have to do anything more if:
1897 // (1) There is an existing application record; and
1898 // (2) The caller doesn't think it is dead, OR there is no thread
1899 // object attached to it so we know it couldn't have crashed; and
1900 // (3) There is a pid assigned to it, so it is either starting or
1901 // already running.
1902 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1903 + " app=" + app + " knownToBeDead=" + knownToBeDead
1904 + " thread=" + (app != null ? app.thread : null)
1905 + " pid=" + (app != null ? app.pid : -1));
1906 if (app != null &&
1907 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1908 return app;
1909 }
1910
1911 String hostingNameStr = hostingName != null
1912 ? hostingName.flattenToShortString() : null;
1913
1914 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1915 // If we are in the background, then check to see if this process
1916 // is bad. If so, we will just silently fail.
1917 if (mBadProcesses.get(info.processName, info.uid) != null) {
1918 return null;
1919 }
1920 } else {
1921 // When the user is explicitly starting a process, then clear its
1922 // crash count so that we won't make it bad until they see at
1923 // least one crash dialog again, and make the process good again
1924 // if it had been bad.
1925 mProcessCrashTimes.remove(info.processName, info.uid);
1926 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001927 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 info.processName);
1929 mBadProcesses.remove(info.processName, info.uid);
1930 if (app != null) {
1931 app.bad = false;
1932 }
1933 }
1934 }
1935
1936 if (app == null) {
1937 app = newProcessRecordLocked(null, info, processName);
1938 mProcessNames.put(processName, info.uid, app);
1939 } else {
1940 // If this is a new package in the process, add the package to the list
1941 app.addPackage(info.packageName);
1942 }
1943
1944 // If the system is not ready yet, then hold off on starting this
1945 // process until it is.
1946 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001947 && !isAllowedWhileBooting(info)
1948 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001949 if (!mProcessesOnHold.contains(app)) {
1950 mProcessesOnHold.add(app);
1951 }
1952 return app;
1953 }
1954
1955 startProcessLocked(app, hostingType, hostingNameStr);
1956 return (app.pid != 0) ? app : null;
1957 }
1958
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001959 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1960 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1961 }
1962
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963 private final void startProcessLocked(ProcessRecord app,
1964 String hostingType, String hostingNameStr) {
1965 if (app.pid > 0 && app.pid != MY_PID) {
1966 synchronized (mPidsSelfLocked) {
1967 mPidsSelfLocked.remove(app.pid);
1968 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1969 }
1970 app.pid = 0;
1971 }
1972
1973 mProcessesOnHold.remove(app);
1974
1975 updateCpuStats();
1976
1977 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1978 mProcDeaths[0] = 0;
1979
1980 try {
1981 int uid = app.info.uid;
1982 int[] gids = null;
1983 try {
1984 gids = mContext.getPackageManager().getPackageGids(
1985 app.info.packageName);
1986 } catch (PackageManager.NameNotFoundException e) {
1987 Log.w(TAG, "Unable to retrieve gids", e);
1988 }
1989 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1990 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1991 && mTopComponent != null
1992 && app.processName.equals(mTopComponent.getPackageName())) {
1993 uid = 0;
1994 }
1995 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1996 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1997 uid = 0;
1998 }
1999 }
2000 int debugFlags = 0;
2001 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
2002 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
2003 }
2004 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
2005 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
2006 }
2007 if ("1".equals(SystemProperties.get("debug.assert"))) {
2008 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2009 }
2010 int pid = Process.start("android.app.ActivityThread",
2011 mSimpleProcessManagement ? app.processName : null, uid, uid,
2012 gids, debugFlags, null);
2013 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2014 synchronized (bs) {
2015 if (bs.isOnBattery()) {
2016 app.batteryStats.incStartsLocked();
2017 }
2018 }
2019
Doug Zongker2bec3d42009-12-04 12:52:44 -08002020 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 app.processName, hostingType,
2022 hostingNameStr != null ? hostingNameStr : "");
2023
2024 if (app.persistent) {
2025 Watchdog.getInstance().processStarted(app, app.processName, pid);
2026 }
2027
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002028 StringBuilder buf = mStringBuilder;
2029 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 buf.append("Start proc ");
2031 buf.append(app.processName);
2032 buf.append(" for ");
2033 buf.append(hostingType);
2034 if (hostingNameStr != null) {
2035 buf.append(" ");
2036 buf.append(hostingNameStr);
2037 }
2038 buf.append(": pid=");
2039 buf.append(pid);
2040 buf.append(" uid=");
2041 buf.append(uid);
2042 buf.append(" gids={");
2043 if (gids != null) {
2044 for (int gi=0; gi<gids.length; gi++) {
2045 if (gi != 0) buf.append(", ");
2046 buf.append(gids[gi]);
2047
2048 }
2049 }
2050 buf.append("}");
2051 Log.i(TAG, buf.toString());
2052 if (pid == 0 || pid == MY_PID) {
2053 // Processes are being emulated with threads.
2054 app.pid = MY_PID;
2055 app.removed = false;
2056 mStartingProcesses.add(app);
2057 } else if (pid > 0) {
2058 app.pid = pid;
2059 app.removed = false;
2060 synchronized (mPidsSelfLocked) {
2061 this.mPidsSelfLocked.put(pid, app);
2062 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2063 msg.obj = app;
2064 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2065 }
2066 } else {
2067 app.pid = 0;
2068 RuntimeException e = new RuntimeException(
2069 "Failure starting process " + app.processName
2070 + ": returned pid=" + pid);
2071 Log.e(TAG, e.getMessage(), e);
2072 }
2073 } catch (RuntimeException e) {
2074 // XXX do better error recovery.
2075 app.pid = 0;
2076 Log.e(TAG, "Failure starting process " + app.processName, e);
2077 }
2078 }
2079
2080 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2081 if (mPausingActivity != null) {
2082 RuntimeException e = new RuntimeException();
2083 Log.e(TAG, "Trying to pause when pause is already pending for "
2084 + mPausingActivity, e);
2085 }
2086 HistoryRecord prev = mResumedActivity;
2087 if (prev == null) {
2088 RuntimeException e = new RuntimeException();
2089 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2090 resumeTopActivityLocked(null);
2091 return;
2092 }
2093 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2094 mResumedActivity = null;
2095 mPausingActivity = prev;
2096 mLastPausedActivity = prev;
2097 prev.state = ActivityState.PAUSING;
2098 prev.task.touchActiveTime();
2099
2100 updateCpuStats();
2101
2102 if (prev.app != null && prev.app.thread != null) {
2103 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2104 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002105 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002106 System.identityHashCode(prev),
2107 prev.shortComponentName);
2108 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2109 prev.configChangeFlags);
2110 updateUsageStats(prev, false);
2111 } catch (Exception e) {
2112 // Ignore exception, if process died other code will cleanup.
2113 Log.w(TAG, "Exception thrown during pause", e);
2114 mPausingActivity = null;
2115 mLastPausedActivity = null;
2116 }
2117 } else {
2118 mPausingActivity = null;
2119 mLastPausedActivity = null;
2120 }
2121
2122 // If we are not going to sleep, we want to ensure the device is
2123 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002124 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002125 mLaunchingActivity.acquire();
2126 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2127 // To be safe, don't allow the wake lock to be held for too long.
2128 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2129 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2130 }
2131 }
2132
2133
2134 if (mPausingActivity != null) {
2135 // Have the window manager pause its key dispatching until the new
2136 // activity has started. If we're pausing the activity just because
2137 // the screen is being turned off and the UI is sleeping, don't interrupt
2138 // key dispatch; the same activity will pick it up again on wakeup.
2139 if (!uiSleeping) {
2140 prev.pauseKeyDispatchingLocked();
2141 } else {
2142 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2143 }
2144
2145 // Schedule a pause timeout in case the app doesn't respond.
2146 // We don't give it much time because this directly impacts the
2147 // responsiveness seen by the user.
2148 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2149 msg.obj = prev;
2150 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2151 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2152 } else {
2153 // This activity failed to schedule the
2154 // pause, so just treat it as being paused now.
2155 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2156 resumeTopActivityLocked(null);
2157 }
2158 }
2159
2160 private final void completePauseLocked() {
2161 HistoryRecord prev = mPausingActivity;
2162 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2163
2164 if (prev != null) {
2165 if (prev.finishing) {
2166 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2167 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2168 } else if (prev.app != null) {
2169 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2170 if (prev.waitingVisible) {
2171 prev.waitingVisible = false;
2172 mWaitingVisibleActivities.remove(prev);
2173 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2174 TAG, "Complete pause, no longer waiting: " + prev);
2175 }
2176 if (prev.configDestroy) {
2177 // The previous is being paused because the configuration
2178 // is changing, which means it is actually stopping...
2179 // To juggle the fact that we are also starting a new
2180 // instance right now, we need to first completely stop
2181 // the current instance before starting the new one.
2182 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2183 destroyActivityLocked(prev, true);
2184 } else {
2185 mStoppingActivities.add(prev);
2186 if (mStoppingActivities.size() > 3) {
2187 // If we already have a few activities waiting to stop,
2188 // then give up on things going idle and start clearing
2189 // them out.
2190 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2191 Message msg = Message.obtain();
2192 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2193 mHandler.sendMessage(msg);
2194 }
2195 }
2196 } else {
2197 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2198 prev = null;
2199 }
2200 mPausingActivity = null;
2201 }
2202
Dianne Hackborn55280a92009-05-07 15:53:46 -07002203 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 resumeTopActivityLocked(prev);
2205 } else {
2206 if (mGoingToSleep.isHeld()) {
2207 mGoingToSleep.release();
2208 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002209 if (mShuttingDown) {
2210 notifyAll();
2211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212 }
2213
2214 if (prev != null) {
2215 prev.resumeKeyDispatchingLocked();
2216 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002217
2218 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2219 long diff = 0;
2220 synchronized (mProcessStatsThread) {
2221 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2222 }
2223 if (diff > 0) {
2224 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2225 synchronized (bsi) {
2226 BatteryStatsImpl.Uid.Proc ps =
2227 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2228 prev.info.packageName);
2229 if (ps != null) {
2230 ps.addForegroundTimeLocked(diff);
2231 }
2232 }
2233 }
2234 }
2235 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002236 }
2237
2238 /**
2239 * Once we know that we have asked an application to put an activity in
2240 * the resumed state (either by launching it or explicitly telling it),
2241 * this function updates the rest of our state to match that fact.
2242 */
2243 private final void completeResumeLocked(HistoryRecord next) {
2244 next.idle = false;
2245 next.results = null;
2246 next.newIntents = null;
2247
2248 // schedule an idle timeout in case the app doesn't do it for us.
2249 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2250 msg.obj = next;
2251 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2252
2253 if (false) {
2254 // The activity was never told to pause, so just keep
2255 // things going as-is. To maintain our own state,
2256 // we need to emulate it coming back and saying it is
2257 // idle.
2258 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2259 msg.obj = next;
2260 mHandler.sendMessage(msg);
2261 }
2262
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002263 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002265 next.thumbnail = null;
2266 setFocusedActivityLocked(next);
2267 next.resumeKeyDispatchingLocked();
2268 ensureActivitiesVisibleLocked(null, 0);
2269 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002270 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002271
2272 // Mark the point when the activity is resuming
2273 // TODO: To be more accurate, the mark should be before the onCreate,
2274 // not after the onResume. But for subsequent starts, onResume is fine.
2275 if (next.app != null) {
2276 synchronized (mProcessStatsThread) {
2277 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2278 }
2279 } else {
2280 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2281 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002282 }
2283
2284 /**
2285 * Make sure that all activities that need to be visible (that is, they
2286 * currently can be seen by the user) actually are.
2287 */
2288 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2289 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2290 if (DEBUG_VISBILITY) Log.v(
2291 TAG, "ensureActivitiesVisible behind " + top
2292 + " configChanges=0x" + Integer.toHexString(configChanges));
2293
2294 // If the top activity is not fullscreen, then we need to
2295 // make sure any activities under it are now visible.
2296 final int count = mHistory.size();
2297 int i = count-1;
2298 while (mHistory.get(i) != top) {
2299 i--;
2300 }
2301 HistoryRecord r;
2302 boolean behindFullscreen = false;
2303 for (; i>=0; i--) {
2304 r = (HistoryRecord)mHistory.get(i);
2305 if (DEBUG_VISBILITY) Log.v(
2306 TAG, "Make visible? " + r + " finishing=" + r.finishing
2307 + " state=" + r.state);
2308 if (r.finishing) {
2309 continue;
2310 }
2311
2312 final boolean doThisProcess = onlyThisProcess == null
2313 || onlyThisProcess.equals(r.processName);
2314
2315 // First: if this is not the current activity being started, make
2316 // sure it matches the current configuration.
2317 if (r != starting && doThisProcess) {
2318 ensureActivityConfigurationLocked(r, 0);
2319 }
2320
2321 if (r.app == null || r.app.thread == null) {
2322 if (onlyThisProcess == null
2323 || onlyThisProcess.equals(r.processName)) {
2324 // This activity needs to be visible, but isn't even
2325 // running... get it started, but don't resume it
2326 // at this point.
2327 if (DEBUG_VISBILITY) Log.v(
2328 TAG, "Start and freeze screen for " + r);
2329 if (r != starting) {
2330 r.startFreezingScreenLocked(r.app, configChanges);
2331 }
2332 if (!r.visible) {
2333 if (DEBUG_VISBILITY) Log.v(
2334 TAG, "Starting and making visible: " + r);
2335 mWindowManager.setAppVisibility(r, true);
2336 }
2337 if (r != starting) {
2338 startSpecificActivityLocked(r, false, false);
2339 }
2340 }
2341
2342 } else if (r.visible) {
2343 // If this activity is already visible, then there is nothing
2344 // else to do here.
2345 if (DEBUG_VISBILITY) Log.v(
2346 TAG, "Skipping: already visible at " + r);
2347 r.stopFreezingScreenLocked(false);
2348
2349 } else if (onlyThisProcess == null) {
2350 // This activity is not currently visible, but is running.
2351 // Tell it to become visible.
2352 r.visible = true;
2353 if (r.state != ActivityState.RESUMED && r != starting) {
2354 // If this activity is paused, tell it
2355 // to now show its window.
2356 if (DEBUG_VISBILITY) Log.v(
2357 TAG, "Making visible and scheduling visibility: " + r);
2358 try {
2359 mWindowManager.setAppVisibility(r, true);
2360 r.app.thread.scheduleWindowVisibility(r, true);
2361 r.stopFreezingScreenLocked(false);
2362 } catch (Exception e) {
2363 // Just skip on any failure; we'll make it
2364 // visible when it next restarts.
2365 Log.w(TAG, "Exception thrown making visibile: "
2366 + r.intent.getComponent(), e);
2367 }
2368 }
2369 }
2370
2371 // Aggregate current change flags.
2372 configChanges |= r.configChangeFlags;
2373
2374 if (r.fullscreen) {
2375 // At this point, nothing else needs to be shown
2376 if (DEBUG_VISBILITY) Log.v(
2377 TAG, "Stopping: fullscreen at " + r);
2378 behindFullscreen = true;
2379 i--;
2380 break;
2381 }
2382 }
2383
2384 // Now for any activities that aren't visible to the user, make
2385 // sure they no longer are keeping the screen frozen.
2386 while (i >= 0) {
2387 r = (HistoryRecord)mHistory.get(i);
2388 if (DEBUG_VISBILITY) Log.v(
2389 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2390 + " state=" + r.state
2391 + " behindFullscreen=" + behindFullscreen);
2392 if (!r.finishing) {
2393 if (behindFullscreen) {
2394 if (r.visible) {
2395 if (DEBUG_VISBILITY) Log.v(
2396 TAG, "Making invisible: " + r);
2397 r.visible = false;
2398 try {
2399 mWindowManager.setAppVisibility(r, false);
2400 if ((r.state == ActivityState.STOPPING
2401 || r.state == ActivityState.STOPPED)
2402 && r.app != null && r.app.thread != null) {
2403 if (DEBUG_VISBILITY) Log.v(
2404 TAG, "Scheduling invisibility: " + r);
2405 r.app.thread.scheduleWindowVisibility(r, false);
2406 }
2407 } catch (Exception e) {
2408 // Just skip on any failure; we'll make it
2409 // visible when it next restarts.
2410 Log.w(TAG, "Exception thrown making hidden: "
2411 + r.intent.getComponent(), e);
2412 }
2413 } else {
2414 if (DEBUG_VISBILITY) Log.v(
2415 TAG, "Already invisible: " + r);
2416 }
2417 } else if (r.fullscreen) {
2418 if (DEBUG_VISBILITY) Log.v(
2419 TAG, "Now behindFullscreen: " + r);
2420 behindFullscreen = true;
2421 }
2422 }
2423 i--;
2424 }
2425 }
2426
2427 /**
2428 * Version of ensureActivitiesVisible that can easily be called anywhere.
2429 */
2430 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2431 int configChanges) {
2432 HistoryRecord r = topRunningActivityLocked(null);
2433 if (r != null) {
2434 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2435 }
2436 }
2437
2438 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2439 if (resumed) {
2440 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2441 } else {
2442 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2443 }
2444 }
2445
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002446 private boolean startHomeActivityLocked() {
2447 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2448 && mTopAction == null) {
2449 // We are running in factory test mode, but unable to find
2450 // the factory test app, so just sit around displaying the
2451 // error message and don't try to start anything.
2452 return false;
2453 }
2454 Intent intent = new Intent(
2455 mTopAction,
2456 mTopData != null ? Uri.parse(mTopData) : null);
2457 intent.setComponent(mTopComponent);
2458 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2459 intent.addCategory(Intent.CATEGORY_HOME);
2460 }
2461 ActivityInfo aInfo =
2462 intent.resolveActivityInfo(mContext.getPackageManager(),
2463 STOCK_PM_FLAGS);
2464 if (aInfo != null) {
2465 intent.setComponent(new ComponentName(
2466 aInfo.applicationInfo.packageName, aInfo.name));
2467 // Don't do this if the home app is currently being
2468 // instrumented.
2469 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2470 aInfo.applicationInfo.uid);
2471 if (app == null || app.instrumentationClass == null) {
2472 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2473 startActivityLocked(null, intent, null, null, 0, aInfo,
2474 null, null, 0, 0, 0, false, false);
2475 }
2476 }
2477
2478
2479 return true;
2480 }
2481
2482 /**
2483 * Starts the "new version setup screen" if appropriate.
2484 */
2485 private void startSetupActivityLocked() {
2486 // Only do this once per boot.
2487 if (mCheckedForSetup) {
2488 return;
2489 }
2490
2491 // We will show this screen if the current one is a different
2492 // version than the last one shown, and we are not running in
2493 // low-level factory test mode.
2494 final ContentResolver resolver = mContext.getContentResolver();
2495 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2496 Settings.Secure.getInt(resolver,
2497 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2498 mCheckedForSetup = true;
2499
2500 // See if we should be showing the platform update setup UI.
2501 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2502 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2503 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2504
2505 // We don't allow third party apps to replace this.
2506 ResolveInfo ri = null;
2507 for (int i=0; ris != null && i<ris.size(); i++) {
2508 if ((ris.get(i).activityInfo.applicationInfo.flags
2509 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2510 ri = ris.get(i);
2511 break;
2512 }
2513 }
2514
2515 if (ri != null) {
2516 String vers = ri.activityInfo.metaData != null
2517 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2518 : null;
2519 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2520 vers = ri.activityInfo.applicationInfo.metaData.getString(
2521 Intent.METADATA_SETUP_VERSION);
2522 }
2523 String lastVers = Settings.Secure.getString(
2524 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2525 if (vers != null && !vers.equals(lastVers)) {
2526 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2527 intent.setComponent(new ComponentName(
2528 ri.activityInfo.packageName, ri.activityInfo.name));
2529 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2530 null, null, 0, 0, 0, false, false);
2531 }
2532 }
2533 }
2534 }
2535
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002536 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002537 //Log.i(TAG, "**** REPORT RESUME: " + r);
2538
2539 final int identHash = System.identityHashCode(r);
2540 updateUsageStats(r, true);
2541
2542 int i = mWatchers.beginBroadcast();
2543 while (i > 0) {
2544 i--;
2545 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2546 if (w != null) {
2547 try {
2548 w.activityResuming(identHash);
2549 } catch (RemoteException e) {
2550 }
2551 }
2552 }
2553 mWatchers.finishBroadcast();
2554 }
2555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002556 /**
2557 * Ensure that the top activity in the stack is resumed.
2558 *
2559 * @param prev The previously resumed activity, for when in the process
2560 * of pausing; can be null to call from elsewhere.
2561 *
2562 * @return Returns true if something is being resumed, or false if
2563 * nothing happened.
2564 */
2565 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2566 // Find the first activity that is not finishing.
2567 HistoryRecord next = topRunningActivityLocked(null);
2568
2569 // Remember how we'll process this pause/resume situation, and ensure
2570 // that the state is reset however we wind up proceeding.
2571 final boolean userLeaving = mUserLeaving;
2572 mUserLeaving = false;
2573
2574 if (next == null) {
2575 // There are no more activities! Let's just start up the
2576 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002577 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002578 }
2579
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002580 next.delayedResume = false;
2581
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002582 // If the top activity is the resumed one, nothing to do.
2583 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2584 // Make sure we have executed any pending transitions, since there
2585 // should be nothing left to do at this point.
2586 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002587 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002588 return false;
2589 }
2590
2591 // If we are sleeping, and there is no resumed activity, and the top
2592 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002593 if ((mSleeping || mShuttingDown)
2594 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002595 // Make sure we have executed any pending transitions, since there
2596 // should be nothing left to do at this point.
2597 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002598 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002599 return false;
2600 }
2601
2602 // The activity may be waiting for stop, but that is no longer
2603 // appropriate for it.
2604 mStoppingActivities.remove(next);
2605 mWaitingVisibleActivities.remove(next);
2606
2607 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2608
2609 // If we are currently pausing an activity, then don't do anything
2610 // until that is done.
2611 if (mPausingActivity != null) {
2612 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2613 return false;
2614 }
2615
2616 // We need to start pausing the current activity so the top one
2617 // can be resumed...
2618 if (mResumedActivity != null) {
2619 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2620 startPausingLocked(userLeaving, false);
2621 return true;
2622 }
2623
2624 if (prev != null && prev != next) {
2625 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2626 prev.waitingVisible = true;
2627 mWaitingVisibleActivities.add(prev);
2628 if (DEBUG_SWITCH) Log.v(
2629 TAG, "Resuming top, waiting visible to hide: " + prev);
2630 } else {
2631 // The next activity is already visible, so hide the previous
2632 // activity's windows right now so we can show the new one ASAP.
2633 // We only do this if the previous is finishing, which should mean
2634 // it is on top of the one being resumed so hiding it quickly
2635 // is good. Otherwise, we want to do the normal route of allowing
2636 // the resumed activity to be shown so we can decide if the
2637 // previous should actually be hidden depending on whether the
2638 // new one is found to be full-screen or not.
2639 if (prev.finishing) {
2640 mWindowManager.setAppVisibility(prev, false);
2641 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2642 + prev + ", waitingVisible="
2643 + (prev != null ? prev.waitingVisible : null)
2644 + ", nowVisible=" + next.nowVisible);
2645 } else {
2646 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2647 + prev + ", waitingVisible="
2648 + (prev != null ? prev.waitingVisible : null)
2649 + ", nowVisible=" + next.nowVisible);
2650 }
2651 }
2652 }
2653
2654 // We are starting up the next activity, so tell the window manager
2655 // that the previous one will be hidden soon. This way it can know
2656 // to ignore it when computing the desired screen orientation.
2657 if (prev != null) {
2658 if (prev.finishing) {
2659 if (DEBUG_TRANSITION) Log.v(TAG,
2660 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002661 if (mNoAnimActivities.contains(prev)) {
2662 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2663 } else {
2664 mWindowManager.prepareAppTransition(prev.task == next.task
2665 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2666 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2667 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002668 mWindowManager.setAppWillBeHidden(prev);
2669 mWindowManager.setAppVisibility(prev, false);
2670 } else {
2671 if (DEBUG_TRANSITION) Log.v(TAG,
2672 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002673 if (mNoAnimActivities.contains(next)) {
2674 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2675 } else {
2676 mWindowManager.prepareAppTransition(prev.task == next.task
2677 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2678 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2679 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 }
2681 if (false) {
2682 mWindowManager.setAppWillBeHidden(prev);
2683 mWindowManager.setAppVisibility(prev, false);
2684 }
2685 } else if (mHistory.size() > 1) {
2686 if (DEBUG_TRANSITION) Log.v(TAG,
2687 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002688 if (mNoAnimActivities.contains(next)) {
2689 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2690 } else {
2691 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2692 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002693 }
2694
2695 if (next.app != null && next.app.thread != null) {
2696 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2697
2698 // This activity is now becoming visible.
2699 mWindowManager.setAppVisibility(next, true);
2700
2701 HistoryRecord lastResumedActivity = mResumedActivity;
2702 ActivityState lastState = next.state;
2703
2704 updateCpuStats();
2705
2706 next.state = ActivityState.RESUMED;
2707 mResumedActivity = next;
2708 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002709 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002710 updateLRUListLocked(next);
2711
2712 // Have the window manager re-evaluate the orientation of
2713 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002714 boolean updated;
2715 synchronized (this) {
2716 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2717 mConfiguration,
2718 next.mayFreezeScreenLocked(next.app) ? next : null);
2719 if (config != null) {
2720 /*
2721 * Explicitly restore the locale to the one from the
2722 * old configuration, since the one that comes back from
2723 * the window manager has the default (boot) locale.
2724 *
2725 * It looks like previously the locale picker only worked
2726 * by coincidence: usually it would do its setting of
2727 * the locale after the activity transition, so it didn't
2728 * matter that this lost it. With the synchronized
2729 * block now keeping them from happening at the same time,
2730 * this one always would happen second and undo what the
2731 * locale picker had just done.
2732 */
2733 config.locale = mConfiguration.locale;
2734 next.frozenBeforeDestroy = true;
2735 }
2736 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002738 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002739 // The configuration update wasn't able to keep the existing
2740 // instance of the activity, and instead started a new one.
2741 // We should be all done, but let's just make sure our activity
2742 // is still at the top and schedule another run if something
2743 // weird happened.
2744 HistoryRecord nextNext = topRunningActivityLocked(null);
2745 if (DEBUG_SWITCH) Log.i(TAG,
2746 "Activity config changed during resume: " + next
2747 + ", new next: " + nextNext);
2748 if (nextNext != next) {
2749 // Do over!
2750 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2751 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002752 setFocusedActivityLocked(next);
2753 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002754 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002755 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002756 return true;
2757 }
2758
2759 try {
2760 // Deliver all pending results.
2761 ArrayList a = next.results;
2762 if (a != null) {
2763 final int N = a.size();
2764 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002765 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002766 TAG, "Delivering results to " + next
2767 + ": " + a);
2768 next.app.thread.scheduleSendResult(next, a);
2769 }
2770 }
2771
2772 if (next.newIntents != null) {
2773 next.app.thread.scheduleNewIntent(next.newIntents, next);
2774 }
2775
Doug Zongker2bec3d42009-12-04 12:52:44 -08002776 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002777 System.identityHashCode(next),
2778 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002779
2780 next.app.thread.scheduleResumeActivity(next,
2781 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002783 pauseIfSleepingLocked();
2784
2785 } catch (Exception e) {
2786 // Whoops, need to restart this activity!
2787 next.state = lastState;
2788 mResumedActivity = lastResumedActivity;
2789 if (Config.LOGD) Log.d(TAG,
2790 "Restarting because process died: " + next);
2791 if (!next.hasBeenLaunched) {
2792 next.hasBeenLaunched = true;
2793 } else {
2794 if (SHOW_APP_STARTING_ICON) {
2795 mWindowManager.setAppStartingWindow(
2796 next, next.packageName, next.theme,
2797 next.nonLocalizedLabel,
2798 next.labelRes, next.icon, null, true);
2799 }
2800 }
2801 startSpecificActivityLocked(next, true, false);
2802 return true;
2803 }
2804
2805 // From this point on, if something goes wrong there is no way
2806 // to recover the activity.
2807 try {
2808 next.visible = true;
2809 completeResumeLocked(next);
2810 } catch (Exception e) {
2811 // If any exception gets thrown, toss away this
2812 // activity and try the next one.
2813 Log.w(TAG, "Exception thrown during resume of " + next, e);
2814 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2815 "resume-exception");
2816 return true;
2817 }
2818
2819 // Didn't need to use the icicle, and it is now out of date.
2820 next.icicle = null;
2821 next.haveState = false;
2822 next.stopped = false;
2823
2824 } else {
2825 // Whoops, need to restart this activity!
2826 if (!next.hasBeenLaunched) {
2827 next.hasBeenLaunched = true;
2828 } else {
2829 if (SHOW_APP_STARTING_ICON) {
2830 mWindowManager.setAppStartingWindow(
2831 next, next.packageName, next.theme,
2832 next.nonLocalizedLabel,
2833 next.labelRes, next.icon, null, true);
2834 }
2835 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2836 }
2837 startSpecificActivityLocked(next, true, true);
2838 }
2839
2840 return true;
2841 }
2842
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002843 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2844 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002845 final int NH = mHistory.size();
2846
2847 int addPos = -1;
2848
2849 if (!newTask) {
2850 // If starting in an existing task, find where that is...
2851 HistoryRecord next = null;
2852 boolean startIt = true;
2853 for (int i = NH-1; i >= 0; i--) {
2854 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2855 if (p.finishing) {
2856 continue;
2857 }
2858 if (p.task == r.task) {
2859 // Here it is! Now, if this is not yet visible to the
2860 // user, then just add it without starting; it will
2861 // get started when the user navigates back to it.
2862 addPos = i+1;
2863 if (!startIt) {
2864 mHistory.add(addPos, r);
2865 r.inHistory = true;
2866 r.task.numActivities++;
2867 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2868 r.info.screenOrientation, r.fullscreen);
2869 if (VALIDATE_TOKENS) {
2870 mWindowManager.validateAppTokens(mHistory);
2871 }
2872 return;
2873 }
2874 break;
2875 }
2876 if (p.fullscreen) {
2877 startIt = false;
2878 }
2879 next = p;
2880 }
2881 }
2882
2883 // Place a new activity at top of stack, so it is next to interact
2884 // with the user.
2885 if (addPos < 0) {
2886 addPos = mHistory.size();
2887 }
2888
2889 // If we are not placing the new activity frontmost, we do not want
2890 // to deliver the onUserLeaving callback to the actual frontmost
2891 // activity
2892 if (addPos < NH) {
2893 mUserLeaving = false;
2894 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2895 }
2896
2897 // Slot the activity into the history stack and proceed
2898 mHistory.add(addPos, r);
2899 r.inHistory = true;
2900 r.frontOfTask = newTask;
2901 r.task.numActivities++;
2902 if (NH > 0) {
2903 // We want to show the starting preview window if we are
2904 // switching to a new task, or the next activity's process is
2905 // not currently running.
2906 boolean showStartingIcon = newTask;
2907 ProcessRecord proc = r.app;
2908 if (proc == null) {
2909 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2910 }
2911 if (proc == null || proc.thread == null) {
2912 showStartingIcon = true;
2913 }
2914 if (DEBUG_TRANSITION) Log.v(TAG,
2915 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002916 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2917 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2918 mNoAnimActivities.add(r);
2919 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2920 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2921 mNoAnimActivities.remove(r);
2922 } else {
2923 mWindowManager.prepareAppTransition(newTask
2924 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2925 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2926 mNoAnimActivities.remove(r);
2927 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002928 mWindowManager.addAppToken(
2929 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2930 boolean doShow = true;
2931 if (newTask) {
2932 // Even though this activity is starting fresh, we still need
2933 // to reset it to make sure we apply affinities to move any
2934 // existing activities from other tasks in to it.
2935 // If the caller has requested that the target task be
2936 // reset, then do so.
2937 if ((r.intent.getFlags()
2938 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2939 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002940 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002941 }
2942 }
2943 if (SHOW_APP_STARTING_ICON && doShow) {
2944 // Figure out if we are transitioning from another activity that is
2945 // "has the same starting icon" as the next one. This allows the
2946 // window manager to keep the previous window it had previously
2947 // created, if it still had one.
2948 HistoryRecord prev = mResumedActivity;
2949 if (prev != null) {
2950 // We don't want to reuse the previous starting preview if:
2951 // (1) The current activity is in a different task.
2952 if (prev.task != r.task) prev = null;
2953 // (2) The current activity is already displayed.
2954 else if (prev.nowVisible) prev = null;
2955 }
2956 mWindowManager.setAppStartingWindow(
2957 r, r.packageName, r.theme, r.nonLocalizedLabel,
2958 r.labelRes, r.icon, prev, showStartingIcon);
2959 }
2960 } else {
2961 // If this is the first activity, don't do any fancy animations,
2962 // because there is nothing for it to animate on top of.
2963 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2964 r.info.screenOrientation, r.fullscreen);
2965 }
2966 if (VALIDATE_TOKENS) {
2967 mWindowManager.validateAppTokens(mHistory);
2968 }
2969
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002970 if (doResume) {
2971 resumeTopActivityLocked(null);
2972 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002973 }
2974
2975 /**
2976 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002977 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2978 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002979 * an instance of that activity in the stack and, if found, finish all
2980 * activities on top of it and return the instance.
2981 *
2982 * @param newR Description of the new activity being started.
2983 * @return Returns the old activity that should be continue to be used,
2984 * or null if none was found.
2985 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002986 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002987 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002988 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002989
2990 // First find the requested task.
2991 while (i > 0) {
2992 i--;
2993 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2994 if (r.task.taskId == taskId) {
2995 i++;
2996 break;
2997 }
2998 }
2999
3000 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003001 while (i > 0) {
3002 i--;
3003 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3004 if (r.finishing) {
3005 continue;
3006 }
3007 if (r.task.taskId != taskId) {
3008 return null;
3009 }
3010 if (r.realActivity.equals(newR.realActivity)) {
3011 // Here it is! Now finish everything in front...
3012 HistoryRecord ret = r;
3013 if (doClear) {
3014 while (i < (mHistory.size()-1)) {
3015 i++;
3016 r = (HistoryRecord)mHistory.get(i);
3017 if (r.finishing) {
3018 continue;
3019 }
3020 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
3021 null, "clear")) {
3022 i--;
3023 }
3024 }
3025 }
3026
3027 // Finally, if this is a normal launch mode (that is, not
3028 // expecting onNewIntent()), then we will finish the current
3029 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003030 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3031 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003032 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003033 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 if (index >= 0) {
3035 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3036 null, "clear");
3037 }
3038 return null;
3039 }
3040 }
3041
3042 return ret;
3043 }
3044 }
3045
3046 return null;
3047 }
3048
3049 /**
3050 * Find the activity in the history stack within the given task. Returns
3051 * the index within the history at which it's found, or < 0 if not found.
3052 */
3053 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3054 int i = mHistory.size();
3055 while (i > 0) {
3056 i--;
3057 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3058 if (candidate.task.taskId != task) {
3059 break;
3060 }
3061 if (candidate.realActivity.equals(r.realActivity)) {
3062 return i;
3063 }
3064 }
3065
3066 return -1;
3067 }
3068
3069 /**
3070 * Reorder the history stack so that the activity at the given index is
3071 * brought to the front.
3072 */
3073 private final HistoryRecord moveActivityToFrontLocked(int where) {
3074 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3075 int top = mHistory.size();
3076 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3077 mHistory.add(top, newTop);
3078 oldTop.frontOfTask = false;
3079 newTop.frontOfTask = true;
3080 return newTop;
3081 }
3082
3083 /**
3084 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3085 * method will be called at the proper time.
3086 */
3087 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3088 boolean sent = false;
3089 if (r.state == ActivityState.RESUMED
3090 && r.app != null && r.app.thread != null) {
3091 try {
3092 ArrayList<Intent> ar = new ArrayList<Intent>();
3093 ar.add(new Intent(intent));
3094 r.app.thread.scheduleNewIntent(ar, r);
3095 sent = true;
3096 } catch (Exception e) {
3097 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3098 }
3099 }
3100 if (!sent) {
3101 r.addNewIntentLocked(new Intent(intent));
3102 }
3103 }
3104
3105 private final void logStartActivity(int tag, HistoryRecord r,
3106 TaskRecord task) {
3107 EventLog.writeEvent(tag,
3108 System.identityHashCode(r), task.taskId,
3109 r.shortComponentName, r.intent.getAction(),
3110 r.intent.getType(), r.intent.getDataString(),
3111 r.intent.getFlags());
3112 }
3113
3114 private final int startActivityLocked(IApplicationThread caller,
3115 Intent intent, String resolvedType,
3116 Uri[] grantedUriPermissions,
3117 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3118 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003119 int callingPid, int callingUid, boolean onlyIfNeeded,
3120 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003121 Log.i(TAG, "Starting activity: " + intent);
3122
3123 HistoryRecord sourceRecord = null;
3124 HistoryRecord resultRecord = null;
3125 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003126 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003127 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3129 if (index >= 0) {
3130 sourceRecord = (HistoryRecord)mHistory.get(index);
3131 if (requestCode >= 0 && !sourceRecord.finishing) {
3132 resultRecord = sourceRecord;
3133 }
3134 }
3135 }
3136
3137 int launchFlags = intent.getFlags();
3138
3139 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3140 && sourceRecord != null) {
3141 // Transfer the result target from the source activity to the new
3142 // one being started, including any failures.
3143 if (requestCode >= 0) {
3144 return START_FORWARD_AND_REQUEST_CONFLICT;
3145 }
3146 resultRecord = sourceRecord.resultTo;
3147 resultWho = sourceRecord.resultWho;
3148 requestCode = sourceRecord.requestCode;
3149 sourceRecord.resultTo = null;
3150 if (resultRecord != null) {
3151 resultRecord.removeResultsLocked(
3152 sourceRecord, resultWho, requestCode);
3153 }
3154 }
3155
3156 int err = START_SUCCESS;
3157
3158 if (intent.getComponent() == null) {
3159 // We couldn't find a class that can handle the given Intent.
3160 // That's the end of that!
3161 err = START_INTENT_NOT_RESOLVED;
3162 }
3163
3164 if (err == START_SUCCESS && aInfo == null) {
3165 // We couldn't find the specific class specified in the Intent.
3166 // Also the end of the line.
3167 err = START_CLASS_NOT_FOUND;
3168 }
3169
3170 ProcessRecord callerApp = null;
3171 if (err == START_SUCCESS && caller != null) {
3172 callerApp = getRecordForAppLocked(caller);
3173 if (callerApp != null) {
3174 callingPid = callerApp.pid;
3175 callingUid = callerApp.info.uid;
3176 } else {
3177 Log.w(TAG, "Unable to find app for caller " + caller
3178 + " (pid=" + callingPid + ") when starting: "
3179 + intent.toString());
3180 err = START_PERMISSION_DENIED;
3181 }
3182 }
3183
3184 if (err != START_SUCCESS) {
3185 if (resultRecord != null) {
3186 sendActivityResultLocked(-1,
3187 resultRecord, resultWho, requestCode,
3188 Activity.RESULT_CANCELED, null);
3189 }
3190 return err;
3191 }
3192
3193 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3194 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3195 if (perm != PackageManager.PERMISSION_GRANTED) {
3196 if (resultRecord != null) {
3197 sendActivityResultLocked(-1,
3198 resultRecord, resultWho, requestCode,
3199 Activity.RESULT_CANCELED, null);
3200 }
3201 String msg = "Permission Denial: starting " + intent.toString()
3202 + " from " + callerApp + " (pid=" + callingPid
3203 + ", uid=" + callingUid + ")"
3204 + " requires " + aInfo.permission;
3205 Log.w(TAG, msg);
3206 throw new SecurityException(msg);
3207 }
3208
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003209 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210 boolean abort = false;
3211 try {
3212 // The Intent we give to the watcher has the extra data
3213 // stripped off, since it can contain private information.
3214 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003215 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 aInfo.applicationInfo.packageName);
3217 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003218 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003219 }
3220
3221 if (abort) {
3222 if (resultRecord != null) {
3223 sendActivityResultLocked(-1,
3224 resultRecord, resultWho, requestCode,
3225 Activity.RESULT_CANCELED, null);
3226 }
3227 // We pretend to the caller that it was really started, but
3228 // they will just get a cancel result.
3229 return START_SUCCESS;
3230 }
3231 }
3232
3233 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3234 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003235 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003237 if (mResumedActivity == null
3238 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3239 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3240 PendingActivityLaunch pal = new PendingActivityLaunch();
3241 pal.r = r;
3242 pal.sourceRecord = sourceRecord;
3243 pal.grantedUriPermissions = grantedUriPermissions;
3244 pal.grantedMode = grantedMode;
3245 pal.onlyIfNeeded = onlyIfNeeded;
3246 mPendingActivityLaunches.add(pal);
3247 return START_SWITCHES_CANCELED;
3248 }
3249 }
3250
3251 if (mDidAppSwitch) {
3252 // This is the second allowed switch since we stopped switches,
3253 // so now just generally allow switches. Use case: user presses
3254 // home (switches disabled, switch to home, mDidAppSwitch now true);
3255 // user taps a home icon (coming from home so allowed, we hit here
3256 // and now allow anyone to switch again).
3257 mAppSwitchesAllowedTime = 0;
3258 } else {
3259 mDidAppSwitch = true;
3260 }
3261
3262 doPendingActivityLaunchesLocked(false);
3263
3264 return startActivityUncheckedLocked(r, sourceRecord,
3265 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3266 }
3267
3268 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3269 final int N = mPendingActivityLaunches.size();
3270 if (N <= 0) {
3271 return;
3272 }
3273 for (int i=0; i<N; i++) {
3274 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3275 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3276 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3277 doResume && i == (N-1));
3278 }
3279 mPendingActivityLaunches.clear();
3280 }
3281
3282 private final int startActivityUncheckedLocked(HistoryRecord r,
3283 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3284 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3285 final Intent intent = r.intent;
3286 final int callingUid = r.launchedFromUid;
3287
3288 int launchFlags = intent.getFlags();
3289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003290 // We'll invoke onUserLeaving before onPause only if the launching
3291 // activity did not explicitly state that this is an automated launch.
3292 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3293 if (DEBUG_USER_LEAVING) Log.v(TAG,
3294 "startActivity() => mUserLeaving=" + mUserLeaving);
3295
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003296 // If the caller has asked not to resume at this point, we make note
3297 // of this in the record so that we can skip it when trying to find
3298 // the top running activity.
3299 if (!doResume) {
3300 r.delayedResume = true;
3301 }
3302
3303 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3304 != 0 ? r : null;
3305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003306 // If the onlyIfNeeded flag is set, then we can do this if the activity
3307 // being launched is the same as the one making the call... or, as
3308 // a special case, if we do not know the caller then we count the
3309 // current top activity as the caller.
3310 if (onlyIfNeeded) {
3311 HistoryRecord checkedCaller = sourceRecord;
3312 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003313 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003314 }
3315 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3316 // Caller is not the same as launcher, so always needed.
3317 onlyIfNeeded = false;
3318 }
3319 }
3320
3321 if (grantedUriPermissions != null && callingUid > 0) {
3322 for (int i=0; i<grantedUriPermissions.length; i++) {
3323 grantUriPermissionLocked(callingUid, r.packageName,
3324 grantedUriPermissions[i], grantedMode, r);
3325 }
3326 }
3327
3328 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3329 intent, r);
3330
3331 if (sourceRecord == null) {
3332 // This activity is not being started from another... in this
3333 // case we -always- start a new task.
3334 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3335 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3336 + intent);
3337 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3338 }
3339 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3340 // The original activity who is starting us is running as a single
3341 // instance... this new activity it is starting must go on its
3342 // own task.
3343 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3344 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3345 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3346 // The activity being started is a single instance... it always
3347 // gets launched into its own task.
3348 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3349 }
3350
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003351 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 // For whatever reason this activity is being launched into a new
3353 // task... yet the caller has requested a result back. Well, that
3354 // is pretty messed up, so instead immediately send back a cancel
3355 // and let the new task continue launched as normal without a
3356 // dependency on its originator.
3357 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3358 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003359 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003360 Activity.RESULT_CANCELED, null);
3361 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 }
3363
3364 boolean addingToTask = false;
3365 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3366 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3367 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3368 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3369 // If bring to front is requested, and no result is requested, and
3370 // we can find a task that was started with this same
3371 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003372 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003373 // See if there is a task to bring to the front. If this is
3374 // a SINGLE_INSTANCE activity, there can be one and only one
3375 // instance of it in the history, and it is always in its own
3376 // unique task, so we do a special search.
3377 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3378 ? findTaskLocked(intent, r.info)
3379 : findActivityLocked(intent, r.info);
3380 if (taskTop != null) {
3381 if (taskTop.task.intent == null) {
3382 // This task was started because of movement of
3383 // the activity based on affinity... now that we
3384 // are actually launching it, we can assign the
3385 // base intent.
3386 taskTop.task.setIntent(intent, r.info);
3387 }
3388 // If the target task is not in the front, then we need
3389 // to bring it to the front... except... well, with
3390 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3391 // to have the same behavior as if a new instance was
3392 // being started, which means not bringing it to the front
3393 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003394 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 if (curTop.task != taskTop.task) {
3396 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3397 boolean callerAtFront = sourceRecord == null
3398 || curTop.task == sourceRecord.task;
3399 if (callerAtFront) {
3400 // We really do want to push this one into the
3401 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003402 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 }
3404 }
3405 // If the caller has requested that the target task be
3406 // reset, then do so.
3407 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3408 taskTop = resetTaskIfNeededLocked(taskTop, r);
3409 }
3410 if (onlyIfNeeded) {
3411 // We don't need to start a new activity, and
3412 // the client said not to do anything if that
3413 // is the case, so this is it! And for paranoia, make
3414 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003415 if (doResume) {
3416 resumeTopActivityLocked(null);
3417 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003418 return START_RETURN_INTENT_TO_CALLER;
3419 }
3420 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3421 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3422 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3423 // In this situation we want to remove all activities
3424 // from the task up to the one being started. In most
3425 // cases this means we are resetting the task to its
3426 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003427 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003428 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003429 if (top != null) {
3430 if (top.frontOfTask) {
3431 // Activity aliases may mean we use different
3432 // intents for the top activity, so make sure
3433 // the task now has the identity of the new
3434 // intent.
3435 top.task.setIntent(r.intent, r.info);
3436 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003437 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003438 deliverNewIntentLocked(top, r.intent);
3439 } else {
3440 // A special case: we need to
3441 // start the activity because it is not currently
3442 // running, and the caller has asked to clear the
3443 // current task to have this activity at the top.
3444 addingToTask = true;
3445 // Now pretend like this activity is being started
3446 // by the top of its task, so it is put in the
3447 // right place.
3448 sourceRecord = taskTop;
3449 }
3450 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3451 // In this case the top activity on the task is the
3452 // same as the one being launched, so we take that
3453 // as a request to bring the task to the foreground.
3454 // If the top activity in the task is the root
3455 // activity, deliver this new intent to it if it
3456 // desires.
3457 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3458 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003459 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 if (taskTop.frontOfTask) {
3461 taskTop.task.setIntent(r.intent, r.info);
3462 }
3463 deliverNewIntentLocked(taskTop, r.intent);
3464 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3465 // In this case we are launching the root activity
3466 // of the task, but with a different intent. We
3467 // should start a new instance on top.
3468 addingToTask = true;
3469 sourceRecord = taskTop;
3470 }
3471 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3472 // In this case an activity is being launched in to an
3473 // existing task, without resetting that task. This
3474 // is typically the situation of launching an activity
3475 // from a notification or shortcut. We want to place
3476 // the new activity on top of the current task.
3477 addingToTask = true;
3478 sourceRecord = taskTop;
3479 } else if (!taskTop.task.rootWasReset) {
3480 // In this case we are launching in to an existing task
3481 // that has not yet been started from its front door.
3482 // The current task has been brought to the front.
3483 // Ideally, we'd probably like to place this new task
3484 // at the bottom of its stack, but that's a little hard
3485 // to do with the current organization of the code so
3486 // for now we'll just drop it.
3487 taskTop.task.setIntent(r.intent, r.info);
3488 }
3489 if (!addingToTask) {
3490 // We didn't do anything... but it was needed (a.k.a., client
3491 // don't use that intent!) And for paranoia, make
3492 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003493 if (doResume) {
3494 resumeTopActivityLocked(null);
3495 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003496 return START_TASK_TO_FRONT;
3497 }
3498 }
3499 }
3500 }
3501
3502 //String uri = r.intent.toURI();
3503 //Intent intent2 = new Intent(uri);
3504 //Log.i(TAG, "Given intent: " + r.intent);
3505 //Log.i(TAG, "URI is: " + uri);
3506 //Log.i(TAG, "To intent: " + intent2);
3507
3508 if (r.packageName != null) {
3509 // If the activity being launched is the same as the one currently
3510 // at the top, then we need to check if it should only be launched
3511 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003512 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3513 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 if (top.realActivity.equals(r.realActivity)) {
3515 if (top.app != null && top.app.thread != null) {
3516 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3517 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3518 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003519 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 // For paranoia, make sure we have correctly
3521 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003522 if (doResume) {
3523 resumeTopActivityLocked(null);
3524 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 if (onlyIfNeeded) {
3526 // We don't need to start a new activity, and
3527 // the client said not to do anything if that
3528 // is the case, so this is it!
3529 return START_RETURN_INTENT_TO_CALLER;
3530 }
3531 deliverNewIntentLocked(top, r.intent);
3532 return START_DELIVERED_TO_TOP;
3533 }
3534 }
3535 }
3536 }
3537
3538 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003539 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003540 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003541 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 Activity.RESULT_CANCELED, null);
3543 }
3544 return START_CLASS_NOT_FOUND;
3545 }
3546
3547 boolean newTask = false;
3548
3549 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003550 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003551 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3552 // todo: should do better management of integers.
3553 mCurTask++;
3554 if (mCurTask <= 0) {
3555 mCurTask = 1;
3556 }
3557 r.task = new TaskRecord(mCurTask, r.info, intent,
3558 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3559 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3560 + " in new task " + r.task);
3561 newTask = true;
3562 addRecentTask(r.task);
3563
3564 } else if (sourceRecord != null) {
3565 if (!addingToTask &&
3566 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3567 // In this case, we are adding the activity to an existing
3568 // task, but the caller has asked to clear that task if the
3569 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003570 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003571 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003573 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003574 deliverNewIntentLocked(top, r.intent);
3575 // For paranoia, make sure we have correctly
3576 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003577 if (doResume) {
3578 resumeTopActivityLocked(null);
3579 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580 return START_DELIVERED_TO_TOP;
3581 }
3582 } else if (!addingToTask &&
3583 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3584 // In this case, we are launching an activity in our own task
3585 // that may already be running somewhere in the history, and
3586 // we want to shuffle it to the front of the stack if so.
3587 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3588 if (where >= 0) {
3589 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003590 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003592 if (doResume) {
3593 resumeTopActivityLocked(null);
3594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003595 return START_DELIVERED_TO_TOP;
3596 }
3597 }
3598 // An existing activity is starting this new activity, so we want
3599 // to keep the new one in the same task as the one that is starting
3600 // it.
3601 r.task = sourceRecord.task;
3602 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3603 + " in existing task " + r.task);
3604
3605 } else {
3606 // This not being started from an existing activity, and not part
3607 // of a new task... just put it in the top task, though these days
3608 // this case should never happen.
3609 final int N = mHistory.size();
3610 HistoryRecord prev =
3611 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3612 r.task = prev != null
3613 ? prev.task
3614 : new TaskRecord(mCurTask, r.info, intent,
3615 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3616 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3617 + " in new guessed " + r.task);
3618 }
3619 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003620 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003621 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003622 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003623 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 return START_SUCCESS;
3625 }
3626
3627 public final int startActivity(IApplicationThread caller,
3628 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3629 int grantedMode, IBinder resultTo,
3630 String resultWho, int requestCode, boolean onlyIfNeeded,
3631 boolean debug) {
3632 // Refuse possible leaked file descriptors
3633 if (intent != null && intent.hasFileDescriptors()) {
3634 throw new IllegalArgumentException("File descriptors passed in Intent");
3635 }
3636
The Android Open Source Project4df24232009-03-05 14:34:35 -08003637 final boolean componentSpecified = intent.getComponent() != null;
3638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003639 // Don't modify the client's object!
3640 intent = new Intent(intent);
3641
3642 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003643 ActivityInfo aInfo;
3644 try {
3645 ResolveInfo rInfo =
3646 ActivityThread.getPackageManager().resolveIntent(
3647 intent, resolvedType,
3648 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003649 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 aInfo = rInfo != null ? rInfo.activityInfo : null;
3651 } catch (RemoteException e) {
3652 aInfo = null;
3653 }
3654
3655 if (aInfo != null) {
3656 // Store the found target back into the intent, because now that
3657 // we have it we never want to do this again. For example, if the
3658 // user navigates back to this point in the history, we should
3659 // always restart the exact same activity.
3660 intent.setComponent(new ComponentName(
3661 aInfo.applicationInfo.packageName, aInfo.name));
3662
3663 // Don't debug things in the system process
3664 if (debug) {
3665 if (!aInfo.processName.equals("system")) {
3666 setDebugApp(aInfo.processName, true, false);
3667 }
3668 }
3669 }
3670
3671 synchronized(this) {
3672 final long origId = Binder.clearCallingIdentity();
3673 int res = startActivityLocked(caller, intent, resolvedType,
3674 grantedUriPermissions, grantedMode, aInfo,
3675 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003676 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003677 Binder.restoreCallingIdentity(origId);
3678 return res;
3679 }
3680 }
3681
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003682 public int startActivityIntentSender(IApplicationThread caller,
3683 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003684 IBinder resultTo, String resultWho, int requestCode,
3685 int flagsMask, int flagsValues) {
3686 // Refuse possible leaked file descriptors
3687 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3688 throw new IllegalArgumentException("File descriptors passed in Intent");
3689 }
3690
3691 IIntentSender sender = intent.getTarget();
3692 if (!(sender instanceof PendingIntentRecord)) {
3693 throw new IllegalArgumentException("Bad PendingIntent object");
3694 }
3695
3696 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003697
3698 synchronized (this) {
3699 // If this is coming from the currently resumed activity, it is
3700 // effectively saying that app switches are allowed at this point.
3701 if (mResumedActivity != null
3702 && mResumedActivity.info.applicationInfo.uid ==
3703 Binder.getCallingUid()) {
3704 mAppSwitchesAllowedTime = 0;
3705 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003706 }
3707
3708 return pir.sendInner(0, fillInIntent, resolvedType,
3709 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3710 }
3711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003712 public boolean startNextMatchingActivity(IBinder callingActivity,
3713 Intent intent) {
3714 // Refuse possible leaked file descriptors
3715 if (intent != null && intent.hasFileDescriptors() == true) {
3716 throw new IllegalArgumentException("File descriptors passed in Intent");
3717 }
3718
3719 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003720 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003721 if (index < 0) {
3722 return false;
3723 }
3724 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3725 if (r.app == null || r.app.thread == null) {
3726 // The caller is not running... d'oh!
3727 return false;
3728 }
3729 intent = new Intent(intent);
3730 // The caller is not allowed to change the data.
3731 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3732 // And we are resetting to find the next component...
3733 intent.setComponent(null);
3734
3735 ActivityInfo aInfo = null;
3736 try {
3737 List<ResolveInfo> resolves =
3738 ActivityThread.getPackageManager().queryIntentActivities(
3739 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003740 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003741
3742 // Look for the original activity in the list...
3743 final int N = resolves != null ? resolves.size() : 0;
3744 for (int i=0; i<N; i++) {
3745 ResolveInfo rInfo = resolves.get(i);
3746 if (rInfo.activityInfo.packageName.equals(r.packageName)
3747 && rInfo.activityInfo.name.equals(r.info.name)) {
3748 // We found the current one... the next matching is
3749 // after it.
3750 i++;
3751 if (i<N) {
3752 aInfo = resolves.get(i).activityInfo;
3753 }
3754 break;
3755 }
3756 }
3757 } catch (RemoteException e) {
3758 }
3759
3760 if (aInfo == null) {
3761 // Nobody who is next!
3762 return false;
3763 }
3764
3765 intent.setComponent(new ComponentName(
3766 aInfo.applicationInfo.packageName, aInfo.name));
3767 intent.setFlags(intent.getFlags()&~(
3768 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3769 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3770 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3771 Intent.FLAG_ACTIVITY_NEW_TASK));
3772
3773 // Okay now we need to start the new activity, replacing the
3774 // currently running activity. This is a little tricky because
3775 // we want to start the new one as if the current one is finished,
3776 // but not finish the current one first so that there is no flicker.
3777 // And thus...
3778 final boolean wasFinishing = r.finishing;
3779 r.finishing = true;
3780
3781 // Propagate reply information over to the new activity.
3782 final HistoryRecord resultTo = r.resultTo;
3783 final String resultWho = r.resultWho;
3784 final int requestCode = r.requestCode;
3785 r.resultTo = null;
3786 if (resultTo != null) {
3787 resultTo.removeResultsLocked(r, resultWho, requestCode);
3788 }
3789
3790 final long origId = Binder.clearCallingIdentity();
3791 // XXX we are not dealing with propagating grantedUriPermissions...
3792 // those are not yet exposed to user code, so there is no need.
3793 int res = startActivityLocked(r.app.thread, intent,
3794 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003795 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796 Binder.restoreCallingIdentity(origId);
3797
3798 r.finishing = wasFinishing;
3799 if (res != START_SUCCESS) {
3800 return false;
3801 }
3802 return true;
3803 }
3804 }
3805
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003806 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003807 Intent intent, String resolvedType, IBinder resultTo,
3808 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003809
3810 // This is so super not safe, that only the system (or okay root)
3811 // can do it.
3812 final int callingUid = Binder.getCallingUid();
3813 if (callingUid != 0 && callingUid != Process.myUid()) {
3814 throw new SecurityException(
3815 "startActivityInPackage only available to the system");
3816 }
3817
The Android Open Source Project4df24232009-03-05 14:34:35 -08003818 final boolean componentSpecified = intent.getComponent() != null;
3819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003820 // Don't modify the client's object!
3821 intent = new Intent(intent);
3822
3823 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003824 ActivityInfo aInfo;
3825 try {
3826 ResolveInfo rInfo =
3827 ActivityThread.getPackageManager().resolveIntent(
3828 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003829 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 aInfo = rInfo != null ? rInfo.activityInfo : null;
3831 } catch (RemoteException e) {
3832 aInfo = null;
3833 }
3834
3835 if (aInfo != null) {
3836 // Store the found target back into the intent, because now that
3837 // we have it we never want to do this again. For example, if the
3838 // user navigates back to this point in the history, we should
3839 // always restart the exact same activity.
3840 intent.setComponent(new ComponentName(
3841 aInfo.applicationInfo.packageName, aInfo.name));
3842 }
3843
3844 synchronized(this) {
3845 return startActivityLocked(null, intent, resolvedType,
3846 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003847 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003848 }
3849 }
3850
3851 private final void addRecentTask(TaskRecord task) {
3852 // Remove any existing entries that are the same kind of task.
3853 int N = mRecentTasks.size();
3854 for (int i=0; i<N; i++) {
3855 TaskRecord tr = mRecentTasks.get(i);
3856 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3857 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3858 mRecentTasks.remove(i);
3859 i--;
3860 N--;
3861 if (task.intent == null) {
3862 // If the new recent task we are adding is not fully
3863 // specified, then replace it with the existing recent task.
3864 task = tr;
3865 }
3866 }
3867 }
3868 if (N >= MAX_RECENT_TASKS) {
3869 mRecentTasks.remove(N-1);
3870 }
3871 mRecentTasks.add(0, task);
3872 }
3873
3874 public void setRequestedOrientation(IBinder token,
3875 int requestedOrientation) {
3876 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003877 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003878 if (index < 0) {
3879 return;
3880 }
3881 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3882 final long origId = Binder.clearCallingIdentity();
3883 mWindowManager.setAppOrientation(r, requestedOrientation);
3884 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003885 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003886 r.mayFreezeScreenLocked(r.app) ? r : null);
3887 if (config != null) {
3888 r.frozenBeforeDestroy = true;
3889 if (!updateConfigurationLocked(config, r)) {
3890 resumeTopActivityLocked(null);
3891 }
3892 }
3893 Binder.restoreCallingIdentity(origId);
3894 }
3895 }
3896
3897 public int getRequestedOrientation(IBinder token) {
3898 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003899 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003900 if (index < 0) {
3901 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3902 }
3903 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3904 return mWindowManager.getAppOrientation(r);
3905 }
3906 }
3907
3908 private final void stopActivityLocked(HistoryRecord r) {
3909 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3910 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3911 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3912 if (!r.finishing) {
3913 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3914 "no-history");
3915 }
3916 } else if (r.app != null && r.app.thread != null) {
3917 if (mFocusedActivity == r) {
3918 setFocusedActivityLocked(topRunningActivityLocked(null));
3919 }
3920 r.resumeKeyDispatchingLocked();
3921 try {
3922 r.stopped = false;
3923 r.state = ActivityState.STOPPING;
3924 if (DEBUG_VISBILITY) Log.v(
3925 TAG, "Stopping visible=" + r.visible + " for " + r);
3926 if (!r.visible) {
3927 mWindowManager.setAppVisibility(r, false);
3928 }
3929 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3930 } catch (Exception e) {
3931 // Maybe just ignore exceptions here... if the process
3932 // has crashed, our death notification will clean things
3933 // up.
3934 Log.w(TAG, "Exception thrown during pause", e);
3935 // Just in case, assume it to be stopped.
3936 r.stopped = true;
3937 r.state = ActivityState.STOPPED;
3938 if (r.configDestroy) {
3939 destroyActivityLocked(r, true);
3940 }
3941 }
3942 }
3943 }
3944
3945 /**
3946 * @return Returns true if the activity is being finished, false if for
3947 * some reason it is being left as-is.
3948 */
3949 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3950 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003951 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003952 TAG, "Finishing activity: token=" + token
3953 + ", result=" + resultCode + ", data=" + resultData);
3954
Dianne Hackborn75b03852009-06-12 15:43:26 -07003955 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003956 if (index < 0) {
3957 return false;
3958 }
3959 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3960
3961 // Is this the last activity left?
3962 boolean lastActivity = true;
3963 for (int i=mHistory.size()-1; i>=0; i--) {
3964 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3965 if (!p.finishing && p != r) {
3966 lastActivity = false;
3967 break;
3968 }
3969 }
3970
3971 // If this is the last activity, but it is the home activity, then
3972 // just don't finish it.
3973 if (lastActivity) {
3974 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3975 return false;
3976 }
3977 }
3978
3979 finishActivityLocked(r, index, resultCode, resultData, reason);
3980 return true;
3981 }
3982
3983 /**
3984 * @return Returns true if this activity has been removed from the history
3985 * list, or false if it is still in the list and will be removed later.
3986 */
3987 private final boolean finishActivityLocked(HistoryRecord r, int index,
3988 int resultCode, Intent resultData, String reason) {
3989 if (r.finishing) {
3990 Log.w(TAG, "Duplicate finish request for " + r);
3991 return false;
3992 }
3993
3994 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003995 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003996 System.identityHashCode(r),
3997 r.task.taskId, r.shortComponentName, reason);
3998 r.task.numActivities--;
3999 if (r.frontOfTask && index < (mHistory.size()-1)) {
4000 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
4001 if (next.task == r.task) {
4002 next.frontOfTask = true;
4003 }
4004 }
4005
4006 r.pauseKeyDispatchingLocked();
4007 if (mFocusedActivity == r) {
4008 setFocusedActivityLocked(topRunningActivityLocked(null));
4009 }
4010
4011 // send the result
4012 HistoryRecord resultTo = r.resultTo;
4013 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07004014 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
4015 + " who=" + r.resultWho + " req=" + r.requestCode
4016 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004017 if (r.info.applicationInfo.uid > 0) {
4018 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
4019 r.packageName, resultData, r);
4020 }
4021 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
4022 resultData);
4023 r.resultTo = null;
4024 }
Chris Tate8a7dc172009-03-24 20:11:42 -07004025 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004026
4027 // Make sure this HistoryRecord is not holding on to other resources,
4028 // because clients have remote IPC references to this object so we
4029 // can't assume that will go away and want to avoid circular IPC refs.
4030 r.results = null;
4031 r.pendingResults = null;
4032 r.newIntents = null;
4033 r.icicle = null;
4034
4035 if (mPendingThumbnails.size() > 0) {
4036 // There are clients waiting to receive thumbnails so, in case
4037 // this is an activity that someone is waiting for, add it
4038 // to the pending list so we can correctly update the clients.
4039 mCancelledThumbnails.add(r);
4040 }
4041
4042 if (mResumedActivity == r) {
4043 boolean endTask = index <= 0
4044 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4045 if (DEBUG_TRANSITION) Log.v(TAG,
4046 "Prepare close transition: finishing " + r);
4047 mWindowManager.prepareAppTransition(endTask
4048 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4049 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4050
4051 // Tell window manager to prepare for this one to be removed.
4052 mWindowManager.setAppVisibility(r, false);
4053
4054 if (mPausingActivity == null) {
4055 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4056 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4057 startPausingLocked(false, false);
4058 }
4059
4060 } else if (r.state != ActivityState.PAUSING) {
4061 // If the activity is PAUSING, we will complete the finish once
4062 // it is done pausing; else we can just directly finish it here.
4063 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4064 return finishCurrentActivityLocked(r, index,
4065 FINISH_AFTER_PAUSE) == null;
4066 } else {
4067 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4068 }
4069
4070 return false;
4071 }
4072
4073 private static final int FINISH_IMMEDIATELY = 0;
4074 private static final int FINISH_AFTER_PAUSE = 1;
4075 private static final int FINISH_AFTER_VISIBLE = 2;
4076
4077 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4078 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004079 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004080 if (index < 0) {
4081 return null;
4082 }
4083
4084 return finishCurrentActivityLocked(r, index, mode);
4085 }
4086
4087 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4088 int index, int mode) {
4089 // First things first: if this activity is currently visible,
4090 // and the resumed activity is not yet visible, then hold off on
4091 // finishing until the resumed one becomes visible.
4092 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4093 if (!mStoppingActivities.contains(r)) {
4094 mStoppingActivities.add(r);
4095 if (mStoppingActivities.size() > 3) {
4096 // If we already have a few activities waiting to stop,
4097 // then give up on things going idle and start clearing
4098 // them out.
4099 Message msg = Message.obtain();
4100 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4101 mHandler.sendMessage(msg);
4102 }
4103 }
4104 r.state = ActivityState.STOPPING;
4105 updateOomAdjLocked();
4106 return r;
4107 }
4108
4109 // make sure the record is cleaned out of other places.
4110 mStoppingActivities.remove(r);
4111 mWaitingVisibleActivities.remove(r);
4112 if (mResumedActivity == r) {
4113 mResumedActivity = null;
4114 }
4115 final ActivityState prevState = r.state;
4116 r.state = ActivityState.FINISHING;
4117
4118 if (mode == FINISH_IMMEDIATELY
4119 || prevState == ActivityState.STOPPED
4120 || prevState == ActivityState.INITIALIZING) {
4121 // If this activity is already stopped, we can just finish
4122 // it right now.
4123 return destroyActivityLocked(r, true) ? null : r;
4124 } else {
4125 // Need to go through the full pause cycle to get this
4126 // activity into the stopped state and then finish it.
4127 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4128 mFinishingActivities.add(r);
4129 resumeTopActivityLocked(null);
4130 }
4131 return r;
4132 }
4133
4134 /**
4135 * This is the internal entry point for handling Activity.finish().
4136 *
4137 * @param token The Binder token referencing the Activity we want to finish.
4138 * @param resultCode Result code, if any, from this Activity.
4139 * @param resultData Result data (Intent), if any, from this Activity.
4140 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004141 * @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 -08004142 */
4143 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4144 // Refuse possible leaked file descriptors
4145 if (resultData != null && resultData.hasFileDescriptors() == true) {
4146 throw new IllegalArgumentException("File descriptors passed in Intent");
4147 }
4148
4149 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004150 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004151 // Find the first activity that is not finishing.
4152 HistoryRecord next = topRunningActivityLocked(token, 0);
4153 if (next != null) {
4154 // ask watcher if this is allowed
4155 boolean resumeOK = true;
4156 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004157 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004158 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004159 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004160 }
4161
4162 if (!resumeOK) {
4163 return false;
4164 }
4165 }
4166 }
4167 final long origId = Binder.clearCallingIdentity();
4168 boolean res = requestFinishActivityLocked(token, resultCode,
4169 resultData, "app-request");
4170 Binder.restoreCallingIdentity(origId);
4171 return res;
4172 }
4173 }
4174
4175 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4176 String resultWho, int requestCode, int resultCode, Intent data) {
4177
4178 if (callingUid > 0) {
4179 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4180 data, r);
4181 }
4182
The Android Open Source Project10592532009-03-18 17:39:46 -07004183 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4184 + " : who=" + resultWho + " req=" + requestCode
4185 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004186 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4187 try {
4188 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4189 list.add(new ResultInfo(resultWho, requestCode,
4190 resultCode, data));
4191 r.app.thread.scheduleSendResult(r, list);
4192 return;
4193 } catch (Exception e) {
4194 Log.w(TAG, "Exception thrown sending result to " + r, e);
4195 }
4196 }
4197
4198 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4199 }
4200
4201 public final void finishSubActivity(IBinder token, String resultWho,
4202 int requestCode) {
4203 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004204 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004205 if (index < 0) {
4206 return;
4207 }
4208 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4209
4210 final long origId = Binder.clearCallingIdentity();
4211
4212 int i;
4213 for (i=mHistory.size()-1; i>=0; i--) {
4214 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4215 if (r.resultTo == self && r.requestCode == requestCode) {
4216 if ((r.resultWho == null && resultWho == null) ||
4217 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4218 finishActivityLocked(r, i,
4219 Activity.RESULT_CANCELED, null, "request-sub");
4220 }
4221 }
4222 }
4223
4224 Binder.restoreCallingIdentity(origId);
4225 }
4226 }
4227
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004228 public void overridePendingTransition(IBinder token, String packageName,
4229 int enterAnim, int exitAnim) {
4230 synchronized(this) {
4231 int index = indexOfTokenLocked(token);
4232 if (index < 0) {
4233 return;
4234 }
4235 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4236
4237 final long origId = Binder.clearCallingIdentity();
4238
4239 if (self.state == ActivityState.RESUMED
4240 || self.state == ActivityState.PAUSING) {
4241 mWindowManager.overridePendingAppTransition(packageName,
4242 enterAnim, exitAnim);
4243 }
4244
4245 Binder.restoreCallingIdentity(origId);
4246 }
4247 }
4248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004249 /**
4250 * Perform clean-up of service connections in an activity record.
4251 */
4252 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4253 // Throw away any services that have been bound by this activity.
4254 if (r.connections != null) {
4255 Iterator<ConnectionRecord> it = r.connections.iterator();
4256 while (it.hasNext()) {
4257 ConnectionRecord c = it.next();
4258 removeConnectionLocked(c, null, r);
4259 }
4260 r.connections = null;
4261 }
4262 }
4263
4264 /**
4265 * Perform the common clean-up of an activity record. This is called both
4266 * as part of destroyActivityLocked() (when destroying the client-side
4267 * representation) and cleaning things up as a result of its hosting
4268 * processing going away, in which case there is no remaining client-side
4269 * state to destroy so only the cleanup here is needed.
4270 */
4271 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4272 if (mResumedActivity == r) {
4273 mResumedActivity = null;
4274 }
4275 if (mFocusedActivity == r) {
4276 mFocusedActivity = null;
4277 }
4278
4279 r.configDestroy = false;
4280 r.frozenBeforeDestroy = false;
4281
4282 // Make sure this record is no longer in the pending finishes list.
4283 // This could happen, for example, if we are trimming activities
4284 // down to the max limit while they are still waiting to finish.
4285 mFinishingActivities.remove(r);
4286 mWaitingVisibleActivities.remove(r);
4287
4288 // Remove any pending results.
4289 if (r.finishing && r.pendingResults != null) {
4290 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4291 PendingIntentRecord rec = apr.get();
4292 if (rec != null) {
4293 cancelIntentSenderLocked(rec, false);
4294 }
4295 }
4296 r.pendingResults = null;
4297 }
4298
4299 if (cleanServices) {
4300 cleanUpActivityServicesLocked(r);
4301 }
4302
4303 if (mPendingThumbnails.size() > 0) {
4304 // There are clients waiting to receive thumbnails so, in case
4305 // this is an activity that someone is waiting for, add it
4306 // to the pending list so we can correctly update the clients.
4307 mCancelledThumbnails.add(r);
4308 }
4309
4310 // Get rid of any pending idle timeouts.
4311 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4312 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4313 }
4314
4315 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4316 if (r.state != ActivityState.DESTROYED) {
4317 mHistory.remove(r);
4318 r.inHistory = false;
4319 r.state = ActivityState.DESTROYED;
4320 mWindowManager.removeAppToken(r);
4321 if (VALIDATE_TOKENS) {
4322 mWindowManager.validateAppTokens(mHistory);
4323 }
4324 cleanUpActivityServicesLocked(r);
4325 removeActivityUriPermissionsLocked(r);
4326 }
4327 }
4328
4329 /**
4330 * Destroy the current CLIENT SIDE instance of an activity. This may be
4331 * called both when actually finishing an activity, or when performing
4332 * a configuration switch where we destroy the current client-side object
4333 * but then create a new client-side object for this same HistoryRecord.
4334 */
4335 private final boolean destroyActivityLocked(HistoryRecord r,
4336 boolean removeFromApp) {
4337 if (DEBUG_SWITCH) Log.v(
4338 TAG, "Removing activity: token=" + r
4339 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004340 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004341 System.identityHashCode(r),
4342 r.task.taskId, r.shortComponentName);
4343
4344 boolean removedFromHistory = false;
4345
4346 cleanUpActivityLocked(r, false);
4347
4348 if (r.app != null) {
4349 if (removeFromApp) {
4350 int idx = r.app.activities.indexOf(r);
4351 if (idx >= 0) {
4352 r.app.activities.remove(idx);
4353 }
4354 if (r.persistent) {
4355 decPersistentCountLocked(r.app);
4356 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004357 if (r.app.activities.size() == 0) {
4358 // No longer have activities, so update location in
4359 // LRU list.
4360 updateLruProcessLocked(r.app, true, false);
4361 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004362 }
4363
4364 boolean skipDestroy = false;
4365
4366 try {
4367 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4368 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4369 r.configChangeFlags);
4370 } catch (Exception e) {
4371 // We can just ignore exceptions here... if the process
4372 // has crashed, our death notification will clean things
4373 // up.
4374 //Log.w(TAG, "Exception thrown during finish", e);
4375 if (r.finishing) {
4376 removeActivityFromHistoryLocked(r);
4377 removedFromHistory = true;
4378 skipDestroy = true;
4379 }
4380 }
4381
4382 r.app = null;
4383 r.nowVisible = false;
4384
4385 if (r.finishing && !skipDestroy) {
4386 r.state = ActivityState.DESTROYING;
4387 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4388 msg.obj = r;
4389 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4390 } else {
4391 r.state = ActivityState.DESTROYED;
4392 }
4393 } else {
4394 // remove this record from the history.
4395 if (r.finishing) {
4396 removeActivityFromHistoryLocked(r);
4397 removedFromHistory = true;
4398 } else {
4399 r.state = ActivityState.DESTROYED;
4400 }
4401 }
4402
4403 r.configChangeFlags = 0;
4404
4405 if (!mLRUActivities.remove(r)) {
4406 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4407 }
4408
4409 return removedFromHistory;
4410 }
4411
4412 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4413 ProcessRecord app)
4414 {
4415 int i = list.size();
4416 if (localLOGV) Log.v(
4417 TAG, "Removing app " + app + " from list " + list
4418 + " with " + i + " entries");
4419 while (i > 0) {
4420 i--;
4421 HistoryRecord r = (HistoryRecord)list.get(i);
4422 if (localLOGV) Log.v(
4423 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4424 if (r.app == app) {
4425 if (localLOGV) Log.v(TAG, "Removing this entry!");
4426 list.remove(i);
4427 }
4428 }
4429 }
4430
4431 /**
4432 * Main function for removing an existing process from the activity manager
4433 * as a result of that process going away. Clears out all connections
4434 * to the process.
4435 */
4436 private final void handleAppDiedLocked(ProcessRecord app,
4437 boolean restarting) {
4438 cleanUpApplicationRecordLocked(app, restarting, -1);
4439 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004440 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004441 }
4442
4443 // Just in case...
4444 if (mPausingActivity != null && mPausingActivity.app == app) {
4445 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4446 mPausingActivity = null;
4447 }
4448 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4449 mLastPausedActivity = null;
4450 }
4451
4452 // Remove this application's activities from active lists.
4453 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4454 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4455 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4456 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4457
4458 boolean atTop = true;
4459 boolean hasVisibleActivities = false;
4460
4461 // Clean out the history list.
4462 int i = mHistory.size();
4463 if (localLOGV) Log.v(
4464 TAG, "Removing app " + app + " from history with " + i + " entries");
4465 while (i > 0) {
4466 i--;
4467 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4468 if (localLOGV) Log.v(
4469 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4470 if (r.app == app) {
4471 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4472 if (localLOGV) Log.v(
4473 TAG, "Removing this entry! frozen=" + r.haveState
4474 + " finishing=" + r.finishing);
4475 mHistory.remove(i);
4476
4477 r.inHistory = false;
4478 mWindowManager.removeAppToken(r);
4479 if (VALIDATE_TOKENS) {
4480 mWindowManager.validateAppTokens(mHistory);
4481 }
4482 removeActivityUriPermissionsLocked(r);
4483
4484 } else {
4485 // We have the current state for this activity, so
4486 // it can be restarted later when needed.
4487 if (localLOGV) Log.v(
4488 TAG, "Keeping entry, setting app to null");
4489 if (r.visible) {
4490 hasVisibleActivities = true;
4491 }
4492 r.app = null;
4493 r.nowVisible = false;
4494 if (!r.haveState) {
4495 r.icicle = null;
4496 }
4497 }
4498
4499 cleanUpActivityLocked(r, true);
4500 r.state = ActivityState.STOPPED;
4501 }
4502 atTop = false;
4503 }
4504
4505 app.activities.clear();
4506
4507 if (app.instrumentationClass != null) {
4508 Log.w(TAG, "Crash of app " + app.processName
4509 + " running instrumentation " + app.instrumentationClass);
4510 Bundle info = new Bundle();
4511 info.putString("shortMsg", "Process crashed.");
4512 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4513 }
4514
4515 if (!restarting) {
4516 if (!resumeTopActivityLocked(null)) {
4517 // If there was nothing to resume, and we are not already
4518 // restarting this process, but there is a visible activity that
4519 // is hosted by the process... then make sure all visible
4520 // activities are running, taking care of restarting this
4521 // process.
4522 if (hasVisibleActivities) {
4523 ensureActivitiesVisibleLocked(null, 0);
4524 }
4525 }
4526 }
4527 }
4528
4529 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4530 IBinder threadBinder = thread.asBinder();
4531
4532 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004533 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4534 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004535 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4536 return i;
4537 }
4538 }
4539 return -1;
4540 }
4541
4542 private final ProcessRecord getRecordForAppLocked(
4543 IApplicationThread thread) {
4544 if (thread == null) {
4545 return null;
4546 }
4547
4548 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004549 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004550 }
4551
4552 private final void appDiedLocked(ProcessRecord app, int pid,
4553 IApplicationThread thread) {
4554
4555 mProcDeaths[0]++;
4556
4557 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4558 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4559 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004560 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004561 if (localLOGV) Log.v(
4562 TAG, "Dying app: " + app + ", pid: " + pid
4563 + ", thread: " + thread.asBinder());
4564 boolean doLowMem = app.instrumentationClass == null;
4565 handleAppDiedLocked(app, false);
4566
4567 if (doLowMem) {
4568 // If there are no longer any background processes running,
4569 // and the app that died was not running instrumentation,
4570 // then tell everyone we are now low on memory.
4571 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004572 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4573 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004574 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4575 haveBg = true;
4576 break;
4577 }
4578 }
4579
4580 if (!haveBg) {
4581 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004582 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004583 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004584 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4585 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004586 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004587 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4588 // The low memory report is overriding any current
4589 // state for a GC request. Make sure to do
4590 // visible/foreground processes first.
4591 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4592 rec.lastRequestedGc = 0;
4593 } else {
4594 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004595 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004596 rec.reportLowMemory = true;
4597 rec.lastLowMemory = now;
4598 mProcessesToGc.remove(rec);
4599 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004600 }
4601 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004602 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004603 }
4604 }
4605 } else if (Config.LOGD) {
4606 Log.d(TAG, "Received spurious death notification for thread "
4607 + thread.asBinder());
4608 }
4609 }
4610
4611 final String readFile(String filename) {
4612 try {
4613 FileInputStream fs = new FileInputStream(filename);
4614 byte[] inp = new byte[8192];
4615 int size = fs.read(inp);
4616 fs.close();
4617 return new String(inp, 0, 0, size);
4618 } catch (java.io.IOException e) {
4619 }
4620 return "";
4621 }
4622
4623 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004624 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004625 if (app.notResponding || app.crashing) {
4626 return;
4627 }
4628
4629 // Log the ANR to the event log.
Doug Zongker2bec3d42009-12-04 12:52:44 -08004630 EventLog.writeEvent(EventLogTags.ANR, app.pid, app.processName, annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004631
4632 // If we are on a secure build and the application is not interesting to the user (it is
4633 // not visible or in the background), just kill it instead of displaying a dialog.
4634 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4635 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4636 Process.killProcess(app.pid);
4637 return;
4638 }
4639
4640 // DeviceMonitor.start();
4641
4642 String processInfo = null;
4643 if (MONITOR_CPU_USAGE) {
4644 updateCpuStatsNow();
4645 synchronized (mProcessStatsThread) {
4646 processInfo = mProcessStats.printCurrentState();
4647 }
4648 }
4649
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004650 StringBuilder info = mStringBuilder;
4651 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004652 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004653 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004654 if (reportedActivity != null && reportedActivity.app != null) {
4655 info.append(" (last in ");
4656 info.append(reportedActivity.app.processName);
4657 info.append(")");
4658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004659 if (annotation != null) {
4660 info.append("\nAnnotation: ");
4661 info.append(annotation);
4662 }
4663 if (MONITOR_CPU_USAGE) {
4664 info.append("\nCPU usage:\n");
4665 info.append(processInfo);
4666 }
4667 Log.i(TAG, info.toString());
4668
4669 // The application is not responding. Dump as many thread traces as we can.
4670 boolean fileDump = prepareTraceFile(true);
4671 if (!fileDump) {
4672 // Dumping traces to the log, just dump the process that isn't responding so
4673 // we don't overflow the log
4674 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4675 } else {
4676 // Dumping traces to a file so dump all active processes we know about
4677 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004678 // First, these are the most important processes.
4679 final int[] imppids = new int[3];
4680 int i=0;
4681 imppids[0] = app.pid;
4682 i++;
4683 if (reportedActivity != null && reportedActivity.app != null
4684 && reportedActivity.app.thread != null
4685 && reportedActivity.app.pid != app.pid) {
4686 imppids[i] = reportedActivity.app.pid;
4687 i++;
4688 }
4689 imppids[i] = Process.myPid();
4690 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4691 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4692 synchronized (this) {
4693 try {
4694 wait(200);
4695 } catch (InterruptedException e) {
4696 }
4697 }
4698 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004699 for (i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
4700 ProcessRecord r = mLruProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004701 boolean done = false;
4702 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4703 if (imppids[j] == r.pid) {
4704 done = true;
4705 break;
4706 }
4707 }
4708 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004709 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004710 synchronized (this) {
4711 try {
4712 wait(200);
4713 } catch (InterruptedException e) {
4714 }
4715 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004716 }
4717 }
4718 }
4719 }
4720
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004721 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004722 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004723 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004724 app.pid, info.toString());
4725 if (res != 0) {
4726 if (res < 0) {
4727 // wait until the SIGQUIT has had a chance to process before killing the
4728 // process.
4729 try {
4730 wait(2000);
4731 } catch (InterruptedException e) {
4732 }
4733
4734 Process.killProcess(app.pid);
4735 return;
4736 }
4737 }
4738 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004739 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004740 }
4741 }
4742
4743 makeAppNotRespondingLocked(app,
4744 activity != null ? activity.shortComponentName : null,
4745 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004746 info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004747 Message msg = Message.obtain();
4748 HashMap map = new HashMap();
4749 msg.what = SHOW_NOT_RESPONDING_MSG;
4750 msg.obj = map;
4751 map.put("app", app);
4752 if (activity != null) {
4753 map.put("activity", activity);
4754 }
4755
4756 mHandler.sendMessage(msg);
4757 return;
4758 }
4759
4760 /**
4761 * If a stack trace file has been configured, prepare the filesystem
4762 * by creating the directory if it doesn't exist and optionally
4763 * removing the old trace file.
4764 *
4765 * @param removeExisting If set, the existing trace file will be removed.
4766 * @return Returns true if the trace file preparations succeeded
4767 */
4768 public static boolean prepareTraceFile(boolean removeExisting) {
4769 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4770 boolean fileReady = false;
4771 if (!TextUtils.isEmpty(tracesPath)) {
4772 File f = new File(tracesPath);
4773 if (!f.exists()) {
4774 // Ensure the enclosing directory exists
4775 File dir = f.getParentFile();
4776 if (!dir.exists()) {
4777 fileReady = dir.mkdirs();
4778 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004779 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004780 } else if (dir.isDirectory()) {
4781 fileReady = true;
4782 }
4783 } else if (removeExisting) {
4784 // Remove the previous traces file, so we don't fill the disk.
4785 // The VM will recreate it
4786 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4787 fileReady = f.delete();
4788 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004789
4790 if (removeExisting) {
4791 try {
4792 f.createNewFile();
4793 FileUtils.setPermissions(f.getAbsolutePath(),
4794 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4795 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4796 fileReady = true;
4797 } catch (IOException e) {
4798 Log.w(TAG, "Unable to make ANR traces file", e);
4799 }
4800 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004801 }
4802
4803 return fileReady;
4804 }
4805
4806
4807 private final void decPersistentCountLocked(ProcessRecord app)
4808 {
4809 app.persistentActivities--;
4810 if (app.persistentActivities > 0) {
4811 // Still more of 'em...
4812 return;
4813 }
4814 if (app.persistent) {
4815 // Ah, but the application itself is persistent. Whatever!
4816 return;
4817 }
4818
4819 // App is no longer persistent... make sure it and the ones
4820 // following it in the LRU list have the correc oom_adj.
4821 updateOomAdjLocked();
4822 }
4823
4824 public void setPersistent(IBinder token, boolean isPersistent) {
4825 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4826 != PackageManager.PERMISSION_GRANTED) {
4827 String msg = "Permission Denial: setPersistent() from pid="
4828 + Binder.getCallingPid()
4829 + ", uid=" + Binder.getCallingUid()
4830 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4831 Log.w(TAG, msg);
4832 throw new SecurityException(msg);
4833 }
4834
4835 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004836 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004837 if (index < 0) {
4838 return;
4839 }
4840 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4841 ProcessRecord app = r.app;
4842
4843 if (localLOGV) Log.v(
4844 TAG, "Setting persistence " + isPersistent + ": " + r);
4845
4846 if (isPersistent) {
4847 if (r.persistent) {
4848 // Okay okay, I heard you already!
4849 if (localLOGV) Log.v(TAG, "Already persistent!");
4850 return;
4851 }
4852 r.persistent = true;
4853 app.persistentActivities++;
4854 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4855 if (app.persistentActivities > 1) {
4856 // We aren't the first...
4857 if (localLOGV) Log.v(TAG, "Not the first!");
4858 return;
4859 }
4860 if (app.persistent) {
4861 // This would be redundant.
4862 if (localLOGV) Log.v(TAG, "App is persistent!");
4863 return;
4864 }
4865
4866 // App is now persistent... make sure it and the ones
4867 // following it now have the correct oom_adj.
4868 final long origId = Binder.clearCallingIdentity();
4869 updateOomAdjLocked();
4870 Binder.restoreCallingIdentity(origId);
4871
4872 } else {
4873 if (!r.persistent) {
4874 // Okay okay, I heard you already!
4875 return;
4876 }
4877 r.persistent = false;
4878 final long origId = Binder.clearCallingIdentity();
4879 decPersistentCountLocked(app);
4880 Binder.restoreCallingIdentity(origId);
4881
4882 }
4883 }
4884 }
4885
4886 public boolean clearApplicationUserData(final String packageName,
4887 final IPackageDataObserver observer) {
4888 int uid = Binder.getCallingUid();
4889 int pid = Binder.getCallingPid();
4890 long callingId = Binder.clearCallingIdentity();
4891 try {
4892 IPackageManager pm = ActivityThread.getPackageManager();
4893 int pkgUid = -1;
4894 synchronized(this) {
4895 try {
4896 pkgUid = pm.getPackageUid(packageName);
4897 } catch (RemoteException e) {
4898 }
4899 if (pkgUid == -1) {
4900 Log.w(TAG, "Invalid packageName:" + packageName);
4901 return false;
4902 }
4903 if (uid == pkgUid || checkComponentPermission(
4904 android.Manifest.permission.CLEAR_APP_USER_DATA,
4905 pid, uid, -1)
4906 == PackageManager.PERMISSION_GRANTED) {
4907 restartPackageLocked(packageName, pkgUid);
4908 } else {
4909 throw new SecurityException(pid+" does not have permission:"+
4910 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4911 "for process:"+packageName);
4912 }
4913 }
4914
4915 try {
4916 //clear application user data
4917 pm.clearApplicationUserData(packageName, observer);
4918 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4919 Uri.fromParts("package", packageName, null));
4920 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4921 broadcastIntentLocked(null, null, intent,
4922 null, null, 0, null, null, null,
4923 false, false, MY_PID, Process.SYSTEM_UID);
4924 } catch (RemoteException e) {
4925 }
4926 } finally {
4927 Binder.restoreCallingIdentity(callingId);
4928 }
4929 return true;
4930 }
4931
4932 public void restartPackage(final String packageName) {
4933 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4934 != PackageManager.PERMISSION_GRANTED) {
4935 String msg = "Permission Denial: restartPackage() from pid="
4936 + Binder.getCallingPid()
4937 + ", uid=" + Binder.getCallingUid()
4938 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4939 Log.w(TAG, msg);
4940 throw new SecurityException(msg);
4941 }
4942
4943 long callingId = Binder.clearCallingIdentity();
4944 try {
4945 IPackageManager pm = ActivityThread.getPackageManager();
4946 int pkgUid = -1;
4947 synchronized(this) {
4948 try {
4949 pkgUid = pm.getPackageUid(packageName);
4950 } catch (RemoteException e) {
4951 }
4952 if (pkgUid == -1) {
4953 Log.w(TAG, "Invalid packageName: " + packageName);
4954 return;
4955 }
4956 restartPackageLocked(packageName, pkgUid);
4957 }
4958 } finally {
4959 Binder.restoreCallingIdentity(callingId);
4960 }
4961 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004962
4963 /*
4964 * The pkg name and uid have to be specified.
4965 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4966 */
4967 public void killApplicationWithUid(String pkg, int uid) {
4968 if (pkg == null) {
4969 return;
4970 }
4971 // Make sure the uid is valid.
4972 if (uid < 0) {
4973 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4974 return;
4975 }
4976 int callerUid = Binder.getCallingUid();
4977 // Only the system server can kill an application
4978 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004979 // Post an aysnc message to kill the application
4980 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4981 msg.arg1 = uid;
4982 msg.arg2 = 0;
4983 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004984 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004985 } else {
4986 throw new SecurityException(callerUid + " cannot kill pkg: " +
4987 pkg);
4988 }
4989 }
4990
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004991 public void closeSystemDialogs(String reason) {
4992 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4993 if (reason != null) {
4994 intent.putExtra("reason", reason);
4995 }
4996
4997 final int uid = Binder.getCallingUid();
4998 final long origId = Binder.clearCallingIdentity();
4999 synchronized (this) {
5000 int i = mWatchers.beginBroadcast();
5001 while (i > 0) {
5002 i--;
5003 IActivityWatcher w = mWatchers.getBroadcastItem(i);
5004 if (w != null) {
5005 try {
5006 w.closingSystemDialogs(reason);
5007 } catch (RemoteException e) {
5008 }
5009 }
5010 }
5011 mWatchers.finishBroadcast();
5012
Dianne Hackbornffa42482009-09-23 22:20:11 -07005013 mWindowManager.closeSystemDialogs(reason);
5014
5015 for (i=mHistory.size()-1; i>=0; i--) {
5016 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5017 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
5018 finishActivityLocked(r, i,
5019 Activity.RESULT_CANCELED, null, "close-sys");
5020 }
5021 }
5022
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005023 broadcastIntentLocked(null, null, intent, null,
5024 null, 0, null, null, null, false, false, -1, uid);
5025 }
5026 Binder.restoreCallingIdentity(origId);
5027 }
5028
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005029 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005030 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005031 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5032 for (int i=pids.length-1; i>=0; i--) {
5033 infos[i] = new Debug.MemoryInfo();
5034 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005035 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005036 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005037 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005038
5039 public void killApplicationProcess(String processName, int uid) {
5040 if (processName == null) {
5041 return;
5042 }
5043
5044 int callerUid = Binder.getCallingUid();
5045 // Only the system server can kill an application
5046 if (callerUid == Process.SYSTEM_UID) {
5047 synchronized (this) {
5048 ProcessRecord app = getProcessRecordLocked(processName, uid);
5049 if (app != null) {
5050 try {
5051 app.thread.scheduleSuicide();
5052 } catch (RemoteException e) {
5053 // If the other end already died, then our work here is done.
5054 }
5055 } else {
5056 Log.w(TAG, "Process/uid not found attempting kill of "
5057 + processName + " / " + uid);
5058 }
5059 }
5060 } else {
5061 throw new SecurityException(callerUid + " cannot kill app process: " +
5062 processName);
5063 }
5064 }
5065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005066 private void restartPackageLocked(final String packageName, int uid) {
5067 uninstallPackageLocked(packageName, uid, false);
5068 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5069 Uri.fromParts("package", packageName, null));
5070 intent.putExtra(Intent.EXTRA_UID, uid);
5071 broadcastIntentLocked(null, null, intent,
5072 null, null, 0, null, null, null,
5073 false, false, MY_PID, Process.SYSTEM_UID);
5074 }
5075
5076 private final void uninstallPackageLocked(String name, int uid,
5077 boolean callerWillRestart) {
5078 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5079
5080 int i, N;
5081
5082 final String procNamePrefix = name + ":";
5083 if (uid < 0) {
5084 try {
5085 uid = ActivityThread.getPackageManager().getPackageUid(name);
5086 } catch (RemoteException e) {
5087 }
5088 }
5089
5090 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5091 while (badApps.hasNext()) {
5092 SparseArray<Long> ba = badApps.next();
5093 if (ba.get(uid) != null) {
5094 badApps.remove();
5095 }
5096 }
5097
5098 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5099
5100 // Remove all processes this package may have touched: all with the
5101 // same UID (except for the system or root user), and all whose name
5102 // matches the package name.
5103 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5104 final int NA = apps.size();
5105 for (int ia=0; ia<NA; ia++) {
5106 ProcessRecord app = apps.valueAt(ia);
5107 if (app.removed) {
5108 procs.add(app);
5109 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5110 || app.processName.equals(name)
5111 || app.processName.startsWith(procNamePrefix)) {
5112 app.removed = true;
5113 procs.add(app);
5114 }
5115 }
5116 }
5117
5118 N = procs.size();
5119 for (i=0; i<N; i++) {
5120 removeProcessLocked(procs.get(i), callerWillRestart);
5121 }
5122
5123 for (i=mHistory.size()-1; i>=0; i--) {
5124 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5125 if (r.packageName.equals(name)) {
5126 if (Config.LOGD) Log.d(
5127 TAG, " Force finishing activity "
5128 + r.intent.getComponent().flattenToShortString());
5129 if (r.app != null) {
5130 r.app.removed = true;
5131 }
5132 r.app = null;
5133 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5134 }
5135 }
5136
5137 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5138 for (ServiceRecord service : mServices.values()) {
5139 if (service.packageName.equals(name)) {
5140 if (service.app != null) {
5141 service.app.removed = true;
5142 }
5143 service.app = null;
5144 services.add(service);
5145 }
5146 }
5147
5148 N = services.size();
5149 for (i=0; i<N; i++) {
5150 bringDownServiceLocked(services.get(i), true);
5151 }
5152
5153 resumeTopActivityLocked(null);
5154 }
5155
5156 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5157 final String name = app.processName;
5158 final int uid = app.info.uid;
5159 if (Config.LOGD) Log.d(
5160 TAG, "Force removing process " + app + " (" + name
5161 + "/" + uid + ")");
5162
5163 mProcessNames.remove(name, uid);
5164 boolean needRestart = false;
5165 if (app.pid > 0 && app.pid != MY_PID) {
5166 int pid = app.pid;
5167 synchronized (mPidsSelfLocked) {
5168 mPidsSelfLocked.remove(pid);
5169 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5170 }
5171 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005172 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005173 Process.killProcess(pid);
5174
5175 if (app.persistent) {
5176 if (!callerWillRestart) {
5177 addAppLocked(app.info);
5178 } else {
5179 needRestart = true;
5180 }
5181 }
5182 } else {
5183 mRemovedProcesses.add(app);
5184 }
5185
5186 return needRestart;
5187 }
5188
5189 private final void processStartTimedOutLocked(ProcessRecord app) {
5190 final int pid = app.pid;
5191 boolean gone = false;
5192 synchronized (mPidsSelfLocked) {
5193 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5194 if (knownApp != null && knownApp.thread == null) {
5195 mPidsSelfLocked.remove(pid);
5196 gone = true;
5197 }
5198 }
5199
5200 if (gone) {
5201 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005202 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005203 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005204 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005205 // Take care of any launching providers waiting for this process.
5206 checkAppInLaunchingProvidersLocked(app, true);
5207 // Take care of any services that are waiting for the process.
5208 for (int i=0; i<mPendingServices.size(); i++) {
5209 ServiceRecord sr = mPendingServices.get(i);
5210 if (app.info.uid == sr.appInfo.uid
5211 && app.processName.equals(sr.processName)) {
5212 Log.w(TAG, "Forcing bringing down service: " + sr);
5213 mPendingServices.remove(i);
5214 i--;
5215 bringDownServiceLocked(sr, true);
5216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005217 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005218 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005219 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5220 Log.w(TAG, "Unattached app died before backup, skipping");
5221 try {
5222 IBackupManager bm = IBackupManager.Stub.asInterface(
5223 ServiceManager.getService(Context.BACKUP_SERVICE));
5224 bm.agentDisconnected(app.info.packageName);
5225 } catch (RemoteException e) {
5226 // Can't happen; the backup manager is local
5227 }
5228 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005229 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5230 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5231 mPendingBroadcast = null;
5232 scheduleBroadcastsLocked();
5233 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005234 } else {
5235 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5236 }
5237 }
5238
5239 private final boolean attachApplicationLocked(IApplicationThread thread,
5240 int pid) {
5241
5242 // Find the application record that is being attached... either via
5243 // the pid if we are running in multiple processes, or just pull the
5244 // next app record if we are emulating process with anonymous threads.
5245 ProcessRecord app;
5246 if (pid != MY_PID && pid >= 0) {
5247 synchronized (mPidsSelfLocked) {
5248 app = mPidsSelfLocked.get(pid);
5249 }
5250 } else if (mStartingProcesses.size() > 0) {
5251 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005252 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005253 } else {
5254 app = null;
5255 }
5256
5257 if (app == null) {
5258 Log.w(TAG, "No pending application record for pid " + pid
5259 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005260 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005261 if (pid > 0 && pid != MY_PID) {
5262 Process.killProcess(pid);
5263 } else {
5264 try {
5265 thread.scheduleExit();
5266 } catch (Exception e) {
5267 // Ignore exceptions.
5268 }
5269 }
5270 return false;
5271 }
5272
5273 // If this application record is still attached to a previous
5274 // process, clean it up now.
5275 if (app.thread != null) {
5276 handleAppDiedLocked(app, true);
5277 }
5278
5279 // Tell the process all about itself.
5280
5281 if (localLOGV) Log.v(
5282 TAG, "Binding process pid " + pid + " to record " + app);
5283
5284 String processName = app.processName;
5285 try {
5286 thread.asBinder().linkToDeath(new AppDeathRecipient(
5287 app, pid, thread), 0);
5288 } catch (RemoteException e) {
5289 app.resetPackageList();
5290 startProcessLocked(app, "link fail", processName);
5291 return false;
5292 }
5293
Doug Zongker2bec3d42009-12-04 12:52:44 -08005294 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005295
5296 app.thread = thread;
5297 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005298 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5299 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005300 app.forcingToForeground = null;
5301 app.foregroundServices = false;
5302 app.debugging = false;
5303
5304 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5305
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005306 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5307 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005308
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005309 if (!normalMode) {
5310 Log.i(TAG, "Launching preboot mode app: " + app);
5311 }
5312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005313 if (localLOGV) Log.v(
5314 TAG, "New app record " + app
5315 + " thread=" + thread.asBinder() + " pid=" + pid);
5316 try {
5317 int testMode = IApplicationThread.DEBUG_OFF;
5318 if (mDebugApp != null && mDebugApp.equals(processName)) {
5319 testMode = mWaitForDebugger
5320 ? IApplicationThread.DEBUG_WAIT
5321 : IApplicationThread.DEBUG_ON;
5322 app.debugging = true;
5323 if (mDebugTransient) {
5324 mDebugApp = mOrigDebugApp;
5325 mWaitForDebugger = mOrigWaitForDebugger;
5326 }
5327 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005328
Christopher Tate181fafa2009-05-14 11:12:14 -07005329 // If the app is being launched for restore or full backup, set it up specially
5330 boolean isRestrictedBackupMode = false;
5331 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5332 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5333 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5334 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005335
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005336 ensurePackageDexOpt(app.instrumentationInfo != null
5337 ? app.instrumentationInfo.packageName
5338 : app.info.packageName);
5339 if (app.instrumentationClass != null) {
5340 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005341 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005342 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5343 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005344 thread.bindApplication(processName, app.instrumentationInfo != null
5345 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005346 app.instrumentationClass, app.instrumentationProfileFile,
5347 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005348 isRestrictedBackupMode || !normalMode,
5349 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005350 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005351 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005352 } catch (Exception e) {
5353 // todo: Yikes! What should we do? For now we will try to
5354 // start another process, but that could easily get us in
5355 // an infinite loop of restarting processes...
5356 Log.w(TAG, "Exception thrown during bind!", e);
5357
5358 app.resetPackageList();
5359 startProcessLocked(app, "bind fail", processName);
5360 return false;
5361 }
5362
5363 // Remove this record from the list of starting applications.
5364 mPersistentStartingProcesses.remove(app);
5365 mProcessesOnHold.remove(app);
5366
5367 boolean badApp = false;
5368 boolean didSomething = false;
5369
5370 // See if the top visible activity is waiting to run in this process...
5371 HistoryRecord hr = topRunningActivityLocked(null);
5372 if (hr != null) {
5373 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5374 && processName.equals(hr.processName)) {
5375 try {
5376 if (realStartActivityLocked(hr, app, true, true)) {
5377 didSomething = true;
5378 }
5379 } catch (Exception e) {
5380 Log.w(TAG, "Exception in new application when starting activity "
5381 + hr.intent.getComponent().flattenToShortString(), e);
5382 badApp = true;
5383 }
5384 } else {
5385 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5386 }
5387 }
5388
5389 // Find any services that should be running in this process...
5390 if (!badApp && mPendingServices.size() > 0) {
5391 ServiceRecord sr = null;
5392 try {
5393 for (int i=0; i<mPendingServices.size(); i++) {
5394 sr = mPendingServices.get(i);
5395 if (app.info.uid != sr.appInfo.uid
5396 || !processName.equals(sr.processName)) {
5397 continue;
5398 }
5399
5400 mPendingServices.remove(i);
5401 i--;
5402 realStartServiceLocked(sr, app);
5403 didSomething = true;
5404 }
5405 } catch (Exception e) {
5406 Log.w(TAG, "Exception in new application when starting service "
5407 + sr.shortName, e);
5408 badApp = true;
5409 }
5410 }
5411
5412 // Check if the next broadcast receiver is in this process...
5413 BroadcastRecord br = mPendingBroadcast;
5414 if (!badApp && br != null && br.curApp == app) {
5415 try {
5416 mPendingBroadcast = null;
5417 processCurBroadcastLocked(br, app);
5418 didSomething = true;
5419 } catch (Exception e) {
5420 Log.w(TAG, "Exception in new application when starting receiver "
5421 + br.curComponent.flattenToShortString(), e);
5422 badApp = true;
5423 logBroadcastReceiverDiscard(br);
5424 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5425 br.resultExtras, br.resultAbort, true);
5426 scheduleBroadcastsLocked();
5427 }
5428 }
5429
Christopher Tate181fafa2009-05-14 11:12:14 -07005430 // Check whether the next backup agent is in this process...
5431 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5432 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005433 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005434 try {
5435 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5436 } catch (Exception e) {
5437 Log.w(TAG, "Exception scheduling backup agent creation: ");
5438 e.printStackTrace();
5439 }
5440 }
5441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005442 if (badApp) {
5443 // todo: Also need to kill application to deal with all
5444 // kinds of exceptions.
5445 handleAppDiedLocked(app, false);
5446 return false;
5447 }
5448
5449 if (!didSomething) {
5450 updateOomAdjLocked();
5451 }
5452
5453 return true;
5454 }
5455
5456 public final void attachApplication(IApplicationThread thread) {
5457 synchronized (this) {
5458 int callingPid = Binder.getCallingPid();
5459 final long origId = Binder.clearCallingIdentity();
5460 attachApplicationLocked(thread, callingPid);
5461 Binder.restoreCallingIdentity(origId);
5462 }
5463 }
5464
Dianne Hackborne88846e2009-09-30 21:34:25 -07005465 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005466 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005467 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005468 Binder.restoreCallingIdentity(origId);
5469 }
5470
5471 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5472 boolean remove) {
5473 int N = mStoppingActivities.size();
5474 if (N <= 0) return null;
5475
5476 ArrayList<HistoryRecord> stops = null;
5477
5478 final boolean nowVisible = mResumedActivity != null
5479 && mResumedActivity.nowVisible
5480 && !mResumedActivity.waitingVisible;
5481 for (int i=0; i<N; i++) {
5482 HistoryRecord s = mStoppingActivities.get(i);
5483 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5484 + nowVisible + " waitingVisible=" + s.waitingVisible
5485 + " finishing=" + s.finishing);
5486 if (s.waitingVisible && nowVisible) {
5487 mWaitingVisibleActivities.remove(s);
5488 s.waitingVisible = false;
5489 if (s.finishing) {
5490 // If this activity is finishing, it is sitting on top of
5491 // everyone else but we now know it is no longer needed...
5492 // so get rid of it. Otherwise, we need to go through the
5493 // normal flow and hide it once we determine that it is
5494 // hidden by the activities in front of it.
5495 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5496 mWindowManager.setAppVisibility(s, false);
5497 }
5498 }
5499 if (!s.waitingVisible && remove) {
5500 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5501 if (stops == null) {
5502 stops = new ArrayList<HistoryRecord>();
5503 }
5504 stops.add(s);
5505 mStoppingActivities.remove(i);
5506 N--;
5507 i--;
5508 }
5509 }
5510
5511 return stops;
5512 }
5513
5514 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005515 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005516 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005517 mWindowManager.enableScreenAfterBoot();
5518 }
5519
Dianne Hackborne88846e2009-09-30 21:34:25 -07005520 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5521 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005522 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5523
5524 ArrayList<HistoryRecord> stops = null;
5525 ArrayList<HistoryRecord> finishes = null;
5526 ArrayList<HistoryRecord> thumbnails = null;
5527 int NS = 0;
5528 int NF = 0;
5529 int NT = 0;
5530 IApplicationThread sendThumbnail = null;
5531 boolean booting = false;
5532 boolean enableScreen = false;
5533
5534 synchronized (this) {
5535 if (token != null) {
5536 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5537 }
5538
5539 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005540 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005541 if (index >= 0) {
5542 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5543
Dianne Hackborne88846e2009-09-30 21:34:25 -07005544 // This is a hack to semi-deal with a race condition
5545 // in the client where it can be constructed with a
5546 // newer configuration from when we asked it to launch.
5547 // We'll update with whatever configuration it now says
5548 // it used to launch.
5549 if (config != null) {
5550 r.configuration = config;
5551 }
5552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005553 // No longer need to keep the device awake.
5554 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5555 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5556 mLaunchingActivity.release();
5557 }
5558
5559 // We are now idle. If someone is waiting for a thumbnail from
5560 // us, we can now deliver.
5561 r.idle = true;
5562 scheduleAppGcsLocked();
5563 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5564 sendThumbnail = r.app.thread;
5565 r.thumbnailNeeded = false;
5566 }
5567
5568 // If this activity is fullscreen, set up to hide those under it.
5569
5570 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5571 ensureActivitiesVisibleLocked(null, 0);
5572
5573 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5574 if (!mBooted && !fromTimeout) {
5575 mBooted = true;
5576 enableScreen = true;
5577 }
5578 }
5579
5580 // Atomically retrieve all of the other things to do.
5581 stops = processStoppingActivitiesLocked(true);
5582 NS = stops != null ? stops.size() : 0;
5583 if ((NF=mFinishingActivities.size()) > 0) {
5584 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5585 mFinishingActivities.clear();
5586 }
5587 if ((NT=mCancelledThumbnails.size()) > 0) {
5588 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5589 mCancelledThumbnails.clear();
5590 }
5591
5592 booting = mBooting;
5593 mBooting = false;
5594 }
5595
5596 int i;
5597
5598 // Send thumbnail if requested.
5599 if (sendThumbnail != null) {
5600 try {
5601 sendThumbnail.requestThumbnail(token);
5602 } catch (Exception e) {
5603 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5604 sendPendingThumbnail(null, token, null, null, true);
5605 }
5606 }
5607
5608 // Stop any activities that are scheduled to do so but have been
5609 // waiting for the next one to start.
5610 for (i=0; i<NS; i++) {
5611 HistoryRecord r = (HistoryRecord)stops.get(i);
5612 synchronized (this) {
5613 if (r.finishing) {
5614 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5615 } else {
5616 stopActivityLocked(r);
5617 }
5618 }
5619 }
5620
5621 // Finish any activities that are scheduled to do so but have been
5622 // waiting for the next one to start.
5623 for (i=0; i<NF; i++) {
5624 HistoryRecord r = (HistoryRecord)finishes.get(i);
5625 synchronized (this) {
5626 destroyActivityLocked(r, true);
5627 }
5628 }
5629
5630 // Report back to any thumbnail receivers.
5631 for (i=0; i<NT; i++) {
5632 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5633 sendPendingThumbnail(r, null, null, null, true);
5634 }
5635
5636 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005637 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005638 }
5639
5640 trimApplications();
5641 //dump();
5642 //mWindowManager.dump();
5643
5644 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005645 enableScreenAfterBoot();
5646 }
5647 }
5648
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005649 final void finishBooting() {
5650 // Ensure that any processes we had put on hold are now started
5651 // up.
5652 final int NP = mProcessesOnHold.size();
5653 if (NP > 0) {
5654 ArrayList<ProcessRecord> procs =
5655 new ArrayList<ProcessRecord>(mProcessesOnHold);
5656 for (int ip=0; ip<NP; ip++) {
5657 this.startProcessLocked(procs.get(ip), "on-hold", null);
5658 }
5659 }
5660 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5661 // Tell anyone interested that we are done booting!
5662 synchronized (this) {
5663 broadcastIntentLocked(null, null,
5664 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5665 null, null, 0, null, null,
5666 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5667 false, false, MY_PID, Process.SYSTEM_UID);
5668 }
5669 }
5670 }
5671
5672 final void ensureBootCompleted() {
5673 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005674 boolean enableScreen;
5675 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005676 booting = mBooting;
5677 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005678 enableScreen = !mBooted;
5679 mBooted = true;
5680 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005681
5682 if (booting) {
5683 finishBooting();
5684 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005685
5686 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005687 enableScreenAfterBoot();
5688 }
5689 }
5690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005691 public final void activityPaused(IBinder token, Bundle icicle) {
5692 // Refuse possible leaked file descriptors
5693 if (icicle != null && icicle.hasFileDescriptors()) {
5694 throw new IllegalArgumentException("File descriptors passed in Bundle");
5695 }
5696
5697 final long origId = Binder.clearCallingIdentity();
5698 activityPaused(token, icicle, false);
5699 Binder.restoreCallingIdentity(origId);
5700 }
5701
5702 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5703 if (DEBUG_PAUSE) Log.v(
5704 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5705 + ", timeout=" + timeout);
5706
5707 HistoryRecord r = null;
5708
5709 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005710 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005711 if (index >= 0) {
5712 r = (HistoryRecord)mHistory.get(index);
5713 if (!timeout) {
5714 r.icicle = icicle;
5715 r.haveState = true;
5716 }
5717 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5718 if (mPausingActivity == r) {
5719 r.state = ActivityState.PAUSED;
5720 completePauseLocked();
5721 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005722 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005723 System.identityHashCode(r), r.shortComponentName,
5724 mPausingActivity != null
5725 ? mPausingActivity.shortComponentName : "(none)");
5726 }
5727 }
5728 }
5729 }
5730
5731 public final void activityStopped(IBinder token, Bitmap thumbnail,
5732 CharSequence description) {
5733 if (localLOGV) Log.v(
5734 TAG, "Activity stopped: token=" + token);
5735
5736 HistoryRecord r = null;
5737
5738 final long origId = Binder.clearCallingIdentity();
5739
5740 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005741 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005742 if (index >= 0) {
5743 r = (HistoryRecord)mHistory.get(index);
5744 r.thumbnail = thumbnail;
5745 r.description = description;
5746 r.stopped = true;
5747 r.state = ActivityState.STOPPED;
5748 if (!r.finishing) {
5749 if (r.configDestroy) {
5750 destroyActivityLocked(r, true);
5751 resumeTopActivityLocked(null);
5752 }
5753 }
5754 }
5755 }
5756
5757 if (r != null) {
5758 sendPendingThumbnail(r, null, null, null, false);
5759 }
5760
5761 trimApplications();
5762
5763 Binder.restoreCallingIdentity(origId);
5764 }
5765
5766 public final void activityDestroyed(IBinder token) {
5767 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5768 synchronized (this) {
5769 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5770
Dianne Hackborn75b03852009-06-12 15:43:26 -07005771 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005772 if (index >= 0) {
5773 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5774 if (r.state == ActivityState.DESTROYING) {
5775 final long origId = Binder.clearCallingIdentity();
5776 removeActivityFromHistoryLocked(r);
5777 Binder.restoreCallingIdentity(origId);
5778 }
5779 }
5780 }
5781 }
5782
5783 public String getCallingPackage(IBinder token) {
5784 synchronized (this) {
5785 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005786 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005787 }
5788 }
5789
5790 public ComponentName getCallingActivity(IBinder token) {
5791 synchronized (this) {
5792 HistoryRecord r = getCallingRecordLocked(token);
5793 return r != null ? r.intent.getComponent() : null;
5794 }
5795 }
5796
5797 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005798 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005799 if (index >= 0) {
5800 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5801 if (r != null) {
5802 return r.resultTo;
5803 }
5804 }
5805 return null;
5806 }
5807
5808 public ComponentName getActivityClassForToken(IBinder token) {
5809 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005810 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005811 if (index >= 0) {
5812 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5813 return r.intent.getComponent();
5814 }
5815 return null;
5816 }
5817 }
5818
5819 public String getPackageForToken(IBinder token) {
5820 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005821 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005822 if (index >= 0) {
5823 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5824 return r.packageName;
5825 }
5826 return null;
5827 }
5828 }
5829
5830 public IIntentSender getIntentSender(int type,
5831 String packageName, IBinder token, String resultWho,
5832 int requestCode, Intent intent, String resolvedType, int flags) {
5833 // Refuse possible leaked file descriptors
5834 if (intent != null && intent.hasFileDescriptors() == true) {
5835 throw new IllegalArgumentException("File descriptors passed in Intent");
5836 }
5837
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005838 if (type == INTENT_SENDER_BROADCAST) {
5839 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5840 throw new IllegalArgumentException(
5841 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5842 }
5843 }
5844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005845 synchronized(this) {
5846 int callingUid = Binder.getCallingUid();
5847 try {
5848 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5849 Process.supportsProcesses()) {
5850 int uid = ActivityThread.getPackageManager()
5851 .getPackageUid(packageName);
5852 if (uid != Binder.getCallingUid()) {
5853 String msg = "Permission Denial: getIntentSender() from pid="
5854 + Binder.getCallingPid()
5855 + ", uid=" + Binder.getCallingUid()
5856 + ", (need uid=" + uid + ")"
5857 + " is not allowed to send as package " + packageName;
5858 Log.w(TAG, msg);
5859 throw new SecurityException(msg);
5860 }
5861 }
5862 } catch (RemoteException e) {
5863 throw new SecurityException(e);
5864 }
5865 HistoryRecord activity = null;
5866 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005867 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005868 if (index < 0) {
5869 return null;
5870 }
5871 activity = (HistoryRecord)mHistory.get(index);
5872 if (activity.finishing) {
5873 return null;
5874 }
5875 }
5876
5877 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5878 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5879 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5880 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5881 |PendingIntent.FLAG_UPDATE_CURRENT);
5882
5883 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5884 type, packageName, activity, resultWho,
5885 requestCode, intent, resolvedType, flags);
5886 WeakReference<PendingIntentRecord> ref;
5887 ref = mIntentSenderRecords.get(key);
5888 PendingIntentRecord rec = ref != null ? ref.get() : null;
5889 if (rec != null) {
5890 if (!cancelCurrent) {
5891 if (updateCurrent) {
5892 rec.key.requestIntent.replaceExtras(intent);
5893 }
5894 return rec;
5895 }
5896 rec.canceled = true;
5897 mIntentSenderRecords.remove(key);
5898 }
5899 if (noCreate) {
5900 return rec;
5901 }
5902 rec = new PendingIntentRecord(this, key, callingUid);
5903 mIntentSenderRecords.put(key, rec.ref);
5904 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5905 if (activity.pendingResults == null) {
5906 activity.pendingResults
5907 = new HashSet<WeakReference<PendingIntentRecord>>();
5908 }
5909 activity.pendingResults.add(rec.ref);
5910 }
5911 return rec;
5912 }
5913 }
5914
5915 public void cancelIntentSender(IIntentSender sender) {
5916 if (!(sender instanceof PendingIntentRecord)) {
5917 return;
5918 }
5919 synchronized(this) {
5920 PendingIntentRecord rec = (PendingIntentRecord)sender;
5921 try {
5922 int uid = ActivityThread.getPackageManager()
5923 .getPackageUid(rec.key.packageName);
5924 if (uid != Binder.getCallingUid()) {
5925 String msg = "Permission Denial: cancelIntentSender() from pid="
5926 + Binder.getCallingPid()
5927 + ", uid=" + Binder.getCallingUid()
5928 + " is not allowed to cancel packges "
5929 + rec.key.packageName;
5930 Log.w(TAG, msg);
5931 throw new SecurityException(msg);
5932 }
5933 } catch (RemoteException e) {
5934 throw new SecurityException(e);
5935 }
5936 cancelIntentSenderLocked(rec, true);
5937 }
5938 }
5939
5940 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5941 rec.canceled = true;
5942 mIntentSenderRecords.remove(rec.key);
5943 if (cleanActivity && rec.key.activity != null) {
5944 rec.key.activity.pendingResults.remove(rec.ref);
5945 }
5946 }
5947
5948 public String getPackageForIntentSender(IIntentSender pendingResult) {
5949 if (!(pendingResult instanceof PendingIntentRecord)) {
5950 return null;
5951 }
5952 synchronized(this) {
5953 try {
5954 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5955 return res.key.packageName;
5956 } catch (ClassCastException e) {
5957 }
5958 }
5959 return null;
5960 }
5961
5962 public void setProcessLimit(int max) {
5963 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5964 "setProcessLimit()");
5965 mProcessLimit = max;
5966 }
5967
5968 public int getProcessLimit() {
5969 return mProcessLimit;
5970 }
5971
5972 void foregroundTokenDied(ForegroundToken token) {
5973 synchronized (ActivityManagerService.this) {
5974 synchronized (mPidsSelfLocked) {
5975 ForegroundToken cur
5976 = mForegroundProcesses.get(token.pid);
5977 if (cur != token) {
5978 return;
5979 }
5980 mForegroundProcesses.remove(token.pid);
5981 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5982 if (pr == null) {
5983 return;
5984 }
5985 pr.forcingToForeground = null;
5986 pr.foregroundServices = false;
5987 }
5988 updateOomAdjLocked();
5989 }
5990 }
5991
5992 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5993 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5994 "setProcessForeground()");
5995 synchronized(this) {
5996 boolean changed = false;
5997
5998 synchronized (mPidsSelfLocked) {
5999 ProcessRecord pr = mPidsSelfLocked.get(pid);
6000 if (pr == null) {
6001 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
6002 return;
6003 }
6004 ForegroundToken oldToken = mForegroundProcesses.get(pid);
6005 if (oldToken != null) {
6006 oldToken.token.unlinkToDeath(oldToken, 0);
6007 mForegroundProcesses.remove(pid);
6008 pr.forcingToForeground = null;
6009 changed = true;
6010 }
6011 if (isForeground && token != null) {
6012 ForegroundToken newToken = new ForegroundToken() {
6013 public void binderDied() {
6014 foregroundTokenDied(this);
6015 }
6016 };
6017 newToken.pid = pid;
6018 newToken.token = token;
6019 try {
6020 token.linkToDeath(newToken, 0);
6021 mForegroundProcesses.put(pid, newToken);
6022 pr.forcingToForeground = token;
6023 changed = true;
6024 } catch (RemoteException e) {
6025 // If the process died while doing this, we will later
6026 // do the cleanup with the process death link.
6027 }
6028 }
6029 }
6030
6031 if (changed) {
6032 updateOomAdjLocked();
6033 }
6034 }
6035 }
6036
6037 // =========================================================
6038 // PERMISSIONS
6039 // =========================================================
6040
6041 static class PermissionController extends IPermissionController.Stub {
6042 ActivityManagerService mActivityManagerService;
6043 PermissionController(ActivityManagerService activityManagerService) {
6044 mActivityManagerService = activityManagerService;
6045 }
6046
6047 public boolean checkPermission(String permission, int pid, int uid) {
6048 return mActivityManagerService.checkPermission(permission, pid,
6049 uid) == PackageManager.PERMISSION_GRANTED;
6050 }
6051 }
6052
6053 /**
6054 * This can be called with or without the global lock held.
6055 */
6056 int checkComponentPermission(String permission, int pid, int uid,
6057 int reqUid) {
6058 // We might be performing an operation on behalf of an indirect binder
6059 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6060 // client identity accordingly before proceeding.
6061 Identity tlsIdentity = sCallerIdentity.get();
6062 if (tlsIdentity != null) {
6063 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6064 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6065 uid = tlsIdentity.uid;
6066 pid = tlsIdentity.pid;
6067 }
6068
6069 // Root, system server and our own process get to do everything.
6070 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6071 !Process.supportsProcesses()) {
6072 return PackageManager.PERMISSION_GRANTED;
6073 }
6074 // If the target requires a specific UID, always fail for others.
6075 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006076 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006077 return PackageManager.PERMISSION_DENIED;
6078 }
6079 if (permission == null) {
6080 return PackageManager.PERMISSION_GRANTED;
6081 }
6082 try {
6083 return ActivityThread.getPackageManager()
6084 .checkUidPermission(permission, uid);
6085 } catch (RemoteException e) {
6086 // Should never happen, but if it does... deny!
6087 Log.e(TAG, "PackageManager is dead?!?", e);
6088 }
6089 return PackageManager.PERMISSION_DENIED;
6090 }
6091
6092 /**
6093 * As the only public entry point for permissions checking, this method
6094 * can enforce the semantic that requesting a check on a null global
6095 * permission is automatically denied. (Internally a null permission
6096 * string is used when calling {@link #checkComponentPermission} in cases
6097 * when only uid-based security is needed.)
6098 *
6099 * This can be called with or without the global lock held.
6100 */
6101 public int checkPermission(String permission, int pid, int uid) {
6102 if (permission == null) {
6103 return PackageManager.PERMISSION_DENIED;
6104 }
6105 return checkComponentPermission(permission, pid, uid, -1);
6106 }
6107
6108 /**
6109 * Binder IPC calls go through the public entry point.
6110 * This can be called with or without the global lock held.
6111 */
6112 int checkCallingPermission(String permission) {
6113 return checkPermission(permission,
6114 Binder.getCallingPid(),
6115 Binder.getCallingUid());
6116 }
6117
6118 /**
6119 * This can be called with or without the global lock held.
6120 */
6121 void enforceCallingPermission(String permission, String func) {
6122 if (checkCallingPermission(permission)
6123 == PackageManager.PERMISSION_GRANTED) {
6124 return;
6125 }
6126
6127 String msg = "Permission Denial: " + func + " from pid="
6128 + Binder.getCallingPid()
6129 + ", uid=" + Binder.getCallingUid()
6130 + " requires " + permission;
6131 Log.w(TAG, msg);
6132 throw new SecurityException(msg);
6133 }
6134
6135 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6136 ProviderInfo pi, int uid, int modeFlags) {
6137 try {
6138 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6139 if ((pi.readPermission != null) &&
6140 (pm.checkUidPermission(pi.readPermission, uid)
6141 != PackageManager.PERMISSION_GRANTED)) {
6142 return false;
6143 }
6144 }
6145 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6146 if ((pi.writePermission != null) &&
6147 (pm.checkUidPermission(pi.writePermission, uid)
6148 != PackageManager.PERMISSION_GRANTED)) {
6149 return false;
6150 }
6151 }
6152 return true;
6153 } catch (RemoteException e) {
6154 return false;
6155 }
6156 }
6157
6158 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6159 int modeFlags) {
6160 // Root gets to do everything.
6161 if (uid == 0 || !Process.supportsProcesses()) {
6162 return true;
6163 }
6164 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6165 if (perms == null) return false;
6166 UriPermission perm = perms.get(uri);
6167 if (perm == null) return false;
6168 return (modeFlags&perm.modeFlags) == modeFlags;
6169 }
6170
6171 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6172 // Another redirected-binder-call permissions check as in
6173 // {@link checkComponentPermission}.
6174 Identity tlsIdentity = sCallerIdentity.get();
6175 if (tlsIdentity != null) {
6176 uid = tlsIdentity.uid;
6177 pid = tlsIdentity.pid;
6178 }
6179
6180 // Our own process gets to do everything.
6181 if (pid == MY_PID) {
6182 return PackageManager.PERMISSION_GRANTED;
6183 }
6184 synchronized(this) {
6185 return checkUriPermissionLocked(uri, uid, modeFlags)
6186 ? PackageManager.PERMISSION_GRANTED
6187 : PackageManager.PERMISSION_DENIED;
6188 }
6189 }
6190
6191 private void grantUriPermissionLocked(int callingUid,
6192 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6193 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6194 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6195 if (modeFlags == 0) {
6196 return;
6197 }
6198
6199 final IPackageManager pm = ActivityThread.getPackageManager();
6200
6201 // If this is not a content: uri, we can't do anything with it.
6202 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6203 return;
6204 }
6205
6206 String name = uri.getAuthority();
6207 ProviderInfo pi = null;
6208 ContentProviderRecord cpr
6209 = (ContentProviderRecord)mProvidersByName.get(name);
6210 if (cpr != null) {
6211 pi = cpr.info;
6212 } else {
6213 try {
6214 pi = pm.resolveContentProvider(name,
6215 PackageManager.GET_URI_PERMISSION_PATTERNS);
6216 } catch (RemoteException ex) {
6217 }
6218 }
6219 if (pi == null) {
6220 Log.w(TAG, "No content provider found for: " + name);
6221 return;
6222 }
6223
6224 int targetUid;
6225 try {
6226 targetUid = pm.getPackageUid(targetPkg);
6227 if (targetUid < 0) {
6228 return;
6229 }
6230 } catch (RemoteException ex) {
6231 return;
6232 }
6233
6234 // First... does the target actually need this permission?
6235 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6236 // No need to grant the target this permission.
6237 return;
6238 }
6239
6240 // Second... maybe someone else has already granted the
6241 // permission?
6242 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6243 // No need to grant the target this permission.
6244 return;
6245 }
6246
6247 // Third... is the provider allowing granting of URI permissions?
6248 if (!pi.grantUriPermissions) {
6249 throw new SecurityException("Provider " + pi.packageName
6250 + "/" + pi.name
6251 + " does not allow granting of Uri permissions (uri "
6252 + uri + ")");
6253 }
6254 if (pi.uriPermissionPatterns != null) {
6255 final int N = pi.uriPermissionPatterns.length;
6256 boolean allowed = false;
6257 for (int i=0; i<N; i++) {
6258 if (pi.uriPermissionPatterns[i] != null
6259 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6260 allowed = true;
6261 break;
6262 }
6263 }
6264 if (!allowed) {
6265 throw new SecurityException("Provider " + pi.packageName
6266 + "/" + pi.name
6267 + " does not allow granting of permission to path of Uri "
6268 + uri);
6269 }
6270 }
6271
6272 // Fourth... does the caller itself have permission to access
6273 // this uri?
6274 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6275 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6276 throw new SecurityException("Uid " + callingUid
6277 + " does not have permission to uri " + uri);
6278 }
6279 }
6280
6281 // Okay! So here we are: the caller has the assumed permission
6282 // to the uri, and the target doesn't. Let's now give this to
6283 // the target.
6284
6285 HashMap<Uri, UriPermission> targetUris
6286 = mGrantedUriPermissions.get(targetUid);
6287 if (targetUris == null) {
6288 targetUris = new HashMap<Uri, UriPermission>();
6289 mGrantedUriPermissions.put(targetUid, targetUris);
6290 }
6291
6292 UriPermission perm = targetUris.get(uri);
6293 if (perm == null) {
6294 perm = new UriPermission(targetUid, uri);
6295 targetUris.put(uri, perm);
6296
6297 }
6298 perm.modeFlags |= modeFlags;
6299 if (activity == null) {
6300 perm.globalModeFlags |= modeFlags;
6301 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6302 perm.readActivities.add(activity);
6303 if (activity.readUriPermissions == null) {
6304 activity.readUriPermissions = new HashSet<UriPermission>();
6305 }
6306 activity.readUriPermissions.add(perm);
6307 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6308 perm.writeActivities.add(activity);
6309 if (activity.writeUriPermissions == null) {
6310 activity.writeUriPermissions = new HashSet<UriPermission>();
6311 }
6312 activity.writeUriPermissions.add(perm);
6313 }
6314 }
6315
6316 private void grantUriPermissionFromIntentLocked(int callingUid,
6317 String targetPkg, Intent intent, HistoryRecord activity) {
6318 if (intent == null) {
6319 return;
6320 }
6321 Uri data = intent.getData();
6322 if (data == null) {
6323 return;
6324 }
6325 grantUriPermissionLocked(callingUid, targetPkg, data,
6326 intent.getFlags(), activity);
6327 }
6328
6329 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6330 Uri uri, int modeFlags) {
6331 synchronized(this) {
6332 final ProcessRecord r = getRecordForAppLocked(caller);
6333 if (r == null) {
6334 throw new SecurityException("Unable to find app for caller "
6335 + caller
6336 + " when granting permission to uri " + uri);
6337 }
6338 if (targetPkg == null) {
6339 Log.w(TAG, "grantUriPermission: null target");
6340 return;
6341 }
6342 if (uri == null) {
6343 Log.w(TAG, "grantUriPermission: null uri");
6344 return;
6345 }
6346
6347 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6348 null);
6349 }
6350 }
6351
6352 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6353 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6354 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6355 HashMap<Uri, UriPermission> perms
6356 = mGrantedUriPermissions.get(perm.uid);
6357 if (perms != null) {
6358 perms.remove(perm.uri);
6359 if (perms.size() == 0) {
6360 mGrantedUriPermissions.remove(perm.uid);
6361 }
6362 }
6363 }
6364 }
6365
6366 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6367 if (activity.readUriPermissions != null) {
6368 for (UriPermission perm : activity.readUriPermissions) {
6369 perm.readActivities.remove(activity);
6370 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6371 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6372 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6373 removeUriPermissionIfNeededLocked(perm);
6374 }
6375 }
6376 }
6377 if (activity.writeUriPermissions != null) {
6378 for (UriPermission perm : activity.writeUriPermissions) {
6379 perm.writeActivities.remove(activity);
6380 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6381 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6382 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6383 removeUriPermissionIfNeededLocked(perm);
6384 }
6385 }
6386 }
6387 }
6388
6389 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6390 int modeFlags) {
6391 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6392 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6393 if (modeFlags == 0) {
6394 return;
6395 }
6396
6397 final IPackageManager pm = ActivityThread.getPackageManager();
6398
6399 final String authority = uri.getAuthority();
6400 ProviderInfo pi = null;
6401 ContentProviderRecord cpr
6402 = (ContentProviderRecord)mProvidersByName.get(authority);
6403 if (cpr != null) {
6404 pi = cpr.info;
6405 } else {
6406 try {
6407 pi = pm.resolveContentProvider(authority,
6408 PackageManager.GET_URI_PERMISSION_PATTERNS);
6409 } catch (RemoteException ex) {
6410 }
6411 }
6412 if (pi == null) {
6413 Log.w(TAG, "No content provider found for: " + authority);
6414 return;
6415 }
6416
6417 // Does the caller have this permission on the URI?
6418 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6419 // Right now, if you are not the original owner of the permission,
6420 // you are not allowed to revoke it.
6421 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6422 throw new SecurityException("Uid " + callingUid
6423 + " does not have permission to uri " + uri);
6424 //}
6425 }
6426
6427 // Go through all of the permissions and remove any that match.
6428 final List<String> SEGMENTS = uri.getPathSegments();
6429 if (SEGMENTS != null) {
6430 final int NS = SEGMENTS.size();
6431 int N = mGrantedUriPermissions.size();
6432 for (int i=0; i<N; i++) {
6433 HashMap<Uri, UriPermission> perms
6434 = mGrantedUriPermissions.valueAt(i);
6435 Iterator<UriPermission> it = perms.values().iterator();
6436 toploop:
6437 while (it.hasNext()) {
6438 UriPermission perm = it.next();
6439 Uri targetUri = perm.uri;
6440 if (!authority.equals(targetUri.getAuthority())) {
6441 continue;
6442 }
6443 List<String> targetSegments = targetUri.getPathSegments();
6444 if (targetSegments == null) {
6445 continue;
6446 }
6447 if (targetSegments.size() < NS) {
6448 continue;
6449 }
6450 for (int j=0; j<NS; j++) {
6451 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6452 continue toploop;
6453 }
6454 }
6455 perm.clearModes(modeFlags);
6456 if (perm.modeFlags == 0) {
6457 it.remove();
6458 }
6459 }
6460 if (perms.size() == 0) {
6461 mGrantedUriPermissions.remove(
6462 mGrantedUriPermissions.keyAt(i));
6463 N--;
6464 i--;
6465 }
6466 }
6467 }
6468 }
6469
6470 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6471 int modeFlags) {
6472 synchronized(this) {
6473 final ProcessRecord r = getRecordForAppLocked(caller);
6474 if (r == null) {
6475 throw new SecurityException("Unable to find app for caller "
6476 + caller
6477 + " when revoking permission to uri " + uri);
6478 }
6479 if (uri == null) {
6480 Log.w(TAG, "revokeUriPermission: null uri");
6481 return;
6482 }
6483
6484 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6485 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6486 if (modeFlags == 0) {
6487 return;
6488 }
6489
6490 final IPackageManager pm = ActivityThread.getPackageManager();
6491
6492 final String authority = uri.getAuthority();
6493 ProviderInfo pi = null;
6494 ContentProviderRecord cpr
6495 = (ContentProviderRecord)mProvidersByName.get(authority);
6496 if (cpr != null) {
6497 pi = cpr.info;
6498 } else {
6499 try {
6500 pi = pm.resolveContentProvider(authority,
6501 PackageManager.GET_URI_PERMISSION_PATTERNS);
6502 } catch (RemoteException ex) {
6503 }
6504 }
6505 if (pi == null) {
6506 Log.w(TAG, "No content provider found for: " + authority);
6507 return;
6508 }
6509
6510 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6511 }
6512 }
6513
6514 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6515 synchronized (this) {
6516 ProcessRecord app =
6517 who != null ? getRecordForAppLocked(who) : null;
6518 if (app == null) return;
6519
6520 Message msg = Message.obtain();
6521 msg.what = WAIT_FOR_DEBUGGER_MSG;
6522 msg.obj = app;
6523 msg.arg1 = waiting ? 1 : 0;
6524 mHandler.sendMessage(msg);
6525 }
6526 }
6527
6528 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6529 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006530 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006531 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006532 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006533 }
6534
6535 // =========================================================
6536 // TASK MANAGEMENT
6537 // =========================================================
6538
6539 public List getTasks(int maxNum, int flags,
6540 IThumbnailReceiver receiver) {
6541 ArrayList list = new ArrayList();
6542
6543 PendingThumbnailsRecord pending = null;
6544 IApplicationThread topThumbnail = null;
6545 HistoryRecord topRecord = null;
6546
6547 synchronized(this) {
6548 if (localLOGV) Log.v(
6549 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6550 + ", receiver=" + receiver);
6551
6552 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6553 != PackageManager.PERMISSION_GRANTED) {
6554 if (receiver != null) {
6555 // If the caller wants to wait for pending thumbnails,
6556 // it ain't gonna get them.
6557 try {
6558 receiver.finished();
6559 } catch (RemoteException ex) {
6560 }
6561 }
6562 String msg = "Permission Denial: getTasks() from pid="
6563 + Binder.getCallingPid()
6564 + ", uid=" + Binder.getCallingUid()
6565 + " requires " + android.Manifest.permission.GET_TASKS;
6566 Log.w(TAG, msg);
6567 throw new SecurityException(msg);
6568 }
6569
6570 int pos = mHistory.size()-1;
6571 HistoryRecord next =
6572 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6573 HistoryRecord top = null;
6574 CharSequence topDescription = null;
6575 TaskRecord curTask = null;
6576 int numActivities = 0;
6577 int numRunning = 0;
6578 while (pos >= 0 && maxNum > 0) {
6579 final HistoryRecord r = next;
6580 pos--;
6581 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6582
6583 // Initialize state for next task if needed.
6584 if (top == null ||
6585 (top.state == ActivityState.INITIALIZING
6586 && top.task == r.task)) {
6587 top = r;
6588 topDescription = r.description;
6589 curTask = r.task;
6590 numActivities = numRunning = 0;
6591 }
6592
6593 // Add 'r' into the current task.
6594 numActivities++;
6595 if (r.app != null && r.app.thread != null) {
6596 numRunning++;
6597 }
6598 if (topDescription == null) {
6599 topDescription = r.description;
6600 }
6601
6602 if (localLOGV) Log.v(
6603 TAG, r.intent.getComponent().flattenToShortString()
6604 + ": task=" + r.task);
6605
6606 // If the next one is a different task, generate a new
6607 // TaskInfo entry for what we have.
6608 if (next == null || next.task != curTask) {
6609 ActivityManager.RunningTaskInfo ci
6610 = new ActivityManager.RunningTaskInfo();
6611 ci.id = curTask.taskId;
6612 ci.baseActivity = r.intent.getComponent();
6613 ci.topActivity = top.intent.getComponent();
6614 ci.thumbnail = top.thumbnail;
6615 ci.description = topDescription;
6616 ci.numActivities = numActivities;
6617 ci.numRunning = numRunning;
6618 //System.out.println(
6619 // "#" + maxNum + ": " + " descr=" + ci.description);
6620 if (ci.thumbnail == null && receiver != null) {
6621 if (localLOGV) Log.v(
6622 TAG, "State=" + top.state + "Idle=" + top.idle
6623 + " app=" + top.app
6624 + " thr=" + (top.app != null ? top.app.thread : null));
6625 if (top.state == ActivityState.RESUMED
6626 || top.state == ActivityState.PAUSING) {
6627 if (top.idle && top.app != null
6628 && top.app.thread != null) {
6629 topRecord = top;
6630 topThumbnail = top.app.thread;
6631 } else {
6632 top.thumbnailNeeded = true;
6633 }
6634 }
6635 if (pending == null) {
6636 pending = new PendingThumbnailsRecord(receiver);
6637 }
6638 pending.pendingRecords.add(top);
6639 }
6640 list.add(ci);
6641 maxNum--;
6642 top = null;
6643 }
6644 }
6645
6646 if (pending != null) {
6647 mPendingThumbnails.add(pending);
6648 }
6649 }
6650
6651 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6652
6653 if (topThumbnail != null) {
6654 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6655 try {
6656 topThumbnail.requestThumbnail(topRecord);
6657 } catch (Exception e) {
6658 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6659 sendPendingThumbnail(null, topRecord, null, null, true);
6660 }
6661 }
6662
6663 if (pending == null && receiver != null) {
6664 // In this case all thumbnails were available and the client
6665 // is being asked to be told when the remaining ones come in...
6666 // which is unusually, since the top-most currently running
6667 // activity should never have a canned thumbnail! Oh well.
6668 try {
6669 receiver.finished();
6670 } catch (RemoteException ex) {
6671 }
6672 }
6673
6674 return list;
6675 }
6676
6677 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6678 int flags) {
6679 synchronized (this) {
6680 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6681 "getRecentTasks()");
6682
6683 final int N = mRecentTasks.size();
6684 ArrayList<ActivityManager.RecentTaskInfo> res
6685 = new ArrayList<ActivityManager.RecentTaskInfo>(
6686 maxNum < N ? maxNum : N);
6687 for (int i=0; i<N && maxNum > 0; i++) {
6688 TaskRecord tr = mRecentTasks.get(i);
6689 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6690 || (tr.intent == null)
6691 || ((tr.intent.getFlags()
6692 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6693 ActivityManager.RecentTaskInfo rti
6694 = new ActivityManager.RecentTaskInfo();
6695 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6696 rti.baseIntent = new Intent(
6697 tr.intent != null ? tr.intent : tr.affinityIntent);
6698 rti.origActivity = tr.origActivity;
6699 res.add(rti);
6700 maxNum--;
6701 }
6702 }
6703 return res;
6704 }
6705 }
6706
6707 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6708 int j;
6709 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6710 TaskRecord jt = startTask;
6711
6712 // First look backwards
6713 for (j=startIndex-1; j>=0; j--) {
6714 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6715 if (r.task != jt) {
6716 jt = r.task;
6717 if (affinity.equals(jt.affinity)) {
6718 return j;
6719 }
6720 }
6721 }
6722
6723 // Now look forwards
6724 final int N = mHistory.size();
6725 jt = startTask;
6726 for (j=startIndex+1; j<N; j++) {
6727 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6728 if (r.task != jt) {
6729 if (affinity.equals(jt.affinity)) {
6730 return j;
6731 }
6732 jt = r.task;
6733 }
6734 }
6735
6736 // Might it be at the top?
6737 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6738 return N-1;
6739 }
6740
6741 return -1;
6742 }
6743
6744 /**
6745 * Perform a reset of the given task, if needed as part of launching it.
6746 * Returns the new HistoryRecord at the top of the task.
6747 */
6748 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6749 HistoryRecord newActivity) {
6750 boolean forceReset = (newActivity.info.flags
6751 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6752 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6753 if ((newActivity.info.flags
6754 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6755 forceReset = true;
6756 }
6757 }
6758
6759 final TaskRecord task = taskTop.task;
6760
6761 // We are going to move through the history list so that we can look
6762 // at each activity 'target' with 'below' either the interesting
6763 // activity immediately below it in the stack or null.
6764 HistoryRecord target = null;
6765 int targetI = 0;
6766 int taskTopI = -1;
6767 int replyChainEnd = -1;
6768 int lastReparentPos = -1;
6769 for (int i=mHistory.size()-1; i>=-1; i--) {
6770 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6771
6772 if (below != null && below.finishing) {
6773 continue;
6774 }
6775 if (target == null) {
6776 target = below;
6777 targetI = i;
6778 // If we were in the middle of a reply chain before this
6779 // task, it doesn't appear like the root of the chain wants
6780 // anything interesting, so drop it.
6781 replyChainEnd = -1;
6782 continue;
6783 }
6784
6785 final int flags = target.info.flags;
6786
6787 final boolean finishOnTaskLaunch =
6788 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6789 final boolean allowTaskReparenting =
6790 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6791
6792 if (target.task == task) {
6793 // We are inside of the task being reset... we'll either
6794 // finish this activity, push it out for another task,
6795 // or leave it as-is. We only do this
6796 // for activities that are not the root of the task (since
6797 // if we finish the root, we may no longer have the task!).
6798 if (taskTopI < 0) {
6799 taskTopI = targetI;
6800 }
6801 if (below != null && below.task == task) {
6802 final boolean clearWhenTaskReset =
6803 (target.intent.getFlags()
6804 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006805 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006806 // If this activity is sending a reply to a previous
6807 // activity, we can't do anything with it now until
6808 // we reach the start of the reply chain.
6809 // XXX note that we are assuming the result is always
6810 // to the previous activity, which is almost always
6811 // the case but we really shouldn't count on.
6812 if (replyChainEnd < 0) {
6813 replyChainEnd = targetI;
6814 }
Ed Heyl73798232009-03-24 21:32:21 -07006815 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006816 && target.taskAffinity != null
6817 && !target.taskAffinity.equals(task.affinity)) {
6818 // If this activity has an affinity for another
6819 // task, then we need to move it out of here. We will
6820 // move it as far out of the way as possible, to the
6821 // bottom of the activity stack. This also keeps it
6822 // correctly ordered with any activities we previously
6823 // moved.
6824 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6825 if (target.taskAffinity != null
6826 && target.taskAffinity.equals(p.task.affinity)) {
6827 // If the activity currently at the bottom has the
6828 // same task affinity as the one we are moving,
6829 // then merge it into the same task.
6830 target.task = p.task;
6831 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6832 + " out to bottom task " + p.task);
6833 } else {
6834 mCurTask++;
6835 if (mCurTask <= 0) {
6836 mCurTask = 1;
6837 }
6838 target.task = new TaskRecord(mCurTask, target.info, null,
6839 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6840 target.task.affinityIntent = target.intent;
6841 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6842 + " out to new task " + target.task);
6843 }
6844 mWindowManager.setAppGroupId(target, task.taskId);
6845 if (replyChainEnd < 0) {
6846 replyChainEnd = targetI;
6847 }
6848 int dstPos = 0;
6849 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6850 p = (HistoryRecord)mHistory.get(srcPos);
6851 if (p.finishing) {
6852 continue;
6853 }
6854 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6855 + " out to target's task " + target.task);
6856 task.numActivities--;
6857 p.task = target.task;
6858 target.task.numActivities++;
6859 mHistory.remove(srcPos);
6860 mHistory.add(dstPos, p);
6861 mWindowManager.moveAppToken(dstPos, p);
6862 mWindowManager.setAppGroupId(p, p.task.taskId);
6863 dstPos++;
6864 if (VALIDATE_TOKENS) {
6865 mWindowManager.validateAppTokens(mHistory);
6866 }
6867 i++;
6868 }
6869 if (taskTop == p) {
6870 taskTop = below;
6871 }
6872 if (taskTopI == replyChainEnd) {
6873 taskTopI = -1;
6874 }
6875 replyChainEnd = -1;
6876 addRecentTask(target.task);
6877 } else if (forceReset || finishOnTaskLaunch
6878 || clearWhenTaskReset) {
6879 // If the activity should just be removed -- either
6880 // because it asks for it, or the task should be
6881 // cleared -- then finish it and anything that is
6882 // part of its reply chain.
6883 if (clearWhenTaskReset) {
6884 // In this case, we want to finish this activity
6885 // and everything above it, so be sneaky and pretend
6886 // like these are all in the reply chain.
6887 replyChainEnd = targetI+1;
6888 while (replyChainEnd < mHistory.size() &&
6889 ((HistoryRecord)mHistory.get(
6890 replyChainEnd)).task == task) {
6891 replyChainEnd++;
6892 }
6893 replyChainEnd--;
6894 } else if (replyChainEnd < 0) {
6895 replyChainEnd = targetI;
6896 }
6897 HistoryRecord p = null;
6898 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6899 p = (HistoryRecord)mHistory.get(srcPos);
6900 if (p.finishing) {
6901 continue;
6902 }
6903 if (finishActivityLocked(p, srcPos,
6904 Activity.RESULT_CANCELED, null, "reset")) {
6905 replyChainEnd--;
6906 srcPos--;
6907 }
6908 }
6909 if (taskTop == p) {
6910 taskTop = below;
6911 }
6912 if (taskTopI == replyChainEnd) {
6913 taskTopI = -1;
6914 }
6915 replyChainEnd = -1;
6916 } else {
6917 // If we were in the middle of a chain, well the
6918 // activity that started it all doesn't want anything
6919 // special, so leave it all as-is.
6920 replyChainEnd = -1;
6921 }
6922 } else {
6923 // Reached the bottom of the task -- any reply chain
6924 // should be left as-is.
6925 replyChainEnd = -1;
6926 }
6927
6928 } else if (target.resultTo != null) {
6929 // If this activity is sending a reply to a previous
6930 // activity, we can't do anything with it now until
6931 // we reach the start of the reply chain.
6932 // XXX note that we are assuming the result is always
6933 // to the previous activity, which is almost always
6934 // the case but we really shouldn't count on.
6935 if (replyChainEnd < 0) {
6936 replyChainEnd = targetI;
6937 }
6938
6939 } else if (taskTopI >= 0 && allowTaskReparenting
6940 && task.affinity != null
6941 && task.affinity.equals(target.taskAffinity)) {
6942 // We are inside of another task... if this activity has
6943 // an affinity for our task, then either remove it if we are
6944 // clearing or move it over to our task. Note that
6945 // we currently punt on the case where we are resetting a
6946 // task that is not at the top but who has activities above
6947 // with an affinity to it... this is really not a normal
6948 // case, and we will need to later pull that task to the front
6949 // and usually at that point we will do the reset and pick
6950 // up those remaining activities. (This only happens if
6951 // someone starts an activity in a new task from an activity
6952 // in a task that is not currently on top.)
6953 if (forceReset || finishOnTaskLaunch) {
6954 if (replyChainEnd < 0) {
6955 replyChainEnd = targetI;
6956 }
6957 HistoryRecord p = null;
6958 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6959 p = (HistoryRecord)mHistory.get(srcPos);
6960 if (p.finishing) {
6961 continue;
6962 }
6963 if (finishActivityLocked(p, srcPos,
6964 Activity.RESULT_CANCELED, null, "reset")) {
6965 taskTopI--;
6966 lastReparentPos--;
6967 replyChainEnd--;
6968 srcPos--;
6969 }
6970 }
6971 replyChainEnd = -1;
6972 } else {
6973 if (replyChainEnd < 0) {
6974 replyChainEnd = targetI;
6975 }
6976 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6977 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6978 if (p.finishing) {
6979 continue;
6980 }
6981 if (lastReparentPos < 0) {
6982 lastReparentPos = taskTopI;
6983 taskTop = p;
6984 } else {
6985 lastReparentPos--;
6986 }
6987 mHistory.remove(srcPos);
6988 p.task.numActivities--;
6989 p.task = task;
6990 mHistory.add(lastReparentPos, p);
6991 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6992 + " in to resetting task " + task);
6993 task.numActivities++;
6994 mWindowManager.moveAppToken(lastReparentPos, p);
6995 mWindowManager.setAppGroupId(p, p.task.taskId);
6996 if (VALIDATE_TOKENS) {
6997 mWindowManager.validateAppTokens(mHistory);
6998 }
6999 }
7000 replyChainEnd = -1;
7001
7002 // Now we've moved it in to place... but what if this is
7003 // a singleTop activity and we have put it on top of another
7004 // instance of the same activity? Then we drop the instance
7005 // below so it remains singleTop.
7006 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
7007 for (int j=lastReparentPos-1; j>=0; j--) {
7008 HistoryRecord p = (HistoryRecord)mHistory.get(j);
7009 if (p.finishing) {
7010 continue;
7011 }
7012 if (p.intent.getComponent().equals(target.intent.getComponent())) {
7013 if (finishActivityLocked(p, j,
7014 Activity.RESULT_CANCELED, null, "replace")) {
7015 taskTopI--;
7016 lastReparentPos--;
7017 }
7018 }
7019 }
7020 }
7021 }
7022 }
7023
7024 target = below;
7025 targetI = i;
7026 }
7027
7028 return taskTop;
7029 }
7030
7031 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007032 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007033 */
7034 public void moveTaskToFront(int task) {
7035 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7036 "moveTaskToFront()");
7037
7038 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007039 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7040 Binder.getCallingUid(), "Task to front")) {
7041 return;
7042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007043 final long origId = Binder.clearCallingIdentity();
7044 try {
7045 int N = mRecentTasks.size();
7046 for (int i=0; i<N; i++) {
7047 TaskRecord tr = mRecentTasks.get(i);
7048 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007049 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007050 return;
7051 }
7052 }
7053 for (int i=mHistory.size()-1; i>=0; i--) {
7054 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7055 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007056 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007057 return;
7058 }
7059 }
7060 } finally {
7061 Binder.restoreCallingIdentity(origId);
7062 }
7063 }
7064 }
7065
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007066 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007067 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7068
7069 final int task = tr.taskId;
7070 int top = mHistory.size()-1;
7071
7072 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7073 // nothing to do!
7074 return;
7075 }
7076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007077 ArrayList moved = new ArrayList();
7078
7079 // Applying the affinities may have removed entries from the history,
7080 // so get the size again.
7081 top = mHistory.size()-1;
7082 int pos = top;
7083
7084 // Shift all activities with this task up to the top
7085 // of the stack, keeping them in the same internal order.
7086 while (pos >= 0) {
7087 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7088 if (localLOGV) Log.v(
7089 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7090 boolean first = true;
7091 if (r.task.taskId == task) {
7092 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7093 mHistory.remove(pos);
7094 mHistory.add(top, r);
7095 moved.add(0, r);
7096 top--;
7097 if (first) {
7098 addRecentTask(r.task);
7099 first = false;
7100 }
7101 }
7102 pos--;
7103 }
7104
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007105 if (DEBUG_TRANSITION) Log.v(TAG,
7106 "Prepare to front transition: task=" + tr);
7107 if (reason != null &&
7108 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7109 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7110 HistoryRecord r = topRunningActivityLocked(null);
7111 if (r != null) {
7112 mNoAnimActivities.add(r);
7113 }
7114 } else {
7115 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7116 }
7117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007118 mWindowManager.moveAppTokensToTop(moved);
7119 if (VALIDATE_TOKENS) {
7120 mWindowManager.validateAppTokens(mHistory);
7121 }
7122
7123 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007124 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007125 }
7126
7127 private final void finishTaskMove(int task) {
7128 resumeTopActivityLocked(null);
7129 }
7130
7131 public void moveTaskToBack(int task) {
7132 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7133 "moveTaskToBack()");
7134
7135 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007136 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7137 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7138 Binder.getCallingUid(), "Task to back")) {
7139 return;
7140 }
7141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007142 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007143 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007144 Binder.restoreCallingIdentity(origId);
7145 }
7146 }
7147
7148 /**
7149 * Moves an activity, and all of the other activities within the same task, to the bottom
7150 * of the history stack. The activity's order within the task is unchanged.
7151 *
7152 * @param token A reference to the activity we wish to move
7153 * @param nonRoot If false then this only works if the activity is the root
7154 * of a task; if true it will work for any activity in a task.
7155 * @return Returns true if the move completed, false if not.
7156 */
7157 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7158 synchronized(this) {
7159 final long origId = Binder.clearCallingIdentity();
7160 int taskId = getTaskForActivityLocked(token, !nonRoot);
7161 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007162 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007163 }
7164 Binder.restoreCallingIdentity(origId);
7165 }
7166 return false;
7167 }
7168
7169 /**
7170 * Worker method for rearranging history stack. Implements the function of moving all
7171 * activities for a specific task (gathering them if disjoint) into a single group at the
7172 * bottom of the stack.
7173 *
7174 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7175 * to premeptively cancel the move.
7176 *
7177 * @param task The taskId to collect and move to the bottom.
7178 * @return Returns true if the move completed, false if not.
7179 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007180 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007181 Log.i(TAG, "moveTaskToBack: " + task);
7182
7183 // If we have a watcher, preflight the move before committing to it. First check
7184 // for *other* available tasks, but if none are available, then try again allowing the
7185 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007186 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007187 HistoryRecord next = topRunningActivityLocked(null, task);
7188 if (next == null) {
7189 next = topRunningActivityLocked(null, 0);
7190 }
7191 if (next != null) {
7192 // ask watcher if this is allowed
7193 boolean moveOK = true;
7194 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007195 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007196 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007197 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007198 }
7199 if (!moveOK) {
7200 return false;
7201 }
7202 }
7203 }
7204
7205 ArrayList moved = new ArrayList();
7206
7207 if (DEBUG_TRANSITION) Log.v(TAG,
7208 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007209
7210 final int N = mHistory.size();
7211 int bottom = 0;
7212 int pos = 0;
7213
7214 // Shift all activities with this task down to the bottom
7215 // of the stack, keeping them in the same internal order.
7216 while (pos < N) {
7217 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7218 if (localLOGV) Log.v(
7219 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7220 if (r.task.taskId == task) {
7221 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7222 mHistory.remove(pos);
7223 mHistory.add(bottom, r);
7224 moved.add(r);
7225 bottom++;
7226 }
7227 pos++;
7228 }
7229
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007230 if (reason != null &&
7231 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7232 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7233 HistoryRecord r = topRunningActivityLocked(null);
7234 if (r != null) {
7235 mNoAnimActivities.add(r);
7236 }
7237 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007238 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007239 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007240 mWindowManager.moveAppTokensToBottom(moved);
7241 if (VALIDATE_TOKENS) {
7242 mWindowManager.validateAppTokens(mHistory);
7243 }
7244
7245 finishTaskMove(task);
7246 return true;
7247 }
7248
7249 public void moveTaskBackwards(int task) {
7250 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7251 "moveTaskBackwards()");
7252
7253 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007254 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7255 Binder.getCallingUid(), "Task backwards")) {
7256 return;
7257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007258 final long origId = Binder.clearCallingIdentity();
7259 moveTaskBackwardsLocked(task);
7260 Binder.restoreCallingIdentity(origId);
7261 }
7262 }
7263
7264 private final void moveTaskBackwardsLocked(int task) {
7265 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7266 }
7267
7268 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7269 synchronized(this) {
7270 return getTaskForActivityLocked(token, onlyRoot);
7271 }
7272 }
7273
7274 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7275 final int N = mHistory.size();
7276 TaskRecord lastTask = null;
7277 for (int i=0; i<N; i++) {
7278 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7279 if (r == token) {
7280 if (!onlyRoot || lastTask != r.task) {
7281 return r.task.taskId;
7282 }
7283 return -1;
7284 }
7285 lastTask = r.task;
7286 }
7287
7288 return -1;
7289 }
7290
7291 /**
7292 * Returns the top activity in any existing task matching the given
7293 * Intent. Returns null if no such task is found.
7294 */
7295 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7296 ComponentName cls = intent.getComponent();
7297 if (info.targetActivity != null) {
7298 cls = new ComponentName(info.packageName, info.targetActivity);
7299 }
7300
7301 TaskRecord cp = null;
7302
7303 final int N = mHistory.size();
7304 for (int i=(N-1); i>=0; i--) {
7305 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7306 if (!r.finishing && r.task != cp
7307 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7308 cp = r.task;
7309 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7310 // + "/aff=" + r.task.affinity + " to new cls="
7311 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7312 if (r.task.affinity != null) {
7313 if (r.task.affinity.equals(info.taskAffinity)) {
7314 //Log.i(TAG, "Found matching affinity!");
7315 return r;
7316 }
7317 } else if (r.task.intent != null
7318 && r.task.intent.getComponent().equals(cls)) {
7319 //Log.i(TAG, "Found matching class!");
7320 //dump();
7321 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7322 return r;
7323 } else if (r.task.affinityIntent != null
7324 && r.task.affinityIntent.getComponent().equals(cls)) {
7325 //Log.i(TAG, "Found matching class!");
7326 //dump();
7327 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7328 return r;
7329 }
7330 }
7331 }
7332
7333 return null;
7334 }
7335
7336 /**
7337 * Returns the first activity (starting from the top of the stack) that
7338 * is the same as the given activity. Returns null if no such activity
7339 * is found.
7340 */
7341 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7342 ComponentName cls = intent.getComponent();
7343 if (info.targetActivity != null) {
7344 cls = new ComponentName(info.packageName, info.targetActivity);
7345 }
7346
7347 final int N = mHistory.size();
7348 for (int i=(N-1); i>=0; i--) {
7349 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7350 if (!r.finishing) {
7351 if (r.intent.getComponent().equals(cls)) {
7352 //Log.i(TAG, "Found matching class!");
7353 //dump();
7354 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7355 return r;
7356 }
7357 }
7358 }
7359
7360 return null;
7361 }
7362
7363 public void finishOtherInstances(IBinder token, ComponentName className) {
7364 synchronized(this) {
7365 final long origId = Binder.clearCallingIdentity();
7366
7367 int N = mHistory.size();
7368 TaskRecord lastTask = null;
7369 for (int i=0; i<N; i++) {
7370 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7371 if (r.realActivity.equals(className)
7372 && r != token && lastTask != r.task) {
7373 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7374 null, "others")) {
7375 i--;
7376 N--;
7377 }
7378 }
7379 lastTask = r.task;
7380 }
7381
7382 Binder.restoreCallingIdentity(origId);
7383 }
7384 }
7385
7386 // =========================================================
7387 // THUMBNAILS
7388 // =========================================================
7389
7390 public void reportThumbnail(IBinder token,
7391 Bitmap thumbnail, CharSequence description) {
7392 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7393 final long origId = Binder.clearCallingIdentity();
7394 sendPendingThumbnail(null, token, thumbnail, description, true);
7395 Binder.restoreCallingIdentity(origId);
7396 }
7397
7398 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7399 Bitmap thumbnail, CharSequence description, boolean always) {
7400 TaskRecord task = null;
7401 ArrayList receivers = null;
7402
7403 //System.out.println("Send pending thumbnail: " + r);
7404
7405 synchronized(this) {
7406 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007407 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007408 if (index < 0) {
7409 return;
7410 }
7411 r = (HistoryRecord)mHistory.get(index);
7412 }
7413 if (thumbnail == null) {
7414 thumbnail = r.thumbnail;
7415 description = r.description;
7416 }
7417 if (thumbnail == null && !always) {
7418 // If there is no thumbnail, and this entry is not actually
7419 // going away, then abort for now and pick up the next
7420 // thumbnail we get.
7421 return;
7422 }
7423 task = r.task;
7424
7425 int N = mPendingThumbnails.size();
7426 int i=0;
7427 while (i<N) {
7428 PendingThumbnailsRecord pr =
7429 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7430 //System.out.println("Looking in " + pr.pendingRecords);
7431 if (pr.pendingRecords.remove(r)) {
7432 if (receivers == null) {
7433 receivers = new ArrayList();
7434 }
7435 receivers.add(pr);
7436 if (pr.pendingRecords.size() == 0) {
7437 pr.finished = true;
7438 mPendingThumbnails.remove(i);
7439 N--;
7440 continue;
7441 }
7442 }
7443 i++;
7444 }
7445 }
7446
7447 if (receivers != null) {
7448 final int N = receivers.size();
7449 for (int i=0; i<N; i++) {
7450 try {
7451 PendingThumbnailsRecord pr =
7452 (PendingThumbnailsRecord)receivers.get(i);
7453 pr.receiver.newThumbnail(
7454 task != null ? task.taskId : -1, thumbnail, description);
7455 if (pr.finished) {
7456 pr.receiver.finished();
7457 }
7458 } catch (Exception e) {
7459 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7460 }
7461 }
7462 }
7463 }
7464
7465 // =========================================================
7466 // CONTENT PROVIDERS
7467 // =========================================================
7468
7469 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7470 List providers = null;
7471 try {
7472 providers = ActivityThread.getPackageManager().
7473 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007474 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007475 } catch (RemoteException ex) {
7476 }
7477 if (providers != null) {
7478 final int N = providers.size();
7479 for (int i=0; i<N; i++) {
7480 ProviderInfo cpi =
7481 (ProviderInfo)providers.get(i);
7482 ContentProviderRecord cpr =
7483 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7484 if (cpr == null) {
7485 cpr = new ContentProviderRecord(cpi, app.info);
7486 mProvidersByClass.put(cpi.name, cpr);
7487 }
7488 app.pubProviders.put(cpi.name, cpr);
7489 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007490 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007491 }
7492 }
7493 return providers;
7494 }
7495
7496 private final String checkContentProviderPermissionLocked(
7497 ProviderInfo cpi, ProcessRecord r, int mode) {
7498 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7499 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7500 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7501 cpi.exported ? -1 : cpi.applicationInfo.uid)
7502 == PackageManager.PERMISSION_GRANTED
7503 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7504 return null;
7505 }
7506 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7507 cpi.exported ? -1 : cpi.applicationInfo.uid)
7508 == PackageManager.PERMISSION_GRANTED) {
7509 return null;
7510 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007511
7512 PathPermission[] pps = cpi.pathPermissions;
7513 if (pps != null) {
7514 int i = pps.length;
7515 while (i > 0) {
7516 i--;
7517 PathPermission pp = pps[i];
7518 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7519 cpi.exported ? -1 : cpi.applicationInfo.uid)
7520 == PackageManager.PERMISSION_GRANTED
7521 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7522 return null;
7523 }
7524 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7525 cpi.exported ? -1 : cpi.applicationInfo.uid)
7526 == PackageManager.PERMISSION_GRANTED) {
7527 return null;
7528 }
7529 }
7530 }
7531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007532 String msg = "Permission Denial: opening provider " + cpi.name
7533 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7534 + ", uid=" + callingUid + ") requires "
7535 + cpi.readPermission + " or " + cpi.writePermission;
7536 Log.w(TAG, msg);
7537 return msg;
7538 }
7539
7540 private final ContentProviderHolder getContentProviderImpl(
7541 IApplicationThread caller, String name) {
7542 ContentProviderRecord cpr;
7543 ProviderInfo cpi = null;
7544
7545 synchronized(this) {
7546 ProcessRecord r = null;
7547 if (caller != null) {
7548 r = getRecordForAppLocked(caller);
7549 if (r == null) {
7550 throw new SecurityException(
7551 "Unable to find app for caller " + caller
7552 + " (pid=" + Binder.getCallingPid()
7553 + ") when getting content provider " + name);
7554 }
7555 }
7556
7557 // First check if this content provider has been published...
7558 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7559 if (cpr != null) {
7560 cpi = cpr.info;
7561 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7562 return new ContentProviderHolder(cpi,
7563 cpi.readPermission != null
7564 ? cpi.readPermission : cpi.writePermission);
7565 }
7566
7567 if (r != null && cpr.canRunHere(r)) {
7568 // This provider has been published or is in the process
7569 // of being published... but it is also allowed to run
7570 // in the caller's process, so don't make a connection
7571 // and just let the caller instantiate its own instance.
7572 if (cpr.provider != null) {
7573 // don't give caller the provider object, it needs
7574 // to make its own.
7575 cpr = new ContentProviderRecord(cpr);
7576 }
7577 return cpr;
7578 }
7579
7580 final long origId = Binder.clearCallingIdentity();
7581
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007582 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007583 // return it right away.
7584 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007585 if (DEBUG_PROVIDER) Log.v(TAG,
7586 "Adding provider requested by "
7587 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007588 + cpr.info.processName);
7589 Integer cnt = r.conProviders.get(cpr);
7590 if (cnt == null) {
7591 r.conProviders.put(cpr, new Integer(1));
7592 } else {
7593 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007595 cpr.clients.add(r);
7596 } else {
7597 cpr.externals++;
7598 }
7599
7600 if (cpr.app != null) {
7601 updateOomAdjLocked(cpr.app);
7602 }
7603
7604 Binder.restoreCallingIdentity(origId);
7605
7606 } else {
7607 try {
7608 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007609 resolveContentProvider(name,
7610 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007611 } catch (RemoteException ex) {
7612 }
7613 if (cpi == null) {
7614 return null;
7615 }
7616
7617 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7618 return new ContentProviderHolder(cpi,
7619 cpi.readPermission != null
7620 ? cpi.readPermission : cpi.writePermission);
7621 }
7622
7623 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7624 final boolean firstClass = cpr == null;
7625 if (firstClass) {
7626 try {
7627 ApplicationInfo ai =
7628 ActivityThread.getPackageManager().
7629 getApplicationInfo(
7630 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007631 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007632 if (ai == null) {
7633 Log.w(TAG, "No package info for content provider "
7634 + cpi.name);
7635 return null;
7636 }
7637 cpr = new ContentProviderRecord(cpi, ai);
7638 } catch (RemoteException ex) {
7639 // pm is in same process, this will never happen.
7640 }
7641 }
7642
7643 if (r != null && cpr.canRunHere(r)) {
7644 // If this is a multiprocess provider, then just return its
7645 // info and allow the caller to instantiate it. Only do
7646 // this if the provider is the same user as the caller's
7647 // process, or can run as root (so can be in any process).
7648 return cpr;
7649 }
7650
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007651 if (DEBUG_PROVIDER) {
7652 RuntimeException e = new RuntimeException("here");
7653 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7654 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007655 }
7656
7657 // This is single process, and our app is now connecting to it.
7658 // See if we are already in the process of launching this
7659 // provider.
7660 final int N = mLaunchingProviders.size();
7661 int i;
7662 for (i=0; i<N; i++) {
7663 if (mLaunchingProviders.get(i) == cpr) {
7664 break;
7665 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007666 }
7667
7668 // If the provider is not already being launched, then get it
7669 // started.
7670 if (i >= N) {
7671 final long origId = Binder.clearCallingIdentity();
7672 ProcessRecord proc = startProcessLocked(cpi.processName,
7673 cpr.appInfo, false, 0, "content provider",
7674 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007675 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007676 if (proc == null) {
7677 Log.w(TAG, "Unable to launch app "
7678 + cpi.applicationInfo.packageName + "/"
7679 + cpi.applicationInfo.uid + " for provider "
7680 + name + ": process is bad");
7681 return null;
7682 }
7683 cpr.launchingApp = proc;
7684 mLaunchingProviders.add(cpr);
7685 Binder.restoreCallingIdentity(origId);
7686 }
7687
7688 // Make sure the provider is published (the same provider class
7689 // may be published under multiple names).
7690 if (firstClass) {
7691 mProvidersByClass.put(cpi.name, cpr);
7692 }
7693 mProvidersByName.put(name, cpr);
7694
7695 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007696 if (DEBUG_PROVIDER) Log.v(TAG,
7697 "Adding provider requested by "
7698 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007699 + cpr.info.processName);
7700 Integer cnt = r.conProviders.get(cpr);
7701 if (cnt == null) {
7702 r.conProviders.put(cpr, new Integer(1));
7703 } else {
7704 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7705 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007706 cpr.clients.add(r);
7707 } else {
7708 cpr.externals++;
7709 }
7710 }
7711 }
7712
7713 // Wait for the provider to be published...
7714 synchronized (cpr) {
7715 while (cpr.provider == null) {
7716 if (cpr.launchingApp == null) {
7717 Log.w(TAG, "Unable to launch app "
7718 + cpi.applicationInfo.packageName + "/"
7719 + cpi.applicationInfo.uid + " for provider "
7720 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007721 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007722 cpi.applicationInfo.packageName,
7723 cpi.applicationInfo.uid, name);
7724 return null;
7725 }
7726 try {
7727 cpr.wait();
7728 } catch (InterruptedException ex) {
7729 }
7730 }
7731 }
7732 return cpr;
7733 }
7734
7735 public final ContentProviderHolder getContentProvider(
7736 IApplicationThread caller, String name) {
7737 if (caller == null) {
7738 String msg = "null IApplicationThread when getting content provider "
7739 + name;
7740 Log.w(TAG, msg);
7741 throw new SecurityException(msg);
7742 }
7743
7744 return getContentProviderImpl(caller, name);
7745 }
7746
7747 private ContentProviderHolder getContentProviderExternal(String name) {
7748 return getContentProviderImpl(null, name);
7749 }
7750
7751 /**
7752 * Drop a content provider from a ProcessRecord's bookkeeping
7753 * @param cpr
7754 */
7755 public void removeContentProvider(IApplicationThread caller, String name) {
7756 synchronized (this) {
7757 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7758 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007759 // remove from mProvidersByClass
7760 if (DEBUG_PROVIDER) Log.v(TAG, name +
7761 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007762 return;
7763 }
7764 final ProcessRecord r = getRecordForAppLocked(caller);
7765 if (r == null) {
7766 throw new SecurityException(
7767 "Unable to find app for caller " + caller +
7768 " when removing content provider " + name);
7769 }
7770 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007771 ContentProviderRecord localCpr = (ContentProviderRecord)
7772 mProvidersByClass.get(cpr.info.name);
7773 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7774 + r.info.processName + " from process "
7775 + localCpr.appInfo.processName);
7776 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007777 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007778 Log.w(TAG, "removeContentProvider called on local provider: "
7779 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007780 return;
7781 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007782 Integer cnt = r.conProviders.get(localCpr);
7783 if (cnt == null || cnt.intValue() <= 1) {
7784 localCpr.clients.remove(r);
7785 r.conProviders.remove(localCpr);
7786 } else {
7787 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7788 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007789 }
7790 updateOomAdjLocked();
7791 }
7792 }
7793
7794 private void removeContentProviderExternal(String name) {
7795 synchronized (this) {
7796 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7797 if(cpr == null) {
7798 //remove from mProvidersByClass
7799 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7800 return;
7801 }
7802
7803 //update content provider record entry info
7804 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7805 localCpr.externals--;
7806 if (localCpr.externals < 0) {
7807 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7808 }
7809 updateOomAdjLocked();
7810 }
7811 }
7812
7813 public final void publishContentProviders(IApplicationThread caller,
7814 List<ContentProviderHolder> providers) {
7815 if (providers == null) {
7816 return;
7817 }
7818
7819 synchronized(this) {
7820 final ProcessRecord r = getRecordForAppLocked(caller);
7821 if (r == null) {
7822 throw new SecurityException(
7823 "Unable to find app for caller " + caller
7824 + " (pid=" + Binder.getCallingPid()
7825 + ") when publishing content providers");
7826 }
7827
7828 final long origId = Binder.clearCallingIdentity();
7829
7830 final int N = providers.size();
7831 for (int i=0; i<N; i++) {
7832 ContentProviderHolder src = providers.get(i);
7833 if (src == null || src.info == null || src.provider == null) {
7834 continue;
7835 }
7836 ContentProviderRecord dst =
7837 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7838 if (dst != null) {
7839 mProvidersByClass.put(dst.info.name, dst);
7840 String names[] = dst.info.authority.split(";");
7841 for (int j = 0; j < names.length; j++) {
7842 mProvidersByName.put(names[j], dst);
7843 }
7844
7845 int NL = mLaunchingProviders.size();
7846 int j;
7847 for (j=0; j<NL; j++) {
7848 if (mLaunchingProviders.get(j) == dst) {
7849 mLaunchingProviders.remove(j);
7850 j--;
7851 NL--;
7852 }
7853 }
7854 synchronized (dst) {
7855 dst.provider = src.provider;
7856 dst.app = r;
7857 dst.notifyAll();
7858 }
7859 updateOomAdjLocked(r);
7860 }
7861 }
7862
7863 Binder.restoreCallingIdentity(origId);
7864 }
7865 }
7866
7867 public static final void installSystemProviders() {
7868 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7869 List providers = mSelf.generateApplicationProvidersLocked(app);
7870 mSystemThread.installSystemProviders(providers);
7871 }
7872
7873 // =========================================================
7874 // GLOBAL MANAGEMENT
7875 // =========================================================
7876
7877 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7878 ApplicationInfo info, String customProcess) {
7879 String proc = customProcess != null ? customProcess : info.processName;
7880 BatteryStatsImpl.Uid.Proc ps = null;
7881 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7882 synchronized (stats) {
7883 ps = stats.getProcessStatsLocked(info.uid, proc);
7884 }
7885 return new ProcessRecord(ps, thread, info, proc);
7886 }
7887
7888 final ProcessRecord addAppLocked(ApplicationInfo info) {
7889 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7890
7891 if (app == null) {
7892 app = newProcessRecordLocked(null, info, null);
7893 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007894 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007895 }
7896
7897 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7898 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7899 app.persistent = true;
7900 app.maxAdj = CORE_SERVER_ADJ;
7901 }
7902 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7903 mPersistentStartingProcesses.add(app);
7904 startProcessLocked(app, "added application", app.processName);
7905 }
7906
7907 return app;
7908 }
7909
7910 public void unhandledBack() {
7911 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7912 "unhandledBack()");
7913
7914 synchronized(this) {
7915 int count = mHistory.size();
7916 if (Config.LOGD) Log.d(
7917 TAG, "Performing unhandledBack(): stack size = " + count);
7918 if (count > 1) {
7919 final long origId = Binder.clearCallingIdentity();
7920 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7921 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7922 Binder.restoreCallingIdentity(origId);
7923 }
7924 }
7925 }
7926
7927 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7928 String name = uri.getAuthority();
7929 ContentProviderHolder cph = getContentProviderExternal(name);
7930 ParcelFileDescriptor pfd = null;
7931 if (cph != null) {
7932 // We record the binder invoker's uid in thread-local storage before
7933 // going to the content provider to open the file. Later, in the code
7934 // that handles all permissions checks, we look for this uid and use
7935 // that rather than the Activity Manager's own uid. The effect is that
7936 // we do the check against the caller's permissions even though it looks
7937 // to the content provider like the Activity Manager itself is making
7938 // the request.
7939 sCallerIdentity.set(new Identity(
7940 Binder.getCallingPid(), Binder.getCallingUid()));
7941 try {
7942 pfd = cph.provider.openFile(uri, "r");
7943 } catch (FileNotFoundException e) {
7944 // do nothing; pfd will be returned null
7945 } finally {
7946 // Ensure that whatever happens, we clean up the identity state
7947 sCallerIdentity.remove();
7948 }
7949
7950 // We've got the fd now, so we're done with the provider.
7951 removeContentProviderExternal(name);
7952 } else {
7953 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7954 }
7955 return pfd;
7956 }
7957
7958 public void goingToSleep() {
7959 synchronized(this) {
7960 mSleeping = true;
7961 mWindowManager.setEventDispatching(false);
7962
7963 if (mResumedActivity != null) {
7964 pauseIfSleepingLocked();
7965 } else {
7966 Log.w(TAG, "goingToSleep with no resumed activity!");
7967 }
7968 }
7969 }
7970
Dianne Hackborn55280a92009-05-07 15:53:46 -07007971 public boolean shutdown(int timeout) {
7972 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7973 != PackageManager.PERMISSION_GRANTED) {
7974 throw new SecurityException("Requires permission "
7975 + android.Manifest.permission.SHUTDOWN);
7976 }
7977
7978 boolean timedout = false;
7979
7980 synchronized(this) {
7981 mShuttingDown = true;
7982 mWindowManager.setEventDispatching(false);
7983
7984 if (mResumedActivity != null) {
7985 pauseIfSleepingLocked();
7986 final long endTime = System.currentTimeMillis() + timeout;
7987 while (mResumedActivity != null || mPausingActivity != null) {
7988 long delay = endTime - System.currentTimeMillis();
7989 if (delay <= 0) {
7990 Log.w(TAG, "Activity manager shutdown timed out");
7991 timedout = true;
7992 break;
7993 }
7994 try {
7995 this.wait();
7996 } catch (InterruptedException e) {
7997 }
7998 }
7999 }
8000 }
8001
8002 mUsageStatsService.shutdown();
8003 mBatteryStatsService.shutdown();
8004
8005 return timedout;
8006 }
8007
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008008 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07008009 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008010 if (!mGoingToSleep.isHeld()) {
8011 mGoingToSleep.acquire();
8012 if (mLaunchingActivity.isHeld()) {
8013 mLaunchingActivity.release();
8014 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
8015 }
8016 }
8017
8018 // If we are not currently pausing an activity, get the current
8019 // one to pause. If we are pausing one, we will just let that stuff
8020 // run and release the wake lock when all done.
8021 if (mPausingActivity == null) {
8022 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8023 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8024 startPausingLocked(false, true);
8025 }
8026 }
8027 }
8028
8029 public void wakingUp() {
8030 synchronized(this) {
8031 if (mGoingToSleep.isHeld()) {
8032 mGoingToSleep.release();
8033 }
8034 mWindowManager.setEventDispatching(true);
8035 mSleeping = false;
8036 resumeTopActivityLocked(null);
8037 }
8038 }
8039
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008040 public void stopAppSwitches() {
8041 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8042 != PackageManager.PERMISSION_GRANTED) {
8043 throw new SecurityException("Requires permission "
8044 + android.Manifest.permission.STOP_APP_SWITCHES);
8045 }
8046
8047 synchronized(this) {
8048 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8049 + APP_SWITCH_DELAY_TIME;
8050 mDidAppSwitch = false;
8051 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8052 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8053 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8054 }
8055 }
8056
8057 public void resumeAppSwitches() {
8058 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8059 != PackageManager.PERMISSION_GRANTED) {
8060 throw new SecurityException("Requires permission "
8061 + android.Manifest.permission.STOP_APP_SWITCHES);
8062 }
8063
8064 synchronized(this) {
8065 // Note that we don't execute any pending app switches... we will
8066 // let those wait until either the timeout, or the next start
8067 // activity request.
8068 mAppSwitchesAllowedTime = 0;
8069 }
8070 }
8071
8072 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8073 String name) {
8074 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8075 return true;
8076 }
8077
8078 final int perm = checkComponentPermission(
8079 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8080 callingUid, -1);
8081 if (perm == PackageManager.PERMISSION_GRANTED) {
8082 return true;
8083 }
8084
8085 Log.w(TAG, name + " request from " + callingUid + " stopped");
8086 return false;
8087 }
8088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008089 public void setDebugApp(String packageName, boolean waitForDebugger,
8090 boolean persistent) {
8091 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8092 "setDebugApp()");
8093
8094 // Note that this is not really thread safe if there are multiple
8095 // callers into it at the same time, but that's not a situation we
8096 // care about.
8097 if (persistent) {
8098 final ContentResolver resolver = mContext.getContentResolver();
8099 Settings.System.putString(
8100 resolver, Settings.System.DEBUG_APP,
8101 packageName);
8102 Settings.System.putInt(
8103 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8104 waitForDebugger ? 1 : 0);
8105 }
8106
8107 synchronized (this) {
8108 if (!persistent) {
8109 mOrigDebugApp = mDebugApp;
8110 mOrigWaitForDebugger = mWaitForDebugger;
8111 }
8112 mDebugApp = packageName;
8113 mWaitForDebugger = waitForDebugger;
8114 mDebugTransient = !persistent;
8115 if (packageName != null) {
8116 final long origId = Binder.clearCallingIdentity();
8117 uninstallPackageLocked(packageName, -1, false);
8118 Binder.restoreCallingIdentity(origId);
8119 }
8120 }
8121 }
8122
8123 public void setAlwaysFinish(boolean enabled) {
8124 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8125 "setAlwaysFinish()");
8126
8127 Settings.System.putInt(
8128 mContext.getContentResolver(),
8129 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8130
8131 synchronized (this) {
8132 mAlwaysFinishActivities = enabled;
8133 }
8134 }
8135
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008136 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008137 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008138 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008139 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008140 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008141 }
8142 }
8143
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008144 public void registerActivityWatcher(IActivityWatcher watcher) {
8145 mWatchers.register(watcher);
8146 }
8147
8148 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8149 mWatchers.unregister(watcher);
8150 }
8151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008152 public final void enterSafeMode() {
8153 synchronized(this) {
8154 // It only makes sense to do this before the system is ready
8155 // and started launching other packages.
8156 if (!mSystemReady) {
8157 try {
8158 ActivityThread.getPackageManager().enterSafeMode();
8159 } catch (RemoteException e) {
8160 }
8161
8162 View v = LayoutInflater.from(mContext).inflate(
8163 com.android.internal.R.layout.safe_mode, null);
8164 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8165 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8166 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8167 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8168 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8169 lp.format = v.getBackground().getOpacity();
8170 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8171 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8172 ((WindowManager)mContext.getSystemService(
8173 Context.WINDOW_SERVICE)).addView(v, lp);
8174 }
8175 }
8176 }
8177
8178 public void noteWakeupAlarm(IIntentSender sender) {
8179 if (!(sender instanceof PendingIntentRecord)) {
8180 return;
8181 }
8182 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8183 synchronized (stats) {
8184 if (mBatteryStatsService.isOnBattery()) {
8185 mBatteryStatsService.enforceCallingPermission();
8186 PendingIntentRecord rec = (PendingIntentRecord)sender;
8187 int MY_UID = Binder.getCallingUid();
8188 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8189 BatteryStatsImpl.Uid.Pkg pkg =
8190 stats.getPackageStatsLocked(uid, rec.key.packageName);
8191 pkg.incWakeupsLocked();
8192 }
8193 }
8194 }
8195
8196 public boolean killPidsForMemory(int[] pids) {
8197 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8198 throw new SecurityException("killPidsForMemory only available to the system");
8199 }
8200
8201 // XXX Note: don't acquire main activity lock here, because the window
8202 // manager calls in with its locks held.
8203
8204 boolean killed = false;
8205 synchronized (mPidsSelfLocked) {
8206 int[] types = new int[pids.length];
8207 int worstType = 0;
8208 for (int i=0; i<pids.length; i++) {
8209 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8210 if (proc != null) {
8211 int type = proc.setAdj;
8212 types[i] = type;
8213 if (type > worstType) {
8214 worstType = type;
8215 }
8216 }
8217 }
8218
8219 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8220 // then constrain it so we will kill all hidden procs.
8221 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8222 worstType = HIDDEN_APP_MIN_ADJ;
8223 }
8224 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8225 for (int i=0; i<pids.length; i++) {
8226 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8227 if (proc == null) {
8228 continue;
8229 }
8230 int adj = proc.setAdj;
8231 if (adj >= worstType) {
8232 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8233 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008234 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008235 proc.processName, adj);
8236 killed = true;
8237 Process.killProcess(pids[i]);
8238 }
8239 }
8240 }
8241 return killed;
8242 }
8243
8244 public void reportPss(IApplicationThread caller, int pss) {
8245 Watchdog.PssRequestor req;
8246 String name;
8247 ProcessRecord callerApp;
8248 synchronized (this) {
8249 if (caller == null) {
8250 return;
8251 }
8252 callerApp = getRecordForAppLocked(caller);
8253 if (callerApp == null) {
8254 return;
8255 }
8256 callerApp.lastPss = pss;
8257 req = callerApp;
8258 name = callerApp.processName;
8259 }
8260 Watchdog.getInstance().reportPss(req, name, pss);
8261 if (!callerApp.persistent) {
8262 removeRequestedPss(callerApp);
8263 }
8264 }
8265
8266 public void requestPss(Runnable completeCallback) {
8267 ArrayList<ProcessRecord> procs;
8268 synchronized (this) {
8269 mRequestPssCallback = completeCallback;
8270 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008271 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8272 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008273 if (!proc.persistent) {
8274 mRequestPssList.add(proc);
8275 }
8276 }
8277 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8278 }
8279
8280 int oldPri = Process.getThreadPriority(Process.myTid());
8281 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8282 for (int i=procs.size()-1; i>=0; i--) {
8283 ProcessRecord proc = procs.get(i);
8284 proc.lastPss = 0;
8285 proc.requestPss();
8286 }
8287 Process.setThreadPriority(oldPri);
8288 }
8289
8290 void removeRequestedPss(ProcessRecord proc) {
8291 Runnable callback = null;
8292 synchronized (this) {
8293 if (mRequestPssList.remove(proc)) {
8294 if (mRequestPssList.size() == 0) {
8295 callback = mRequestPssCallback;
8296 mRequestPssCallback = null;
8297 }
8298 }
8299 }
8300
8301 if (callback != null) {
8302 callback.run();
8303 }
8304 }
8305
8306 public void collectPss(Watchdog.PssStats stats) {
8307 stats.mEmptyPss = 0;
8308 stats.mEmptyCount = 0;
8309 stats.mBackgroundPss = 0;
8310 stats.mBackgroundCount = 0;
8311 stats.mServicePss = 0;
8312 stats.mServiceCount = 0;
8313 stats.mVisiblePss = 0;
8314 stats.mVisibleCount = 0;
8315 stats.mForegroundPss = 0;
8316 stats.mForegroundCount = 0;
8317 stats.mNoPssCount = 0;
8318 synchronized (this) {
8319 int i;
8320 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8321 ? mProcDeaths.length : stats.mProcDeaths.length;
8322 int aggr = 0;
8323 for (i=0; i<NPD; i++) {
8324 aggr += mProcDeaths[i];
8325 stats.mProcDeaths[i] = aggr;
8326 }
8327 while (i<stats.mProcDeaths.length) {
8328 stats.mProcDeaths[i] = 0;
8329 i++;
8330 }
8331
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008332 for (i=mLruProcesses.size()-1; i>=0; i--) {
8333 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008334 if (proc.persistent) {
8335 continue;
8336 }
8337 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8338 if (proc.lastPss == 0) {
8339 stats.mNoPssCount++;
8340 continue;
8341 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008342 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8343 if (proc.empty) {
8344 stats.mEmptyPss += proc.lastPss;
8345 stats.mEmptyCount++;
8346 } else {
8347 stats.mBackgroundPss += proc.lastPss;
8348 stats.mBackgroundCount++;
8349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008350 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8351 stats.mVisiblePss += proc.lastPss;
8352 stats.mVisibleCount++;
8353 } else {
8354 stats.mForegroundPss += proc.lastPss;
8355 stats.mForegroundCount++;
8356 }
8357 }
8358 }
8359 }
8360
8361 public final void startRunning(String pkg, String cls, String action,
8362 String data) {
8363 synchronized(this) {
8364 if (mStartRunning) {
8365 return;
8366 }
8367 mStartRunning = true;
8368 mTopComponent = pkg != null && cls != null
8369 ? new ComponentName(pkg, cls) : null;
8370 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8371 mTopData = data;
8372 if (!mSystemReady) {
8373 return;
8374 }
8375 }
8376
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008377 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008378 }
8379
8380 private void retrieveSettings() {
8381 final ContentResolver resolver = mContext.getContentResolver();
8382 String debugApp = Settings.System.getString(
8383 resolver, Settings.System.DEBUG_APP);
8384 boolean waitForDebugger = Settings.System.getInt(
8385 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8386 boolean alwaysFinishActivities = Settings.System.getInt(
8387 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8388
8389 Configuration configuration = new Configuration();
8390 Settings.System.getConfiguration(resolver, configuration);
8391
8392 synchronized (this) {
8393 mDebugApp = mOrigDebugApp = debugApp;
8394 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8395 mAlwaysFinishActivities = alwaysFinishActivities;
8396 // This happens before any activities are started, so we can
8397 // change mConfiguration in-place.
8398 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008399 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008400 }
8401 }
8402
8403 public boolean testIsSystemReady() {
8404 // no need to synchronize(this) just to read & return the value
8405 return mSystemReady;
8406 }
8407
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008408 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008409 // In the simulator, startRunning will never have been called, which
8410 // normally sets a few crucial variables. Do it here instead.
8411 if (!Process.supportsProcesses()) {
8412 mStartRunning = true;
8413 mTopAction = Intent.ACTION_MAIN;
8414 }
8415
8416 synchronized(this) {
8417 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008418 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008419 return;
8420 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008421
8422 // Check to see if there are any update receivers to run.
8423 if (!mDidUpdate) {
8424 if (mWaitingUpdate) {
8425 return;
8426 }
8427 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8428 List<ResolveInfo> ris = null;
8429 try {
8430 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8431 intent, null, 0);
8432 } catch (RemoteException e) {
8433 }
8434 if (ris != null) {
8435 for (int i=ris.size()-1; i>=0; i--) {
8436 if ((ris.get(i).activityInfo.applicationInfo.flags
8437 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8438 ris.remove(i);
8439 }
8440 }
8441 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8442 for (int i=0; i<ris.size(); i++) {
8443 ActivityInfo ai = ris.get(i).activityInfo;
8444 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8445 IIntentReceiver finisher = null;
8446 if (i == 0) {
8447 finisher = new IIntentReceiver.Stub() {
8448 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008449 String data, Bundle extras, boolean ordered,
8450 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008451 throws RemoteException {
8452 synchronized (ActivityManagerService.this) {
8453 mDidUpdate = true;
8454 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008455 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008456 }
8457 };
8458 }
8459 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8460 broadcastIntentLocked(null, null, intent, null, finisher,
8461 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8462 if (i == 0) {
8463 mWaitingUpdate = true;
8464 }
8465 }
8466 }
8467 if (mWaitingUpdate) {
8468 return;
8469 }
8470 mDidUpdate = true;
8471 }
8472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008473 mSystemReady = true;
8474 if (!mStartRunning) {
8475 return;
8476 }
8477 }
8478
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008479 ArrayList<ProcessRecord> procsToKill = null;
8480 synchronized(mPidsSelfLocked) {
8481 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8482 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8483 if (!isAllowedWhileBooting(proc.info)){
8484 if (procsToKill == null) {
8485 procsToKill = new ArrayList<ProcessRecord>();
8486 }
8487 procsToKill.add(proc);
8488 }
8489 }
8490 }
8491
8492 if (procsToKill != null) {
8493 synchronized(this) {
8494 for (int i=procsToKill.size()-1; i>=0; i--) {
8495 ProcessRecord proc = procsToKill.get(i);
8496 Log.i(TAG, "Removing system update proc: " + proc);
8497 removeProcessLocked(proc, true);
8498 }
8499 }
8500 }
8501
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008502 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008503 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008504 SystemClock.uptimeMillis());
8505
8506 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008507 // Make sure we have no pre-ready processes sitting around.
8508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008509 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8510 ResolveInfo ri = mContext.getPackageManager()
8511 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008512 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008513 CharSequence errorMsg = null;
8514 if (ri != null) {
8515 ActivityInfo ai = ri.activityInfo;
8516 ApplicationInfo app = ai.applicationInfo;
8517 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8518 mTopAction = Intent.ACTION_FACTORY_TEST;
8519 mTopData = null;
8520 mTopComponent = new ComponentName(app.packageName,
8521 ai.name);
8522 } else {
8523 errorMsg = mContext.getResources().getText(
8524 com.android.internal.R.string.factorytest_not_system);
8525 }
8526 } else {
8527 errorMsg = mContext.getResources().getText(
8528 com.android.internal.R.string.factorytest_no_action);
8529 }
8530 if (errorMsg != null) {
8531 mTopAction = null;
8532 mTopData = null;
8533 mTopComponent = null;
8534 Message msg = Message.obtain();
8535 msg.what = SHOW_FACTORY_ERROR_MSG;
8536 msg.getData().putCharSequence("msg", errorMsg);
8537 mHandler.sendMessage(msg);
8538 }
8539 }
8540 }
8541
8542 retrieveSettings();
8543
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008544 if (goingCallback != null) goingCallback.run();
8545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008546 synchronized (this) {
8547 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8548 try {
8549 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008550 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008551 if (apps != null) {
8552 int N = apps.size();
8553 int i;
8554 for (i=0; i<N; i++) {
8555 ApplicationInfo info
8556 = (ApplicationInfo)apps.get(i);
8557 if (info != null &&
8558 !info.packageName.equals("android")) {
8559 addAppLocked(info);
8560 }
8561 }
8562 }
8563 } catch (RemoteException ex) {
8564 // pm is in same process, this will never happen.
8565 }
8566 }
8567
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008568 // Start up initial activity.
8569 mBooting = true;
8570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008571 try {
8572 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8573 Message msg = Message.obtain();
8574 msg.what = SHOW_UID_ERROR_MSG;
8575 mHandler.sendMessage(msg);
8576 }
8577 } catch (RemoteException e) {
8578 }
8579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008580 resumeTopActivityLocked(null);
8581 }
8582 }
8583
Dan Egnorb7f03672009-12-09 16:22:32 -08008584 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008585 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008586 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008587 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008588 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008589 startAppProblemLocked(app);
8590 app.stopFreezingAllLocked();
8591 return handleAppCrashLocked(app);
8592 }
8593
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008594 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008595 // check if error reporting is enabled in Gservices
8596 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8597 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8598 if (enabled == 0) {
8599 return null;
8600 }
8601
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008602 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008603
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008604 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008605 // look for receiver in the installer package
8606 String candidate = pm.getInstallerPackageName(app.info.packageName);
8607 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8608 if (result != null) {
8609 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008610 }
8611
Jacek Surazski82a73df2009-06-17 14:33:18 +02008612 // if the error app is on the system image, look for system apps
8613 // error receiver
8614 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8615 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8616 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8617 if (result != null) {
8618 return result;
8619 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008620 }
8621
Jacek Surazski82a73df2009-06-17 14:33:18 +02008622 // if there is a default receiver, try that
8623 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8624 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008625 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008626 // should not happen
8627 Log.e(TAG, "error talking to PackageManager", e);
8628 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008629 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008630 }
8631
8632 /**
8633 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8634 *
8635 * @param pm PackageManager isntance
8636 * @param errorPackage package which caused the error
8637 * @param receiverPackage candidate package to receive the error
8638 * @return activity component within receiverPackage which handles
8639 * ACTION_APP_ERROR, or null if not found
8640 */
8641 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8642 String receiverPackage) throws RemoteException {
8643 if (receiverPackage == null || receiverPackage.length() == 0) {
8644 return null;
8645 }
8646
8647 // break the loop if it's the error report receiver package that crashed
8648 if (receiverPackage.equals(errorPackage)) {
8649 return null;
8650 }
8651
8652 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8653 intent.setPackage(receiverPackage);
8654 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8655 if (info == null || info.activityInfo == null) {
8656 return null;
8657 }
8658 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008659 }
8660
Dan Egnorb7f03672009-12-09 16:22:32 -08008661 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008662 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008663 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008664 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008665 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8666 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008667 startAppProblemLocked(app);
8668 app.stopFreezingAllLocked();
8669 }
8670
8671 /**
8672 * Generate a process error record, suitable for attachment to a ProcessRecord.
8673 *
8674 * @param app The ProcessRecord in which the error occurred.
8675 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8676 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008677 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008678 * @param shortMsg Short message describing the crash.
8679 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008680 * @param stackTrace Full crash stack trace, may be null.
8681 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008682 * @return Returns a fully-formed AppErrorStateInfo record.
8683 */
8684 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008685 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008686 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008688 report.condition = condition;
8689 report.processName = app.processName;
8690 report.pid = app.pid;
8691 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008692 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008693 report.shortMsg = shortMsg;
8694 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008695 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008696
8697 return report;
8698 }
8699
8700 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8701 boolean crashed) {
8702 synchronized (this) {
8703 app.crashing = false;
8704 app.crashingReport = null;
8705 app.notResponding = false;
8706 app.notRespondingReport = null;
8707 if (app.anrDialog == fromDialog) {
8708 app.anrDialog = null;
8709 }
8710 if (app.waitDialog == fromDialog) {
8711 app.waitDialog = null;
8712 }
8713 if (app.pid > 0 && app.pid != MY_PID) {
8714 if (crashed) {
8715 handleAppCrashLocked(app);
8716 }
8717 Log.i(ActivityManagerService.TAG, "Killing process "
8718 + app.processName
8719 + " (pid=" + app.pid + ") at user's request");
8720 Process.killProcess(app.pid);
8721 }
8722
8723 }
8724 }
8725
Dan Egnorb7f03672009-12-09 16:22:32 -08008726 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008727 long now = SystemClock.uptimeMillis();
8728
8729 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8730 app.info.uid);
8731 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8732 // This process loses!
8733 Log.w(TAG, "Process " + app.info.processName
8734 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008735 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008736 app.info.processName, app.info.uid);
8737 killServicesLocked(app, false);
8738 for (int i=mHistory.size()-1; i>=0; i--) {
8739 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8740 if (r.app == app) {
8741 if (Config.LOGD) Log.d(
8742 TAG, " Force finishing activity "
8743 + r.intent.getComponent().flattenToShortString());
8744 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8745 }
8746 }
8747 if (!app.persistent) {
8748 // We don't want to start this process again until the user
8749 // explicitly does so... but for persistent process, we really
8750 // need to keep it running. If a persistent process is actually
8751 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008752 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008753 app.info.processName);
8754 mBadProcesses.put(app.info.processName, app.info.uid, now);
8755 app.bad = true;
8756 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8757 app.removed = true;
8758 removeProcessLocked(app, false);
8759 return false;
8760 }
8761 }
8762
8763 // Bump up the crash count of any services currently running in the proc.
8764 if (app.services.size() != 0) {
8765 // Any services running in the application need to be placed
8766 // back in the pending list.
8767 Iterator it = app.services.iterator();
8768 while (it.hasNext()) {
8769 ServiceRecord sr = (ServiceRecord)it.next();
8770 sr.crashCount++;
8771 }
8772 }
8773
8774 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8775 return true;
8776 }
8777
8778 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008779 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008780 skipCurrentReceiverLocked(app);
8781 }
8782
8783 void skipCurrentReceiverLocked(ProcessRecord app) {
8784 boolean reschedule = false;
8785 BroadcastRecord r = app.curReceiver;
8786 if (r != null) {
8787 // The current broadcast is waiting for this app's receiver
8788 // to be finished. Looks like that's not going to happen, so
8789 // let the broadcast continue.
8790 logBroadcastReceiverDiscard(r);
8791 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8792 r.resultExtras, r.resultAbort, true);
8793 reschedule = true;
8794 }
8795 r = mPendingBroadcast;
8796 if (r != null && r.curApp == app) {
8797 if (DEBUG_BROADCAST) Log.v(TAG,
8798 "skip & discard pending app " + r);
8799 logBroadcastReceiverDiscard(r);
8800 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8801 r.resultExtras, r.resultAbort, true);
8802 reschedule = true;
8803 }
8804 if (reschedule) {
8805 scheduleBroadcastsLocked();
8806 }
8807 }
8808
Dan Egnor60d87622009-12-16 16:32:58 -08008809 /**
8810 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8811 * The application process will exit immediately after this call returns.
8812 * @param app object of the crashing app, null for the system server
8813 * @param crashInfo describing the exception
8814 */
8815 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8816 ProcessRecord r = findAppProcess(app);
8817
8818 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8819 app == null ? "system" : (r == null ? "unknown" : r.processName),
8820 crashInfo.exceptionClassName,
8821 crashInfo.exceptionMessage,
8822 crashInfo.throwFileName,
8823 crashInfo.throwLineNumber);
8824
8825 addExceptionToDropBox("crash", r, null, crashInfo);
8826
8827 crashApplication(r, crashInfo);
8828 }
8829
8830 /**
8831 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8832 * @param app object of the crashing app, null for the system server
8833 * @param tag reported by the caller
8834 * @param crashInfo describing the context of the error
8835 * @return true if the process should exit immediately (WTF is fatal)
8836 */
8837 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008838 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008839 ProcessRecord r = findAppProcess(app);
8840
8841 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8842 app == null ? "system" : (r == null ? "unknown" : r.processName),
8843 tag, crashInfo.exceptionMessage);
8844
8845 addExceptionToDropBox("wtf", r, tag, crashInfo);
8846
8847 if (Settings.Gservices.getInt(mContext.getContentResolver(),
8848 Settings.Gservices.WTF_IS_FATAL, 0) != 0) {
8849 crashApplication(r, crashInfo);
8850 return true;
8851 } else {
8852 return false;
8853 }
8854 }
8855
8856 /**
8857 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8858 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8859 */
8860 private ProcessRecord findAppProcess(IBinder app) {
8861 if (app == null) {
8862 return null;
8863 }
8864
8865 synchronized (this) {
8866 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8867 final int NA = apps.size();
8868 for (int ia=0; ia<NA; ia++) {
8869 ProcessRecord p = apps.valueAt(ia);
8870 if (p.thread != null && p.thread.asBinder() == app) {
8871 return p;
8872 }
8873 }
8874 }
8875
8876 Log.w(TAG, "Can't find mystery application: " + app);
8877 return null;
8878 }
8879 }
8880
8881 /**
8882 * Write a description of an exception (from a crash or WTF report) to the drop box.
8883 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
8884 * @param r the process which crashed, null for the system server
8885 * @param tag supplied by the application (in the case of WTF), or null
8886 * @param crashInfo describing the exception
8887 */
8888 private void addExceptionToDropBox(String eventType, ProcessRecord r, String tag,
8889 ApplicationErrorReport.CrashInfo crashInfo) {
8890 String dropboxTag, processName;
8891 if (r == null) {
8892 dropboxTag = "system_server_" + eventType;
8893 } else if ((r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
8894 dropboxTag = "system_app_" + eventType;
8895 } else {
8896 dropboxTag = "data_app_" + eventType;
8897 }
8898
8899 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8900 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8901 StringBuilder sb = new StringBuilder(1024);
8902 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8903 if (r == null) {
8904 sb.append("Process: system_server\n");
8905 } else {
8906 sb.append("Package: ").append(r.info.packageName).append("\n");
8907 if (!r.processName.equals(r.info.packageName)) {
8908 sb.append("Process: ").append(r.processName).append("\n");
8909 }
8910 }
8911 if (tag != null) {
8912 sb.append("Tag: ").append(tag).append("\n");
8913 }
8914 if (crashInfo != null && crashInfo.stackTrace != null) {
8915 sb.append("\n").append(crashInfo.stackTrace);
8916 }
8917 dbox.addText(dropboxTag, sb.toString());
8918 }
8919 }
8920
8921 /**
8922 * Bring up the "unexpected error" dialog box for a crashing app.
8923 * Deal with edge cases (intercepts from instrumented applications,
8924 * ActivityController, error intent receivers, that sort of thing).
8925 * @param r the application crashing
8926 * @param crashInfo describing the failure
8927 */
8928 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008929 long timeMillis = System.currentTimeMillis();
8930 String shortMsg = crashInfo.exceptionClassName;
8931 String longMsg = crashInfo.exceptionMessage;
8932 String stackTrace = crashInfo.stackTrace;
8933 if (shortMsg != null && longMsg != null) {
8934 longMsg = shortMsg + ": " + longMsg;
8935 } else if (shortMsg != null) {
8936 longMsg = shortMsg;
8937 }
8938
Dan Egnor60d87622009-12-16 16:32:58 -08008939 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008940 synchronized (this) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008941 if (r != null) {
8942 // The application has crashed. Send the SIGQUIT to the process so
8943 // that it can dump its state.
8944 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8945 //Log.i(TAG, "Current system threads:");
8946 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8947 }
8948
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008949 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008950 try {
8951 String name = r != null ? r.processName : null;
8952 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008953 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008954 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008955 Log.w(TAG, "Force-killing crashed app " + name
8956 + " at watcher's request");
8957 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008958 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008959 }
8960 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008961 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008962 }
8963 }
8964
8965 final long origId = Binder.clearCallingIdentity();
8966
8967 // If this process is running instrumentation, finish it.
8968 if (r != null && r.instrumentationClass != null) {
8969 Log.w(TAG, "Error in app " + r.processName
8970 + " running instrumentation " + r.instrumentationClass + ":");
8971 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8972 if (longMsg != null) Log.w(TAG, " " + longMsg);
8973 Bundle info = new Bundle();
8974 info.putString("shortMsg", shortMsg);
8975 info.putString("longMsg", longMsg);
8976 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8977 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008978 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008979 }
8980
Dan Egnor60d87622009-12-16 16:32:58 -08008981 // If we can't identify the process or it's already exceeded its crash quota,
8982 // quit right away without showing a crash dialog.
8983 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008984 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008985 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008986 }
8987
8988 Message msg = Message.obtain();
8989 msg.what = SHOW_ERROR_MSG;
8990 HashMap data = new HashMap();
8991 data.put("result", result);
8992 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008993 msg.obj = data;
8994 mHandler.sendMessage(msg);
8995
8996 Binder.restoreCallingIdentity(origId);
8997 }
8998
8999 int res = result.get();
9000
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009001 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009002 synchronized (this) {
9003 if (r != null) {
9004 mProcessCrashTimes.put(r.info.processName, r.info.uid,
9005 SystemClock.uptimeMillis());
9006 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009007 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08009008 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009009 }
9010 }
9011
9012 if (appErrorIntent != null) {
9013 try {
9014 mContext.startActivity(appErrorIntent);
9015 } catch (ActivityNotFoundException e) {
9016 Log.w(TAG, "bug report receiver dissappeared", e);
9017 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009018 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009019 }
Dan Egnorb7f03672009-12-09 16:22:32 -08009020
9021 Intent createAppErrorIntentLocked(ProcessRecord r,
9022 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
9023 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009024 if (report == null) {
9025 return null;
9026 }
9027 Intent result = new Intent(Intent.ACTION_APP_ERROR);
9028 result.setComponent(r.errorReportReceiver);
9029 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
9030 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
9031 return result;
9032 }
9033
Dan Egnorb7f03672009-12-09 16:22:32 -08009034 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
9035 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009036 if (r.errorReportReceiver == null) {
9037 return null;
9038 }
9039
9040 if (!r.crashing && !r.notResponding) {
9041 return null;
9042 }
9043
Dan Egnorb7f03672009-12-09 16:22:32 -08009044 ApplicationErrorReport report = new ApplicationErrorReport();
9045 report.packageName = r.info.packageName;
9046 report.installerPackageName = r.errorReportReceiver.getPackageName();
9047 report.processName = r.processName;
9048 report.time = timeMillis;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009049
Dan Egnorb7f03672009-12-09 16:22:32 -08009050 if (r.crashing) {
9051 report.type = ApplicationErrorReport.TYPE_CRASH;
9052 report.crashInfo = crashInfo;
9053 } else if (r.notResponding) {
9054 report.type = ApplicationErrorReport.TYPE_ANR;
9055 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009056
Dan Egnorb7f03672009-12-09 16:22:32 -08009057 report.anrInfo.activity = r.notRespondingReport.tag;
9058 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9059 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009060 }
9061
Dan Egnorb7f03672009-12-09 16:22:32 -08009062 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009063 }
9064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009065 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9066 // assume our apps are happy - lazy create the list
9067 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9068
9069 synchronized (this) {
9070
9071 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009072 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9073 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009074 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9075 // This one's in trouble, so we'll generate a report for it
9076 // crashes are higher priority (in case there's a crash *and* an anr)
9077 ActivityManager.ProcessErrorStateInfo report = null;
9078 if (app.crashing) {
9079 report = app.crashingReport;
9080 } else if (app.notResponding) {
9081 report = app.notRespondingReport;
9082 }
9083
9084 if (report != null) {
9085 if (errList == null) {
9086 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9087 }
9088 errList.add(report);
9089 } else {
9090 Log.w(TAG, "Missing app error report, app = " + app.processName +
9091 " crashing = " + app.crashing +
9092 " notResponding = " + app.notResponding);
9093 }
9094 }
9095 }
9096 }
9097
9098 return errList;
9099 }
9100
9101 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9102 // Lazy instantiation of list
9103 List<ActivityManager.RunningAppProcessInfo> runList = null;
9104 synchronized (this) {
9105 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009106 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9107 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009108 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9109 // Generate process state info for running application
9110 ActivityManager.RunningAppProcessInfo currApp =
9111 new ActivityManager.RunningAppProcessInfo(app.processName,
9112 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009113 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009114 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009115 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009116 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9117 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9118 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009119 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9120 } else if (adj >= HOME_APP_ADJ) {
9121 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9122 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009123 } else if (adj >= SECONDARY_SERVER_ADJ) {
9124 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9125 } else if (adj >= VISIBLE_APP_ADJ) {
9126 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9127 } else {
9128 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9129 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009130 currApp.importanceReasonCode = app.adjTypeCode;
9131 if (app.adjSource instanceof ProcessRecord) {
9132 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9133 } else if (app.adjSource instanceof HistoryRecord) {
9134 HistoryRecord r = (HistoryRecord)app.adjSource;
9135 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9136 }
9137 if (app.adjTarget instanceof ComponentName) {
9138 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009140 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9141 // + " lru=" + currApp.lru);
9142 if (runList == null) {
9143 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9144 }
9145 runList.add(currApp);
9146 }
9147 }
9148 }
9149 return runList;
9150 }
9151
9152 @Override
9153 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9154 synchronized (this) {
9155 if (checkCallingPermission(android.Manifest.permission.DUMP)
9156 != PackageManager.PERMISSION_GRANTED) {
9157 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9158 + Binder.getCallingPid()
9159 + ", uid=" + Binder.getCallingUid()
9160 + " without permission "
9161 + android.Manifest.permission.DUMP);
9162 return;
9163 }
9164 if (args.length != 0 && "service".equals(args[0])) {
9165 dumpService(fd, pw, args);
9166 return;
9167 }
9168 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009169 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009170 pw.println(" ");
9171 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009172 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009173 if (mWaitingVisibleActivities.size() > 0) {
9174 pw.println(" ");
9175 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009176 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009177 }
9178 if (mStoppingActivities.size() > 0) {
9179 pw.println(" ");
9180 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009181 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009182 }
9183 if (mFinishingActivities.size() > 0) {
9184 pw.println(" ");
9185 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009186 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009187 }
9188
9189 pw.println(" ");
9190 pw.println(" mPausingActivity: " + mPausingActivity);
9191 pw.println(" mResumedActivity: " + mResumedActivity);
9192 pw.println(" mFocusedActivity: " + mFocusedActivity);
9193 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9194
9195 if (mRecentTasks.size() > 0) {
9196 pw.println(" ");
9197 pw.println("Recent tasks in Current Activity Manager State:");
9198
9199 final int N = mRecentTasks.size();
9200 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009201 TaskRecord tr = mRecentTasks.get(i);
9202 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9203 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009204 mRecentTasks.get(i).dump(pw, " ");
9205 }
9206 }
9207
9208 pw.println(" ");
9209 pw.println(" mCurTask: " + mCurTask);
9210
9211 pw.println(" ");
9212 pw.println("Processes in Current Activity Manager State:");
9213
9214 boolean needSep = false;
9215 int numPers = 0;
9216
9217 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9218 final int NA = procs.size();
9219 for (int ia=0; ia<NA; ia++) {
9220 if (!needSep) {
9221 pw.println(" All known processes:");
9222 needSep = true;
9223 }
9224 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009225 pw.print(r.persistent ? " *PERS*" : " *APP*");
9226 pw.print(" UID "); pw.print(procs.keyAt(ia));
9227 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009228 r.dump(pw, " ");
9229 if (r.persistent) {
9230 numPers++;
9231 }
9232 }
9233 }
9234
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009235 if (mLruProcesses.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009236 if (needSep) pw.println(" ");
9237 needSep = true;
9238 pw.println(" Running processes (most recent first):");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009239 dumpProcessList(pw, this, mLruProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009240 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009241 needSep = true;
9242 }
9243
9244 synchronized (mPidsSelfLocked) {
9245 if (mPidsSelfLocked.size() > 0) {
9246 if (needSep) pw.println(" ");
9247 needSep = true;
9248 pw.println(" PID mappings:");
9249 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009250 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9251 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009252 }
9253 }
9254 }
9255
9256 if (mForegroundProcesses.size() > 0) {
9257 if (needSep) pw.println(" ");
9258 needSep = true;
9259 pw.println(" Foreground Processes:");
9260 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009261 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9262 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009263 }
9264 }
9265
9266 if (mPersistentStartingProcesses.size() > 0) {
9267 if (needSep) pw.println(" ");
9268 needSep = true;
9269 pw.println(" Persisent processes that are starting:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009270 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009271 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009272 }
9273
9274 if (mStartingProcesses.size() > 0) {
9275 if (needSep) pw.println(" ");
9276 needSep = true;
9277 pw.println(" Processes that are starting:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009278 dumpProcessList(pw, this, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009279 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009280 }
9281
9282 if (mRemovedProcesses.size() > 0) {
9283 if (needSep) pw.println(" ");
9284 needSep = true;
9285 pw.println(" Processes that are being removed:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009286 dumpProcessList(pw, this, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009287 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009288 }
9289
9290 if (mProcessesOnHold.size() > 0) {
9291 if (needSep) pw.println(" ");
9292 needSep = true;
9293 pw.println(" Processes that are on old until the system is ready:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009294 dumpProcessList(pw, this, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009295 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009296 }
9297
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009298 if (mProcessesToGc.size() > 0) {
9299 if (needSep) pw.println(" ");
9300 needSep = true;
9301 pw.println(" Processes that are waiting to GC:");
9302 long now = SystemClock.uptimeMillis();
9303 for (int i=0; i<mProcessesToGc.size(); i++) {
9304 ProcessRecord proc = mProcessesToGc.get(i);
9305 pw.print(" Process "); pw.println(proc);
9306 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9307 pw.print(", last gced=");
9308 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009309 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009310 pw.print(now-proc.lastLowMemory);
9311 pw.println(" ms ago");
9312
9313 }
9314 }
9315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009316 if (mProcessCrashTimes.getMap().size() > 0) {
9317 if (needSep) pw.println(" ");
9318 needSep = true;
9319 pw.println(" Time since processes crashed:");
9320 long now = SystemClock.uptimeMillis();
9321 for (Map.Entry<String, SparseArray<Long>> procs
9322 : mProcessCrashTimes.getMap().entrySet()) {
9323 SparseArray<Long> uids = procs.getValue();
9324 final int N = uids.size();
9325 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009326 pw.print(" Process "); pw.print(procs.getKey());
9327 pw.print(" uid "); pw.print(uids.keyAt(i));
9328 pw.print(": last crashed ");
9329 pw.print((now-uids.valueAt(i)));
9330 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009331 }
9332 }
9333 }
9334
9335 if (mBadProcesses.getMap().size() > 0) {
9336 if (needSep) pw.println(" ");
9337 needSep = true;
9338 pw.println(" Bad processes:");
9339 for (Map.Entry<String, SparseArray<Long>> procs
9340 : mBadProcesses.getMap().entrySet()) {
9341 SparseArray<Long> uids = procs.getValue();
9342 final int N = uids.size();
9343 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009344 pw.print(" Bad process "); pw.print(procs.getKey());
9345 pw.print(" uid "); pw.print(uids.keyAt(i));
9346 pw.print(": crashed at time ");
9347 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009348 }
9349 }
9350 }
9351
9352 pw.println(" ");
9353 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009354 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009355 pw.println(" mConfiguration: " + mConfiguration);
9356 pw.println(" mStartRunning=" + mStartRunning
9357 + " mSystemReady=" + mSystemReady
9358 + " mBooting=" + mBooting
9359 + " mBooted=" + mBooted
9360 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009361 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009362 pw.println(" mGoingToSleep=" + mGoingToSleep);
9363 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9364 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9365 + " mDebugTransient=" + mDebugTransient
9366 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9367 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009368 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009369 }
9370 }
9371
9372 /**
9373 * There are three ways to call this:
9374 * - no service specified: dump all the services
9375 * - a flattened component name that matched an existing service was specified as the
9376 * first arg: dump that one service
9377 * - the first arg isn't the flattened component name of an existing service:
9378 * dump all services whose component contains the first arg as a substring
9379 */
9380 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9381 String[] newArgs;
9382 String componentNameString;
9383 ServiceRecord r;
9384 if (args.length == 1) {
9385 componentNameString = null;
9386 newArgs = EMPTY_STRING_ARRAY;
9387 r = null;
9388 } else {
9389 componentNameString = args[1];
9390 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9391 r = componentName != null ? mServices.get(componentName) : null;
9392 newArgs = new String[args.length - 2];
9393 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9394 }
9395
9396 if (r != null) {
9397 dumpService(fd, pw, r, newArgs);
9398 } else {
9399 for (ServiceRecord r1 : mServices.values()) {
9400 if (componentNameString == null
9401 || r1.name.flattenToString().contains(componentNameString)) {
9402 dumpService(fd, pw, r1, newArgs);
9403 }
9404 }
9405 }
9406 }
9407
9408 /**
9409 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9410 * there is a thread associated with the service.
9411 */
9412 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9413 pw.println(" Service " + r.name.flattenToString());
9414 if (r.app != null && r.app.thread != null) {
9415 try {
9416 // flush anything that is already in the PrintWriter since the thread is going
9417 // to write to the file descriptor directly
9418 pw.flush();
9419 r.app.thread.dumpService(fd, r, args);
9420 pw.print("\n");
9421 } catch (RemoteException e) {
9422 pw.println("got a RemoteException while dumping the service");
9423 }
9424 }
9425 }
9426
9427 void dumpBroadcasts(PrintWriter pw) {
9428 synchronized (this) {
9429 if (checkCallingPermission(android.Manifest.permission.DUMP)
9430 != PackageManager.PERMISSION_GRANTED) {
9431 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9432 + Binder.getCallingPid()
9433 + ", uid=" + Binder.getCallingUid()
9434 + " without permission "
9435 + android.Manifest.permission.DUMP);
9436 return;
9437 }
9438 pw.println("Broadcasts in Current Activity Manager State:");
9439
9440 if (mRegisteredReceivers.size() > 0) {
9441 pw.println(" ");
9442 pw.println(" Registered Receivers:");
9443 Iterator it = mRegisteredReceivers.values().iterator();
9444 while (it.hasNext()) {
9445 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009446 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009447 r.dump(pw, " ");
9448 }
9449 }
9450
9451 pw.println(" ");
9452 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009453 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009454
9455 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9456 || mPendingBroadcast != null) {
9457 if (mParallelBroadcasts.size() > 0) {
9458 pw.println(" ");
9459 pw.println(" Active broadcasts:");
9460 }
9461 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9462 pw.println(" Broadcast #" + i + ":");
9463 mParallelBroadcasts.get(i).dump(pw, " ");
9464 }
9465 if (mOrderedBroadcasts.size() > 0) {
9466 pw.println(" ");
9467 pw.println(" Active serialized broadcasts:");
9468 }
9469 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9470 pw.println(" Serialized Broadcast #" + i + ":");
9471 mOrderedBroadcasts.get(i).dump(pw, " ");
9472 }
9473 pw.println(" ");
9474 pw.println(" Pending broadcast:");
9475 if (mPendingBroadcast != null) {
9476 mPendingBroadcast.dump(pw, " ");
9477 } else {
9478 pw.println(" (null)");
9479 }
9480 }
9481
9482 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009483 pw.println(" Historical broadcasts:");
9484 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9485 BroadcastRecord r = mBroadcastHistory[i];
9486 if (r == null) {
9487 break;
9488 }
9489 pw.println(" Historical Broadcast #" + i + ":");
9490 r.dump(pw, " ");
9491 }
9492
9493 pw.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009494 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9495 if (mStickyBroadcasts != null) {
9496 pw.println(" ");
9497 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009498 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009499 for (Map.Entry<String, ArrayList<Intent>> ent
9500 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009501 pw.print(" * Sticky action "); pw.print(ent.getKey());
9502 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009503 ArrayList<Intent> intents = ent.getValue();
9504 final int N = intents.size();
9505 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009506 sb.setLength(0);
9507 sb.append(" Intent: ");
9508 intents.get(i).toShortString(sb, true, false);
9509 pw.println(sb.toString());
9510 Bundle bundle = intents.get(i).getExtras();
9511 if (bundle != null) {
9512 pw.print(" ");
9513 pw.println(bundle.toString());
9514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009515 }
9516 }
9517 }
9518
9519 pw.println(" ");
9520 pw.println(" mHandler:");
9521 mHandler.dump(new PrintWriterPrinter(pw), " ");
9522 }
9523 }
9524
9525 void dumpServices(PrintWriter pw) {
9526 synchronized (this) {
9527 if (checkCallingPermission(android.Manifest.permission.DUMP)
9528 != PackageManager.PERMISSION_GRANTED) {
9529 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9530 + Binder.getCallingPid()
9531 + ", uid=" + Binder.getCallingUid()
9532 + " without permission "
9533 + android.Manifest.permission.DUMP);
9534 return;
9535 }
9536 pw.println("Services in Current Activity Manager State:");
9537
9538 boolean needSep = false;
9539
9540 if (mServices.size() > 0) {
9541 pw.println(" Active services:");
9542 Iterator<ServiceRecord> it = mServices.values().iterator();
9543 while (it.hasNext()) {
9544 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009545 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009546 r.dump(pw, " ");
9547 }
9548 needSep = true;
9549 }
9550
9551 if (mPendingServices.size() > 0) {
9552 if (needSep) pw.println(" ");
9553 pw.println(" Pending services:");
9554 for (int i=0; i<mPendingServices.size(); i++) {
9555 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009556 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009557 r.dump(pw, " ");
9558 }
9559 needSep = true;
9560 }
9561
9562 if (mRestartingServices.size() > 0) {
9563 if (needSep) pw.println(" ");
9564 pw.println(" Restarting services:");
9565 for (int i=0; i<mRestartingServices.size(); i++) {
9566 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009567 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009568 r.dump(pw, " ");
9569 }
9570 needSep = true;
9571 }
9572
9573 if (mStoppingServices.size() > 0) {
9574 if (needSep) pw.println(" ");
9575 pw.println(" Stopping services:");
9576 for (int i=0; i<mStoppingServices.size(); i++) {
9577 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009578 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009579 r.dump(pw, " ");
9580 }
9581 needSep = true;
9582 }
9583
9584 if (mServiceConnections.size() > 0) {
9585 if (needSep) pw.println(" ");
9586 pw.println(" Connection bindings to services:");
9587 Iterator<ConnectionRecord> it
9588 = mServiceConnections.values().iterator();
9589 while (it.hasNext()) {
9590 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009591 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009592 r.dump(pw, " ");
9593 }
9594 }
9595 }
9596 }
9597
9598 void dumpProviders(PrintWriter pw) {
9599 synchronized (this) {
9600 if (checkCallingPermission(android.Manifest.permission.DUMP)
9601 != PackageManager.PERMISSION_GRANTED) {
9602 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9603 + Binder.getCallingPid()
9604 + ", uid=" + Binder.getCallingUid()
9605 + " without permission "
9606 + android.Manifest.permission.DUMP);
9607 return;
9608 }
9609
9610 pw.println("Content Providers in Current Activity Manager State:");
9611
9612 boolean needSep = false;
9613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009614 if (mProvidersByClass.size() > 0) {
9615 if (needSep) pw.println(" ");
9616 pw.println(" Published content providers (by class):");
9617 Iterator it = mProvidersByClass.entrySet().iterator();
9618 while (it.hasNext()) {
9619 Map.Entry e = (Map.Entry)it.next();
9620 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009621 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009622 r.dump(pw, " ");
9623 }
9624 needSep = true;
9625 }
9626
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009627 if (mProvidersByName.size() > 0) {
9628 pw.println(" ");
9629 pw.println(" Authority to provider mappings:");
9630 Iterator it = mProvidersByName.entrySet().iterator();
9631 while (it.hasNext()) {
9632 Map.Entry e = (Map.Entry)it.next();
9633 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9634 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9635 pw.println(r);
9636 }
9637 needSep = true;
9638 }
9639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009640 if (mLaunchingProviders.size() > 0) {
9641 if (needSep) pw.println(" ");
9642 pw.println(" Launching content providers:");
9643 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009644 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9645 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009646 }
9647 needSep = true;
9648 }
9649
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009650 if (mGrantedUriPermissions.size() > 0) {
9651 pw.println();
9652 pw.println("Granted Uri Permissions:");
9653 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9654 int uid = mGrantedUriPermissions.keyAt(i);
9655 HashMap<Uri, UriPermission> perms
9656 = mGrantedUriPermissions.valueAt(i);
9657 pw.print(" * UID "); pw.print(uid);
9658 pw.println(" holds:");
9659 for (UriPermission perm : perms.values()) {
9660 pw.print(" "); pw.println(perm);
9661 perm.dump(pw, " ");
9662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009663 }
9664 }
9665 }
9666 }
9667
9668 void dumpSenders(PrintWriter pw) {
9669 synchronized (this) {
9670 if (checkCallingPermission(android.Manifest.permission.DUMP)
9671 != PackageManager.PERMISSION_GRANTED) {
9672 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9673 + Binder.getCallingPid()
9674 + ", uid=" + Binder.getCallingUid()
9675 + " without permission "
9676 + android.Manifest.permission.DUMP);
9677 return;
9678 }
9679
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009680 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009681
9682 if (this.mIntentSenderRecords.size() > 0) {
9683 Iterator<WeakReference<PendingIntentRecord>> it
9684 = mIntentSenderRecords.values().iterator();
9685 while (it.hasNext()) {
9686 WeakReference<PendingIntentRecord> ref = it.next();
9687 PendingIntentRecord rec = ref != null ? ref.get(): null;
9688 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009689 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009690 rec.dump(pw, " ");
9691 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009692 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009693 }
9694 }
9695 }
9696 }
9697 }
9698
9699 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009700 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009701 TaskRecord lastTask = null;
9702 for (int i=list.size()-1; i>=0; i--) {
9703 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009704 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009705 if (lastTask != r.task) {
9706 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009707 pw.print(prefix);
9708 pw.print(full ? "* " : " ");
9709 pw.println(lastTask);
9710 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009711 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009713 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009714 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9715 pw.print(" #"); pw.print(i); pw.print(": ");
9716 pw.println(r);
9717 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009718 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009720 }
9721 }
9722
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009723 private static String buildOomTag(String prefix, String space, int val, int base) {
9724 if (val == base) {
9725 if (space == null) return prefix;
9726 return prefix + " ";
9727 }
9728 return prefix + "+" + Integer.toString(val-base);
9729 }
9730
9731 private static final int dumpProcessList(PrintWriter pw,
9732 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009733 String prefix, String normalLabel, String persistentLabel,
9734 boolean inclOomAdj) {
9735 int numPers = 0;
9736 for (int i=list.size()-1; i>=0; i--) {
9737 ProcessRecord r = (ProcessRecord)list.get(i);
9738 if (false) {
9739 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9740 + " #" + i + ":");
9741 r.dump(pw, prefix + " ");
9742 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009743 String oomAdj;
9744 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009745 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009746 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009747 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9748 } else if (r.setAdj >= HOME_APP_ADJ) {
9749 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9750 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9751 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9752 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9753 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9754 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9755 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9756 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9757 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009758 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009759 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009760 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009761 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009762 } else {
9763 oomAdj = Integer.toString(r.setAdj);
9764 }
9765 String schedGroup;
9766 switch (r.setSchedGroup) {
9767 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9768 schedGroup = "B";
9769 break;
9770 case Process.THREAD_GROUP_DEFAULT:
9771 schedGroup = "F";
9772 break;
9773 default:
9774 schedGroup = Integer.toString(r.setSchedGroup);
9775 break;
9776 }
9777 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009778 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009779 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009780 if (r.adjSource != null || r.adjTarget != null) {
9781 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009782 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009784 } else {
9785 pw.println(String.format("%s%s #%2d: %s",
9786 prefix, (r.persistent ? persistentLabel : normalLabel),
9787 i, r.toString()));
9788 }
9789 if (r.persistent) {
9790 numPers++;
9791 }
9792 }
9793 return numPers;
9794 }
9795
9796 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9797 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009798 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009799 long uptime = SystemClock.uptimeMillis();
9800 long realtime = SystemClock.elapsedRealtime();
9801
9802 if (isCheckinRequest) {
9803 // short checkin version
9804 pw.println(uptime + "," + realtime);
9805 pw.flush();
9806 } else {
9807 pw.println("Applications Memory Usage (kB):");
9808 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9809 }
9810 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9811 ProcessRecord r = (ProcessRecord)list.get(i);
9812 if (r.thread != null) {
9813 if (!isCheckinRequest) {
9814 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9815 pw.flush();
9816 }
9817 try {
9818 r.thread.asBinder().dump(fd, args);
9819 } catch (RemoteException e) {
9820 if (!isCheckinRequest) {
9821 pw.println("Got RemoteException!");
9822 pw.flush();
9823 }
9824 }
9825 }
9826 }
9827 }
9828
9829 /**
9830 * Searches array of arguments for the specified string
9831 * @param args array of argument strings
9832 * @param value value to search for
9833 * @return true if the value is contained in the array
9834 */
9835 private static boolean scanArgs(String[] args, String value) {
9836 if (args != null) {
9837 for (String arg : args) {
9838 if (value.equals(arg)) {
9839 return true;
9840 }
9841 }
9842 }
9843 return false;
9844 }
9845
Dianne Hackborn75b03852009-06-12 15:43:26 -07009846 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009847 int count = mHistory.size();
9848
9849 // convert the token to an entry in the history.
9850 HistoryRecord r = null;
9851 int index = -1;
9852 for (int i=count-1; i>=0; i--) {
9853 Object o = mHistory.get(i);
9854 if (o == token) {
9855 r = (HistoryRecord)o;
9856 index = i;
9857 break;
9858 }
9859 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009860
9861 return index;
9862 }
9863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009864 private final void killServicesLocked(ProcessRecord app,
9865 boolean allowRestart) {
9866 // Report disconnected services.
9867 if (false) {
9868 // XXX we are letting the client link to the service for
9869 // death notifications.
9870 if (app.services.size() > 0) {
9871 Iterator it = app.services.iterator();
9872 while (it.hasNext()) {
9873 ServiceRecord r = (ServiceRecord)it.next();
9874 if (r.connections.size() > 0) {
9875 Iterator<ConnectionRecord> jt
9876 = r.connections.values().iterator();
9877 while (jt.hasNext()) {
9878 ConnectionRecord c = jt.next();
9879 if (c.binding.client != app) {
9880 try {
9881 //c.conn.connected(r.className, null);
9882 } catch (Exception e) {
9883 // todo: this should be asynchronous!
9884 Log.w(TAG, "Exception thrown disconnected servce "
9885 + r.shortName
9886 + " from app " + app.processName, e);
9887 }
9888 }
9889 }
9890 }
9891 }
9892 }
9893 }
9894
9895 // Clean up any connections this application has to other services.
9896 if (app.connections.size() > 0) {
9897 Iterator<ConnectionRecord> it = app.connections.iterator();
9898 while (it.hasNext()) {
9899 ConnectionRecord r = it.next();
9900 removeConnectionLocked(r, app, null);
9901 }
9902 }
9903 app.connections.clear();
9904
9905 if (app.services.size() != 0) {
9906 // Any services running in the application need to be placed
9907 // back in the pending list.
9908 Iterator it = app.services.iterator();
9909 while (it.hasNext()) {
9910 ServiceRecord sr = (ServiceRecord)it.next();
9911 synchronized (sr.stats.getBatteryStats()) {
9912 sr.stats.stopLaunchedLocked();
9913 }
9914 sr.app = null;
9915 sr.executeNesting = 0;
9916 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009917
9918 boolean hasClients = sr.bindings.size() > 0;
9919 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009920 Iterator<IntentBindRecord> bindings
9921 = sr.bindings.values().iterator();
9922 while (bindings.hasNext()) {
9923 IntentBindRecord b = bindings.next();
9924 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9925 + ": shouldUnbind=" + b.hasBound);
9926 b.binder = null;
9927 b.requested = b.received = b.hasBound = false;
9928 }
9929 }
9930
9931 if (sr.crashCount >= 2) {
9932 Log.w(TAG, "Service crashed " + sr.crashCount
9933 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -08009934 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009935 sr.crashCount, sr.shortName, app.pid);
9936 bringDownServiceLocked(sr, true);
9937 } else if (!allowRestart) {
9938 bringDownServiceLocked(sr, true);
9939 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009940 boolean canceled = scheduleServiceRestartLocked(sr, true);
9941
9942 // Should the service remain running? Note that in the
9943 // extreme case of so many attempts to deliver a command
9944 // that it failed, that we also will stop it here.
9945 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9946 if (sr.pendingStarts.size() == 0) {
9947 sr.startRequested = false;
9948 if (!hasClients) {
9949 // Whoops, no reason to restart!
9950 bringDownServiceLocked(sr, true);
9951 }
9952 }
9953 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009954 }
9955 }
9956
9957 if (!allowRestart) {
9958 app.services.clear();
9959 }
9960 }
9961
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009962 // Make sure we have no more records on the stopping list.
9963 int i = mStoppingServices.size();
9964 while (i > 0) {
9965 i--;
9966 ServiceRecord sr = mStoppingServices.get(i);
9967 if (sr.app == app) {
9968 mStoppingServices.remove(i);
9969 }
9970 }
9971
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009972 app.executingServices.clear();
9973 }
9974
9975 private final void removeDyingProviderLocked(ProcessRecord proc,
9976 ContentProviderRecord cpr) {
9977 synchronized (cpr) {
9978 cpr.launchingApp = null;
9979 cpr.notifyAll();
9980 }
9981
9982 mProvidersByClass.remove(cpr.info.name);
9983 String names[] = cpr.info.authority.split(";");
9984 for (int j = 0; j < names.length; j++) {
9985 mProvidersByName.remove(names[j]);
9986 }
9987
9988 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9989 while (cit.hasNext()) {
9990 ProcessRecord capp = cit.next();
9991 if (!capp.persistent && capp.thread != null
9992 && capp.pid != 0
9993 && capp.pid != MY_PID) {
9994 Log.i(TAG, "Killing app " + capp.processName
9995 + " (pid " + capp.pid
9996 + ") because provider " + cpr.info.name
9997 + " is in dying process " + proc.processName);
9998 Process.killProcess(capp.pid);
9999 }
10000 }
10001
10002 mLaunchingProviders.remove(cpr);
10003 }
10004
10005 /**
10006 * Main code for cleaning up a process when it has gone away. This is
10007 * called both as a result of the process dying, or directly when stopping
10008 * a process when running in single process mode.
10009 */
10010 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10011 boolean restarting, int index) {
10012 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010013 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010014 }
10015
Dianne Hackborn36124872009-10-08 16:22:03 -070010016 mProcessesToGc.remove(app);
10017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010018 // Dismiss any open dialogs.
10019 if (app.crashDialog != null) {
10020 app.crashDialog.dismiss();
10021 app.crashDialog = null;
10022 }
10023 if (app.anrDialog != null) {
10024 app.anrDialog.dismiss();
10025 app.anrDialog = null;
10026 }
10027 if (app.waitDialog != null) {
10028 app.waitDialog.dismiss();
10029 app.waitDialog = null;
10030 }
10031
10032 app.crashing = false;
10033 app.notResponding = false;
10034
10035 app.resetPackageList();
10036 app.thread = null;
10037 app.forcingToForeground = null;
10038 app.foregroundServices = false;
10039
10040 killServicesLocked(app, true);
10041
10042 boolean restart = false;
10043
10044 int NL = mLaunchingProviders.size();
10045
10046 // Remove published content providers.
10047 if (!app.pubProviders.isEmpty()) {
10048 Iterator it = app.pubProviders.values().iterator();
10049 while (it.hasNext()) {
10050 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10051 cpr.provider = null;
10052 cpr.app = null;
10053
10054 // See if someone is waiting for this provider... in which
10055 // case we don't remove it, but just let it restart.
10056 int i = 0;
10057 if (!app.bad) {
10058 for (; i<NL; i++) {
10059 if (mLaunchingProviders.get(i) == cpr) {
10060 restart = true;
10061 break;
10062 }
10063 }
10064 } else {
10065 i = NL;
10066 }
10067
10068 if (i >= NL) {
10069 removeDyingProviderLocked(app, cpr);
10070 NL = mLaunchingProviders.size();
10071 }
10072 }
10073 app.pubProviders.clear();
10074 }
10075
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010076 // Take care of any launching providers waiting for this process.
10077 if (checkAppInLaunchingProvidersLocked(app, false)) {
10078 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010079 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010081 // Unregister from connected content providers.
10082 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010083 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010084 while (it.hasNext()) {
10085 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10086 cpr.clients.remove(app);
10087 }
10088 app.conProviders.clear();
10089 }
10090
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010091 // At this point there may be remaining entries in mLaunchingProviders
10092 // where we were the only one waiting, so they are no longer of use.
10093 // Look for these and clean up if found.
10094 // XXX Commented out for now. Trying to figure out a way to reproduce
10095 // the actual situation to identify what is actually going on.
10096 if (false) {
10097 for (int i=0; i<NL; i++) {
10098 ContentProviderRecord cpr = (ContentProviderRecord)
10099 mLaunchingProviders.get(i);
10100 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10101 synchronized (cpr) {
10102 cpr.launchingApp = null;
10103 cpr.notifyAll();
10104 }
10105 }
10106 }
10107 }
10108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010109 skipCurrentReceiverLocked(app);
10110
10111 // Unregister any receivers.
10112 if (app.receivers.size() > 0) {
10113 Iterator<ReceiverList> it = app.receivers.iterator();
10114 while (it.hasNext()) {
10115 removeReceiverLocked(it.next());
10116 }
10117 app.receivers.clear();
10118 }
10119
Christopher Tate181fafa2009-05-14 11:12:14 -070010120 // If the app is undergoing backup, tell the backup manager about it
10121 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10122 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10123 try {
10124 IBackupManager bm = IBackupManager.Stub.asInterface(
10125 ServiceManager.getService(Context.BACKUP_SERVICE));
10126 bm.agentDisconnected(app.info.packageName);
10127 } catch (RemoteException e) {
10128 // can't happen; backup manager is local
10129 }
10130 }
10131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010132 // If the caller is restarting this app, then leave it in its
10133 // current lists and let the caller take care of it.
10134 if (restarting) {
10135 return;
10136 }
10137
10138 if (!app.persistent) {
10139 if (DEBUG_PROCESSES) Log.v(TAG,
10140 "Removing non-persistent process during cleanup: " + app);
10141 mProcessNames.remove(app.processName, app.info.uid);
10142 } else if (!app.removed) {
10143 // This app is persistent, so we need to keep its record around.
10144 // If it is not already on the pending app list, add it there
10145 // and start a new process for it.
10146 app.thread = null;
10147 app.forcingToForeground = null;
10148 app.foregroundServices = false;
10149 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10150 mPersistentStartingProcesses.add(app);
10151 restart = true;
10152 }
10153 }
10154 mProcessesOnHold.remove(app);
10155
The Android Open Source Project4df24232009-03-05 14:34:35 -080010156 if (app == mHomeProcess) {
10157 mHomeProcess = null;
10158 }
10159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010160 if (restart) {
10161 // We have components that still need to be running in the
10162 // process, so re-launch it.
10163 mProcessNames.put(app.processName, app.info.uid, app);
10164 startProcessLocked(app, "restart", app.processName);
10165 } else if (app.pid > 0 && app.pid != MY_PID) {
10166 // Goodbye!
10167 synchronized (mPidsSelfLocked) {
10168 mPidsSelfLocked.remove(app.pid);
10169 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10170 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010171 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010172 }
10173 }
10174
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010175 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10176 // Look through the content providers we are waiting to have launched,
10177 // and if any run in this process then either schedule a restart of
10178 // the process or kill the client waiting for it if this process has
10179 // gone bad.
10180 int NL = mLaunchingProviders.size();
10181 boolean restart = false;
10182 for (int i=0; i<NL; i++) {
10183 ContentProviderRecord cpr = (ContentProviderRecord)
10184 mLaunchingProviders.get(i);
10185 if (cpr.launchingApp == app) {
10186 if (!alwaysBad && !app.bad) {
10187 restart = true;
10188 } else {
10189 removeDyingProviderLocked(app, cpr);
10190 NL = mLaunchingProviders.size();
10191 }
10192 }
10193 }
10194 return restart;
10195 }
10196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010197 // =========================================================
10198 // SERVICES
10199 // =========================================================
10200
10201 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10202 ActivityManager.RunningServiceInfo info =
10203 new ActivityManager.RunningServiceInfo();
10204 info.service = r.name;
10205 if (r.app != null) {
10206 info.pid = r.app.pid;
10207 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010208 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010209 info.process = r.processName;
10210 info.foreground = r.isForeground;
10211 info.activeSince = r.createTime;
10212 info.started = r.startRequested;
10213 info.clientCount = r.connections.size();
10214 info.crashCount = r.crashCount;
10215 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010216 if (r.isForeground) {
10217 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10218 }
10219 if (r.startRequested) {
10220 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10221 }
10222 if (r.app != null && r.app.pid == Process.myPid()) {
10223 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10224 }
10225 if (r.app != null && r.app.persistent) {
10226 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10227 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010228 for (ConnectionRecord conn : r.connections.values()) {
10229 if (conn.clientLabel != 0) {
10230 info.clientPackage = conn.binding.client.info.packageName;
10231 info.clientLabel = conn.clientLabel;
10232 break;
10233 }
10234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010235 return info;
10236 }
10237
10238 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10239 int flags) {
10240 synchronized (this) {
10241 ArrayList<ActivityManager.RunningServiceInfo> res
10242 = new ArrayList<ActivityManager.RunningServiceInfo>();
10243
10244 if (mServices.size() > 0) {
10245 Iterator<ServiceRecord> it = mServices.values().iterator();
10246 while (it.hasNext() && res.size() < maxNum) {
10247 res.add(makeRunningServiceInfoLocked(it.next()));
10248 }
10249 }
10250
10251 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10252 ServiceRecord r = mRestartingServices.get(i);
10253 ActivityManager.RunningServiceInfo info =
10254 makeRunningServiceInfoLocked(r);
10255 info.restarting = r.nextRestartTime;
10256 res.add(info);
10257 }
10258
10259 return res;
10260 }
10261 }
10262
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010263 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10264 synchronized (this) {
10265 ServiceRecord r = mServices.get(name);
10266 if (r != null) {
10267 for (ConnectionRecord conn : r.connections.values()) {
10268 if (conn.clientIntent != null) {
10269 return conn.clientIntent;
10270 }
10271 }
10272 }
10273 }
10274 return null;
10275 }
10276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010277 private final ServiceRecord findServiceLocked(ComponentName name,
10278 IBinder token) {
10279 ServiceRecord r = mServices.get(name);
10280 return r == token ? r : null;
10281 }
10282
10283 private final class ServiceLookupResult {
10284 final ServiceRecord record;
10285 final String permission;
10286
10287 ServiceLookupResult(ServiceRecord _record, String _permission) {
10288 record = _record;
10289 permission = _permission;
10290 }
10291 };
10292
10293 private ServiceLookupResult findServiceLocked(Intent service,
10294 String resolvedType) {
10295 ServiceRecord r = null;
10296 if (service.getComponent() != null) {
10297 r = mServices.get(service.getComponent());
10298 }
10299 if (r == null) {
10300 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10301 r = mServicesByIntent.get(filter);
10302 }
10303
10304 if (r == null) {
10305 try {
10306 ResolveInfo rInfo =
10307 ActivityThread.getPackageManager().resolveService(
10308 service, resolvedType, 0);
10309 ServiceInfo sInfo =
10310 rInfo != null ? rInfo.serviceInfo : null;
10311 if (sInfo == null) {
10312 return null;
10313 }
10314
10315 ComponentName name = new ComponentName(
10316 sInfo.applicationInfo.packageName, sInfo.name);
10317 r = mServices.get(name);
10318 } catch (RemoteException ex) {
10319 // pm is in same process, this will never happen.
10320 }
10321 }
10322 if (r != null) {
10323 int callingPid = Binder.getCallingPid();
10324 int callingUid = Binder.getCallingUid();
10325 if (checkComponentPermission(r.permission,
10326 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10327 != PackageManager.PERMISSION_GRANTED) {
10328 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10329 + " from pid=" + callingPid
10330 + ", uid=" + callingUid
10331 + " requires " + r.permission);
10332 return new ServiceLookupResult(null, r.permission);
10333 }
10334 return new ServiceLookupResult(r, null);
10335 }
10336 return null;
10337 }
10338
10339 private class ServiceRestarter implements Runnable {
10340 private ServiceRecord mService;
10341
10342 void setService(ServiceRecord service) {
10343 mService = service;
10344 }
10345
10346 public void run() {
10347 synchronized(ActivityManagerService.this) {
10348 performServiceRestartLocked(mService);
10349 }
10350 }
10351 }
10352
10353 private ServiceLookupResult retrieveServiceLocked(Intent service,
10354 String resolvedType, int callingPid, int callingUid) {
10355 ServiceRecord r = null;
10356 if (service.getComponent() != null) {
10357 r = mServices.get(service.getComponent());
10358 }
10359 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10360 r = mServicesByIntent.get(filter);
10361 if (r == null) {
10362 try {
10363 ResolveInfo rInfo =
10364 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010365 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010366 ServiceInfo sInfo =
10367 rInfo != null ? rInfo.serviceInfo : null;
10368 if (sInfo == null) {
10369 Log.w(TAG, "Unable to start service " + service +
10370 ": not found");
10371 return null;
10372 }
10373
10374 ComponentName name = new ComponentName(
10375 sInfo.applicationInfo.packageName, sInfo.name);
10376 r = mServices.get(name);
10377 if (r == null) {
10378 filter = new Intent.FilterComparison(service.cloneFilter());
10379 ServiceRestarter res = new ServiceRestarter();
10380 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10381 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10382 synchronized (stats) {
10383 ss = stats.getServiceStatsLocked(
10384 sInfo.applicationInfo.uid, sInfo.packageName,
10385 sInfo.name);
10386 }
10387 r = new ServiceRecord(ss, name, filter, sInfo, res);
10388 res.setService(r);
10389 mServices.put(name, r);
10390 mServicesByIntent.put(filter, r);
10391
10392 // Make sure this component isn't in the pending list.
10393 int N = mPendingServices.size();
10394 for (int i=0; i<N; i++) {
10395 ServiceRecord pr = mPendingServices.get(i);
10396 if (pr.name.equals(name)) {
10397 mPendingServices.remove(i);
10398 i--;
10399 N--;
10400 }
10401 }
10402 }
10403 } catch (RemoteException ex) {
10404 // pm is in same process, this will never happen.
10405 }
10406 }
10407 if (r != null) {
10408 if (checkComponentPermission(r.permission,
10409 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10410 != PackageManager.PERMISSION_GRANTED) {
10411 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10412 + " from pid=" + Binder.getCallingPid()
10413 + ", uid=" + Binder.getCallingUid()
10414 + " requires " + r.permission);
10415 return new ServiceLookupResult(null, r.permission);
10416 }
10417 return new ServiceLookupResult(r, null);
10418 }
10419 return null;
10420 }
10421
10422 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10423 long now = SystemClock.uptimeMillis();
10424 if (r.executeNesting == 0 && r.app != null) {
10425 if (r.app.executingServices.size() == 0) {
10426 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10427 msg.obj = r.app;
10428 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10429 }
10430 r.app.executingServices.add(r);
10431 }
10432 r.executeNesting++;
10433 r.executingStart = now;
10434 }
10435
10436 private final void sendServiceArgsLocked(ServiceRecord r,
10437 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010438 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010439 if (N == 0) {
10440 return;
10441 }
10442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010443 int i = 0;
10444 while (i < N) {
10445 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010446 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010447 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010448 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010449 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010450 // If somehow we got a dummy start at the front, then
10451 // just drop it here.
10452 i++;
10453 continue;
10454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010455 bumpServiceExecutingLocked(r);
10456 if (!oomAdjusted) {
10457 oomAdjusted = true;
10458 updateOomAdjLocked(r.app);
10459 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010460 int flags = 0;
10461 if (si.deliveryCount > 0) {
10462 flags |= Service.START_FLAG_RETRY;
10463 }
10464 if (si.doneExecutingCount > 0) {
10465 flags |= Service.START_FLAG_REDELIVERY;
10466 }
10467 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10468 si.deliveredTime = SystemClock.uptimeMillis();
10469 r.deliveredStarts.add(si);
10470 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010471 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010472 } catch (RemoteException e) {
10473 // Remote process gone... we'll let the normal cleanup take
10474 // care of this.
10475 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010476 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010477 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010478 break;
10479 }
10480 }
10481 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010482 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010483 } else {
10484 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010485 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010486 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010487 }
10488 }
10489 }
10490
10491 private final boolean requestServiceBindingLocked(ServiceRecord r,
10492 IntentBindRecord i, boolean rebind) {
10493 if (r.app == null || r.app.thread == null) {
10494 // If service is not currently running, can't yet bind.
10495 return false;
10496 }
10497 if ((!i.requested || rebind) && i.apps.size() > 0) {
10498 try {
10499 bumpServiceExecutingLocked(r);
10500 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10501 + ": shouldUnbind=" + i.hasBound);
10502 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10503 if (!rebind) {
10504 i.requested = true;
10505 }
10506 i.hasBound = true;
10507 i.doRebind = false;
10508 } catch (RemoteException e) {
10509 return false;
10510 }
10511 }
10512 return true;
10513 }
10514
10515 private final void requestServiceBindingsLocked(ServiceRecord r) {
10516 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10517 while (bindings.hasNext()) {
10518 IntentBindRecord i = bindings.next();
10519 if (!requestServiceBindingLocked(r, i, false)) {
10520 break;
10521 }
10522 }
10523 }
10524
10525 private final void realStartServiceLocked(ServiceRecord r,
10526 ProcessRecord app) throws RemoteException {
10527 if (app.thread == null) {
10528 throw new RemoteException();
10529 }
10530
10531 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010532 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010533
10534 app.services.add(r);
10535 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010536 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010537
10538 boolean created = false;
10539 try {
10540 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10541 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010542 mStringBuilder.setLength(0);
10543 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010544 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010545 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010546 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010547 synchronized (r.stats.getBatteryStats()) {
10548 r.stats.startLaunchedLocked();
10549 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010550 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010551 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010552 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010553 created = true;
10554 } finally {
10555 if (!created) {
10556 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010557 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010558 }
10559 }
10560
10561 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010562
10563 // If the service is in the started state, and there are no
10564 // pending arguments, then fake up one so its onStartCommand() will
10565 // be called.
10566 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10567 r.lastStartId++;
10568 if (r.lastStartId < 1) {
10569 r.lastStartId = 1;
10570 }
10571 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10572 }
10573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010574 sendServiceArgsLocked(r, true);
10575 }
10576
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010577 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10578 boolean allowCancel) {
10579 boolean canceled = false;
10580
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010581 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010582 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010583 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010584
10585 // Any delivered but not yet finished starts should be put back
10586 // on the pending list.
10587 final int N = r.deliveredStarts.size();
10588 if (N > 0) {
10589 for (int i=N-1; i>=0; i--) {
10590 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10591 if (si.intent == null) {
10592 // We'll generate this again if needed.
10593 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10594 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10595 r.pendingStarts.add(0, si);
10596 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10597 dur *= 2;
10598 if (minDuration < dur) minDuration = dur;
10599 if (resetTime < dur) resetTime = dur;
10600 } else {
10601 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10602 + r.name);
10603 canceled = true;
10604 }
10605 }
10606 r.deliveredStarts.clear();
10607 }
10608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010609 r.totalRestartCount++;
10610 if (r.restartDelay == 0) {
10611 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010612 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010613 } else {
10614 // If it has been a "reasonably long time" since the service
10615 // was started, then reset our restart duration back to
10616 // the beginning, so we don't infinitely increase the duration
10617 // on a service that just occasionally gets killed (which is
10618 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010619 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010620 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010621 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010622 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010623 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010624 if (r.restartDelay < minDuration) {
10625 r.restartDelay = minDuration;
10626 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010627 }
10628 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010629
10630 r.nextRestartTime = now + r.restartDelay;
10631
10632 // Make sure that we don't end up restarting a bunch of services
10633 // all at the same time.
10634 boolean repeat;
10635 do {
10636 repeat = false;
10637 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10638 ServiceRecord r2 = mRestartingServices.get(i);
10639 if (r2 != r && r.nextRestartTime
10640 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10641 && r.nextRestartTime
10642 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10643 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10644 r.restartDelay = r.nextRestartTime - now;
10645 repeat = true;
10646 break;
10647 }
10648 }
10649 } while (repeat);
10650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010651 if (!mRestartingServices.contains(r)) {
10652 mRestartingServices.add(r);
10653 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010654
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010655 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010657 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010658 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010659 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10660 Log.w(TAG, "Scheduling restart of crashed service "
10661 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010662 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010663 r.shortName, r.restartDelay);
10664
10665 Message msg = Message.obtain();
10666 msg.what = SERVICE_ERROR_MSG;
10667 msg.obj = r;
10668 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010669
10670 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010671 }
10672
10673 final void performServiceRestartLocked(ServiceRecord r) {
10674 if (!mRestartingServices.contains(r)) {
10675 return;
10676 }
10677 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10678 }
10679
10680 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10681 if (r.restartDelay == 0) {
10682 return false;
10683 }
10684 r.resetRestartCounter();
10685 mRestartingServices.remove(r);
10686 mHandler.removeCallbacks(r.restarter);
10687 return true;
10688 }
10689
10690 private final boolean bringUpServiceLocked(ServiceRecord r,
10691 int intentFlags, boolean whileRestarting) {
10692 //Log.i(TAG, "Bring up service:");
10693 //r.dump(" ");
10694
Dianne Hackborn36124872009-10-08 16:22:03 -070010695 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010696 sendServiceArgsLocked(r, false);
10697 return true;
10698 }
10699
10700 if (!whileRestarting && r.restartDelay > 0) {
10701 // If waiting for a restart, then do nothing.
10702 return true;
10703 }
10704
10705 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10706 + " " + r.intent);
10707
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010708 // We are now bringing the service up, so no longer in the
10709 // restarting state.
10710 mRestartingServices.remove(r);
10711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010712 final String appName = r.processName;
10713 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10714 if (app != null && app.thread != null) {
10715 try {
10716 realStartServiceLocked(r, app);
10717 return true;
10718 } catch (RemoteException e) {
10719 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10720 }
10721
10722 // If a dead object exception was thrown -- fall through to
10723 // restart the application.
10724 }
10725
Dianne Hackborn36124872009-10-08 16:22:03 -070010726 // Not running -- get it started, and enqueue this service record
10727 // to be executed when the app comes up.
10728 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10729 "service", r.name, false) == null) {
10730 Log.w(TAG, "Unable to launch app "
10731 + r.appInfo.packageName + "/"
10732 + r.appInfo.uid + " for service "
10733 + r.intent.getIntent() + ": process is bad");
10734 bringDownServiceLocked(r, true);
10735 return false;
10736 }
10737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010738 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010739 mPendingServices.add(r);
10740 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010742 return true;
10743 }
10744
10745 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10746 //Log.i(TAG, "Bring down service:");
10747 //r.dump(" ");
10748
10749 // Does it still need to run?
10750 if (!force && r.startRequested) {
10751 return;
10752 }
10753 if (r.connections.size() > 0) {
10754 if (!force) {
10755 // XXX should probably keep a count of the number of auto-create
10756 // connections directly in the service.
10757 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10758 while (it.hasNext()) {
10759 ConnectionRecord cr = it.next();
10760 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10761 return;
10762 }
10763 }
10764 }
10765
10766 // Report to all of the connections that the service is no longer
10767 // available.
10768 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10769 while (it.hasNext()) {
10770 ConnectionRecord c = it.next();
10771 try {
10772 // todo: shouldn't be a synchronous call!
10773 c.conn.connected(r.name, null);
10774 } catch (Exception e) {
10775 Log.w(TAG, "Failure disconnecting service " + r.name +
10776 " to connection " + c.conn.asBinder() +
10777 " (in " + c.binding.client.processName + ")", e);
10778 }
10779 }
10780 }
10781
10782 // Tell the service that it has been unbound.
10783 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10784 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10785 while (it.hasNext()) {
10786 IntentBindRecord ibr = it.next();
10787 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10788 + ": hasBound=" + ibr.hasBound);
10789 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10790 try {
10791 bumpServiceExecutingLocked(r);
10792 updateOomAdjLocked(r.app);
10793 ibr.hasBound = false;
10794 r.app.thread.scheduleUnbindService(r,
10795 ibr.intent.getIntent());
10796 } catch (Exception e) {
10797 Log.w(TAG, "Exception when unbinding service "
10798 + r.shortName, e);
10799 serviceDoneExecutingLocked(r, true);
10800 }
10801 }
10802 }
10803 }
10804
10805 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10806 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010807 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010808 System.identityHashCode(r), r.shortName,
10809 (r.app != null) ? r.app.pid : -1);
10810
10811 mServices.remove(r.name);
10812 mServicesByIntent.remove(r.intent);
10813 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10814 r.totalRestartCount = 0;
10815 unscheduleServiceRestartLocked(r);
10816
10817 // Also make sure it is not on the pending list.
10818 int N = mPendingServices.size();
10819 for (int i=0; i<N; i++) {
10820 if (mPendingServices.get(i) == r) {
10821 mPendingServices.remove(i);
10822 if (DEBUG_SERVICE) Log.v(
10823 TAG, "Removed pending service: " + r.shortName);
10824 i--;
10825 N--;
10826 }
10827 }
10828
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010829 r.cancelNotification();
10830 r.isForeground = false;
10831 r.foregroundId = 0;
10832 r.foregroundNoti = null;
10833
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010834 // Clear start entries.
10835 r.deliveredStarts.clear();
10836 r.pendingStarts.clear();
10837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010838 if (r.app != null) {
10839 synchronized (r.stats.getBatteryStats()) {
10840 r.stats.stopLaunchedLocked();
10841 }
10842 r.app.services.remove(r);
10843 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010844 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010845 if (DEBUG_SERVICE) Log.v(TAG,
10846 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010847 bumpServiceExecutingLocked(r);
10848 mStoppingServices.add(r);
10849 updateOomAdjLocked(r.app);
10850 r.app.thread.scheduleStopService(r);
10851 } catch (Exception e) {
10852 Log.w(TAG, "Exception when stopping service "
10853 + r.shortName, e);
10854 serviceDoneExecutingLocked(r, true);
10855 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010856 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010857 } else {
10858 if (DEBUG_SERVICE) Log.v(
10859 TAG, "Removed service that has no process: " + r.shortName);
10860 }
10861 } else {
10862 if (DEBUG_SERVICE) Log.v(
10863 TAG, "Removed service that is not running: " + r.shortName);
10864 }
10865 }
10866
10867 ComponentName startServiceLocked(IApplicationThread caller,
10868 Intent service, String resolvedType,
10869 int callingPid, int callingUid) {
10870 synchronized(this) {
10871 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10872 + " type=" + resolvedType + " args=" + service.getExtras());
10873
10874 if (caller != null) {
10875 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10876 if (callerApp == null) {
10877 throw new SecurityException(
10878 "Unable to find app for caller " + caller
10879 + " (pid=" + Binder.getCallingPid()
10880 + ") when starting service " + service);
10881 }
10882 }
10883
10884 ServiceLookupResult res =
10885 retrieveServiceLocked(service, resolvedType,
10886 callingPid, callingUid);
10887 if (res == null) {
10888 return null;
10889 }
10890 if (res.record == null) {
10891 return new ComponentName("!", res.permission != null
10892 ? res.permission : "private to package");
10893 }
10894 ServiceRecord r = res.record;
10895 if (unscheduleServiceRestartLocked(r)) {
10896 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10897 + r.shortName);
10898 }
10899 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010900 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010901 r.lastStartId++;
10902 if (r.lastStartId < 1) {
10903 r.lastStartId = 1;
10904 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010905 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010906 r.lastActivity = SystemClock.uptimeMillis();
10907 synchronized (r.stats.getBatteryStats()) {
10908 r.stats.startRunningLocked();
10909 }
10910 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10911 return new ComponentName("!", "Service process is bad");
10912 }
10913 return r.name;
10914 }
10915 }
10916
10917 public ComponentName startService(IApplicationThread caller, Intent service,
10918 String resolvedType) {
10919 // Refuse possible leaked file descriptors
10920 if (service != null && service.hasFileDescriptors() == true) {
10921 throw new IllegalArgumentException("File descriptors passed in Intent");
10922 }
10923
10924 synchronized(this) {
10925 final int callingPid = Binder.getCallingPid();
10926 final int callingUid = Binder.getCallingUid();
10927 final long origId = Binder.clearCallingIdentity();
10928 ComponentName res = startServiceLocked(caller, service,
10929 resolvedType, callingPid, callingUid);
10930 Binder.restoreCallingIdentity(origId);
10931 return res;
10932 }
10933 }
10934
10935 ComponentName startServiceInPackage(int uid,
10936 Intent service, String resolvedType) {
10937 synchronized(this) {
10938 final long origId = Binder.clearCallingIdentity();
10939 ComponentName res = startServiceLocked(null, service,
10940 resolvedType, -1, uid);
10941 Binder.restoreCallingIdentity(origId);
10942 return res;
10943 }
10944 }
10945
10946 public int stopService(IApplicationThread caller, Intent service,
10947 String resolvedType) {
10948 // Refuse possible leaked file descriptors
10949 if (service != null && service.hasFileDescriptors() == true) {
10950 throw new IllegalArgumentException("File descriptors passed in Intent");
10951 }
10952
10953 synchronized(this) {
10954 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10955 + " type=" + resolvedType);
10956
10957 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10958 if (caller != null && callerApp == null) {
10959 throw new SecurityException(
10960 "Unable to find app for caller " + caller
10961 + " (pid=" + Binder.getCallingPid()
10962 + ") when stopping service " + service);
10963 }
10964
10965 // If this service is active, make sure it is stopped.
10966 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10967 if (r != null) {
10968 if (r.record != null) {
10969 synchronized (r.record.stats.getBatteryStats()) {
10970 r.record.stats.stopRunningLocked();
10971 }
10972 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010973 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010974 final long origId = Binder.clearCallingIdentity();
10975 bringDownServiceLocked(r.record, false);
10976 Binder.restoreCallingIdentity(origId);
10977 return 1;
10978 }
10979 return -1;
10980 }
10981 }
10982
10983 return 0;
10984 }
10985
10986 public IBinder peekService(Intent service, String resolvedType) {
10987 // Refuse possible leaked file descriptors
10988 if (service != null && service.hasFileDescriptors() == true) {
10989 throw new IllegalArgumentException("File descriptors passed in Intent");
10990 }
10991
10992 IBinder ret = null;
10993
10994 synchronized(this) {
10995 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10996
10997 if (r != null) {
10998 // r.record is null if findServiceLocked() failed the caller permission check
10999 if (r.record == null) {
11000 throw new SecurityException(
11001 "Permission Denial: Accessing service " + r.record.name
11002 + " from pid=" + Binder.getCallingPid()
11003 + ", uid=" + Binder.getCallingUid()
11004 + " requires " + r.permission);
11005 }
11006 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11007 if (ib != null) {
11008 ret = ib.binder;
11009 }
11010 }
11011 }
11012
11013 return ret;
11014 }
11015
11016 public boolean stopServiceToken(ComponentName className, IBinder token,
11017 int startId) {
11018 synchronized(this) {
11019 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11020 + " " + token + " startId=" + startId);
11021 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011022 if (r != null) {
11023 if (startId >= 0) {
11024 // Asked to only stop if done with all work. Note that
11025 // to avoid leaks, we will take this as dropping all
11026 // start items up to and including this one.
11027 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11028 if (si != null) {
11029 while (r.deliveredStarts.size() > 0) {
11030 if (r.deliveredStarts.remove(0) == si) {
11031 break;
11032 }
11033 }
11034 }
11035
11036 if (r.lastStartId != startId) {
11037 return false;
11038 }
11039
11040 if (r.deliveredStarts.size() > 0) {
11041 Log.w(TAG, "stopServiceToken startId " + startId
11042 + " is last, but have " + r.deliveredStarts.size()
11043 + " remaining args");
11044 }
11045 }
11046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011047 synchronized (r.stats.getBatteryStats()) {
11048 r.stats.stopRunningLocked();
11049 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011050 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011051 }
11052 final long origId = Binder.clearCallingIdentity();
11053 bringDownServiceLocked(r, false);
11054 Binder.restoreCallingIdentity(origId);
11055 return true;
11056 }
11057 }
11058 return false;
11059 }
11060
11061 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011062 int id, Notification notification, boolean removeNotification) {
11063 final long origId = Binder.clearCallingIdentity();
11064 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011065 synchronized(this) {
11066 ServiceRecord r = findServiceLocked(className, token);
11067 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011068 if (id != 0) {
11069 if (notification == null) {
11070 throw new IllegalArgumentException("null notification");
11071 }
11072 if (r.foregroundId != id) {
11073 r.cancelNotification();
11074 r.foregroundId = id;
11075 }
11076 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11077 r.foregroundNoti = notification;
11078 r.isForeground = true;
11079 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011080 if (r.app != null) {
11081 updateServiceForegroundLocked(r.app, true);
11082 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011083 } else {
11084 if (r.isForeground) {
11085 r.isForeground = false;
11086 if (r.app != null) {
11087 updateServiceForegroundLocked(r.app, true);
11088 }
11089 }
11090 if (removeNotification) {
11091 r.cancelNotification();
11092 r.foregroundId = 0;
11093 r.foregroundNoti = null;
11094 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011095 }
11096 }
11097 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011098 } finally {
11099 Binder.restoreCallingIdentity(origId);
11100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011101 }
11102
11103 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11104 boolean anyForeground = false;
11105 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11106 if (sr.isForeground) {
11107 anyForeground = true;
11108 break;
11109 }
11110 }
11111 if (anyForeground != proc.foregroundServices) {
11112 proc.foregroundServices = anyForeground;
11113 if (oomAdj) {
11114 updateOomAdjLocked();
11115 }
11116 }
11117 }
11118
11119 public int bindService(IApplicationThread caller, IBinder token,
11120 Intent service, String resolvedType,
11121 IServiceConnection connection, int flags) {
11122 // Refuse possible leaked file descriptors
11123 if (service != null && service.hasFileDescriptors() == true) {
11124 throw new IllegalArgumentException("File descriptors passed in Intent");
11125 }
11126
11127 synchronized(this) {
11128 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11129 + " type=" + resolvedType + " conn=" + connection.asBinder()
11130 + " flags=0x" + Integer.toHexString(flags));
11131 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11132 if (callerApp == null) {
11133 throw new SecurityException(
11134 "Unable to find app for caller " + caller
11135 + " (pid=" + Binder.getCallingPid()
11136 + ") when binding service " + service);
11137 }
11138
11139 HistoryRecord activity = null;
11140 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011141 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011142 if (aindex < 0) {
11143 Log.w(TAG, "Binding with unknown activity: " + token);
11144 return 0;
11145 }
11146 activity = (HistoryRecord)mHistory.get(aindex);
11147 }
11148
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011149 int clientLabel = 0;
11150 PendingIntent clientIntent = null;
11151
11152 if (callerApp.info.uid == Process.SYSTEM_UID) {
11153 // Hacky kind of thing -- allow system stuff to tell us
11154 // what they are, so we can report this elsewhere for
11155 // others to know why certain services are running.
11156 try {
11157 clientIntent = (PendingIntent)service.getParcelableExtra(
11158 Intent.EXTRA_CLIENT_INTENT);
11159 } catch (RuntimeException e) {
11160 }
11161 if (clientIntent != null) {
11162 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11163 if (clientLabel != 0) {
11164 // There are no useful extras in the intent, trash them.
11165 // System code calling with this stuff just needs to know
11166 // this will happen.
11167 service = service.cloneFilter();
11168 }
11169 }
11170 }
11171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011172 ServiceLookupResult res =
11173 retrieveServiceLocked(service, resolvedType,
11174 Binder.getCallingPid(), Binder.getCallingUid());
11175 if (res == null) {
11176 return 0;
11177 }
11178 if (res.record == null) {
11179 return -1;
11180 }
11181 ServiceRecord s = res.record;
11182
11183 final long origId = Binder.clearCallingIdentity();
11184
11185 if (unscheduleServiceRestartLocked(s)) {
11186 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11187 + s.shortName);
11188 }
11189
11190 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11191 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011192 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011193
11194 IBinder binder = connection.asBinder();
11195 s.connections.put(binder, c);
11196 b.connections.add(c);
11197 if (activity != null) {
11198 if (activity.connections == null) {
11199 activity.connections = new HashSet<ConnectionRecord>();
11200 }
11201 activity.connections.add(c);
11202 }
11203 b.client.connections.add(c);
11204 mServiceConnections.put(binder, c);
11205
11206 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11207 s.lastActivity = SystemClock.uptimeMillis();
11208 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11209 return 0;
11210 }
11211 }
11212
11213 if (s.app != null) {
11214 // This could have made the service more important.
11215 updateOomAdjLocked(s.app);
11216 }
11217
11218 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11219 + ": received=" + b.intent.received
11220 + " apps=" + b.intent.apps.size()
11221 + " doRebind=" + b.intent.doRebind);
11222
11223 if (s.app != null && b.intent.received) {
11224 // Service is already running, so we can immediately
11225 // publish the connection.
11226 try {
11227 c.conn.connected(s.name, b.intent.binder);
11228 } catch (Exception e) {
11229 Log.w(TAG, "Failure sending service " + s.shortName
11230 + " to connection " + c.conn.asBinder()
11231 + " (in " + c.binding.client.processName + ")", e);
11232 }
11233
11234 // If this is the first app connected back to this binding,
11235 // and the service had previously asked to be told when
11236 // rebound, then do so.
11237 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11238 requestServiceBindingLocked(s, b.intent, true);
11239 }
11240 } else if (!b.intent.requested) {
11241 requestServiceBindingLocked(s, b.intent, false);
11242 }
11243
11244 Binder.restoreCallingIdentity(origId);
11245 }
11246
11247 return 1;
11248 }
11249
11250 private void removeConnectionLocked(
11251 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11252 IBinder binder = c.conn.asBinder();
11253 AppBindRecord b = c.binding;
11254 ServiceRecord s = b.service;
11255 s.connections.remove(binder);
11256 b.connections.remove(c);
11257 if (c.activity != null && c.activity != skipAct) {
11258 if (c.activity.connections != null) {
11259 c.activity.connections.remove(c);
11260 }
11261 }
11262 if (b.client != skipApp) {
11263 b.client.connections.remove(c);
11264 }
11265 mServiceConnections.remove(binder);
11266
11267 if (b.connections.size() == 0) {
11268 b.intent.apps.remove(b.client);
11269 }
11270
11271 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11272 + ": shouldUnbind=" + b.intent.hasBound);
11273 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11274 && b.intent.hasBound) {
11275 try {
11276 bumpServiceExecutingLocked(s);
11277 updateOomAdjLocked(s.app);
11278 b.intent.hasBound = false;
11279 // Assume the client doesn't want to know about a rebind;
11280 // we will deal with that later if it asks for one.
11281 b.intent.doRebind = false;
11282 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11283 } catch (Exception e) {
11284 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11285 serviceDoneExecutingLocked(s, true);
11286 }
11287 }
11288
11289 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11290 bringDownServiceLocked(s, false);
11291 }
11292 }
11293
11294 public boolean unbindService(IServiceConnection connection) {
11295 synchronized (this) {
11296 IBinder binder = connection.asBinder();
11297 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11298 ConnectionRecord r = mServiceConnections.get(binder);
11299 if (r == null) {
11300 Log.w(TAG, "Unbind failed: could not find connection for "
11301 + connection.asBinder());
11302 return false;
11303 }
11304
11305 final long origId = Binder.clearCallingIdentity();
11306
11307 removeConnectionLocked(r, null, null);
11308
11309 if (r.binding.service.app != null) {
11310 // This could have made the service less important.
11311 updateOomAdjLocked(r.binding.service.app);
11312 }
11313
11314 Binder.restoreCallingIdentity(origId);
11315 }
11316
11317 return true;
11318 }
11319
11320 public void publishService(IBinder token, Intent intent, IBinder service) {
11321 // Refuse possible leaked file descriptors
11322 if (intent != null && intent.hasFileDescriptors() == true) {
11323 throw new IllegalArgumentException("File descriptors passed in Intent");
11324 }
11325
11326 synchronized(this) {
11327 if (!(token instanceof ServiceRecord)) {
11328 throw new IllegalArgumentException("Invalid service token");
11329 }
11330 ServiceRecord r = (ServiceRecord)token;
11331
11332 final long origId = Binder.clearCallingIdentity();
11333
11334 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11335 + " " + intent + ": " + service);
11336 if (r != null) {
11337 Intent.FilterComparison filter
11338 = new Intent.FilterComparison(intent);
11339 IntentBindRecord b = r.bindings.get(filter);
11340 if (b != null && !b.received) {
11341 b.binder = service;
11342 b.requested = true;
11343 b.received = true;
11344 if (r.connections.size() > 0) {
11345 Iterator<ConnectionRecord> it
11346 = r.connections.values().iterator();
11347 while (it.hasNext()) {
11348 ConnectionRecord c = it.next();
11349 if (!filter.equals(c.binding.intent.intent)) {
11350 if (DEBUG_SERVICE) Log.v(
11351 TAG, "Not publishing to: " + c);
11352 if (DEBUG_SERVICE) Log.v(
11353 TAG, "Bound intent: " + c.binding.intent.intent);
11354 if (DEBUG_SERVICE) Log.v(
11355 TAG, "Published intent: " + intent);
11356 continue;
11357 }
11358 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11359 try {
11360 c.conn.connected(r.name, service);
11361 } catch (Exception e) {
11362 Log.w(TAG, "Failure sending service " + r.name +
11363 " to connection " + c.conn.asBinder() +
11364 " (in " + c.binding.client.processName + ")", e);
11365 }
11366 }
11367 }
11368 }
11369
11370 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11371
11372 Binder.restoreCallingIdentity(origId);
11373 }
11374 }
11375 }
11376
11377 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11378 // Refuse possible leaked file descriptors
11379 if (intent != null && intent.hasFileDescriptors() == true) {
11380 throw new IllegalArgumentException("File descriptors passed in Intent");
11381 }
11382
11383 synchronized(this) {
11384 if (!(token instanceof ServiceRecord)) {
11385 throw new IllegalArgumentException("Invalid service token");
11386 }
11387 ServiceRecord r = (ServiceRecord)token;
11388
11389 final long origId = Binder.clearCallingIdentity();
11390
11391 if (r != null) {
11392 Intent.FilterComparison filter
11393 = new Intent.FilterComparison(intent);
11394 IntentBindRecord b = r.bindings.get(filter);
11395 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11396 + " at " + b + ": apps="
11397 + (b != null ? b.apps.size() : 0));
11398 if (b != null) {
11399 if (b.apps.size() > 0) {
11400 // Applications have already bound since the last
11401 // unbind, so just rebind right here.
11402 requestServiceBindingLocked(r, b, true);
11403 } else {
11404 // Note to tell the service the next time there is
11405 // a new client.
11406 b.doRebind = true;
11407 }
11408 }
11409
11410 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11411
11412 Binder.restoreCallingIdentity(origId);
11413 }
11414 }
11415 }
11416
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011417 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011418 synchronized(this) {
11419 if (!(token instanceof ServiceRecord)) {
11420 throw new IllegalArgumentException("Invalid service token");
11421 }
11422 ServiceRecord r = (ServiceRecord)token;
11423 boolean inStopping = mStoppingServices.contains(token);
11424 if (r != null) {
11425 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11426 + ": nesting=" + r.executeNesting
11427 + ", inStopping=" + inStopping);
11428 if (r != token) {
11429 Log.w(TAG, "Done executing service " + r.name
11430 + " with incorrect token: given " + token
11431 + ", expected " + r);
11432 return;
11433 }
11434
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011435 if (type == 1) {
11436 // This is a call from a service start... take care of
11437 // book-keeping.
11438 r.callStart = true;
11439 switch (res) {
11440 case Service.START_STICKY_COMPATIBILITY:
11441 case Service.START_STICKY: {
11442 // We are done with the associated start arguments.
11443 r.findDeliveredStart(startId, true);
11444 // Don't stop if killed.
11445 r.stopIfKilled = false;
11446 break;
11447 }
11448 case Service.START_NOT_STICKY: {
11449 // We are done with the associated start arguments.
11450 r.findDeliveredStart(startId, true);
11451 if (r.lastStartId == startId) {
11452 // There is no more work, and this service
11453 // doesn't want to hang around if killed.
11454 r.stopIfKilled = true;
11455 }
11456 break;
11457 }
11458 case Service.START_REDELIVER_INTENT: {
11459 // We'll keep this item until they explicitly
11460 // call stop for it, but keep track of the fact
11461 // that it was delivered.
11462 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11463 if (si != null) {
11464 si.deliveryCount = 0;
11465 si.doneExecutingCount++;
11466 // Don't stop if killed.
11467 r.stopIfKilled = true;
11468 }
11469 break;
11470 }
11471 default:
11472 throw new IllegalArgumentException(
11473 "Unknown service start result: " + res);
11474 }
11475 if (res == Service.START_STICKY_COMPATIBILITY) {
11476 r.callStart = false;
11477 }
11478 }
11479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011480 final long origId = Binder.clearCallingIdentity();
11481 serviceDoneExecutingLocked(r, inStopping);
11482 Binder.restoreCallingIdentity(origId);
11483 } else {
11484 Log.w(TAG, "Done executing unknown service " + r.name
11485 + " with token " + token);
11486 }
11487 }
11488 }
11489
11490 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11491 r.executeNesting--;
11492 if (r.executeNesting <= 0 && r.app != null) {
11493 r.app.executingServices.remove(r);
11494 if (r.app.executingServices.size() == 0) {
11495 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11496 }
11497 if (inStopping) {
11498 mStoppingServices.remove(r);
11499 }
11500 updateOomAdjLocked(r.app);
11501 }
11502 }
11503
11504 void serviceTimeout(ProcessRecord proc) {
11505 synchronized(this) {
11506 if (proc.executingServices.size() == 0 || proc.thread == null) {
11507 return;
11508 }
11509 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11510 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11511 ServiceRecord timeout = null;
11512 long nextTime = 0;
11513 while (it.hasNext()) {
11514 ServiceRecord sr = it.next();
11515 if (sr.executingStart < maxTime) {
11516 timeout = sr;
11517 break;
11518 }
11519 if (sr.executingStart > nextTime) {
11520 nextTime = sr.executingStart;
11521 }
11522 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011523 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011524 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnorb7f03672009-12-09 16:22:32 -080011525 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011526 } else {
11527 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11528 msg.obj = proc;
11529 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11530 }
11531 }
11532 }
11533
11534 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011535 // BACKUP AND RESTORE
11536 // =========================================================
11537
11538 // Cause the target app to be launched if necessary and its backup agent
11539 // instantiated. The backup agent will invoke backupAgentCreated() on the
11540 // activity manager to announce its creation.
11541 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11542 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11543 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11544
11545 synchronized(this) {
11546 // !!! TODO: currently no check here that we're already bound
11547 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11548 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11549 synchronized (stats) {
11550 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11551 }
11552
11553 BackupRecord r = new BackupRecord(ss, app, backupMode);
11554 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11555 // startProcessLocked() returns existing proc's record if it's already running
11556 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011557 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011558 if (proc == null) {
11559 Log.e(TAG, "Unable to start backup agent process " + r);
11560 return false;
11561 }
11562
11563 r.app = proc;
11564 mBackupTarget = r;
11565 mBackupAppName = app.packageName;
11566
Christopher Tate6fa95972009-06-05 18:43:55 -070011567 // Try not to kill the process during backup
11568 updateOomAdjLocked(proc);
11569
Christopher Tate181fafa2009-05-14 11:12:14 -070011570 // If the process is already attached, schedule the creation of the backup agent now.
11571 // If it is not yet live, this will be done when it attaches to the framework.
11572 if (proc.thread != null) {
11573 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11574 try {
11575 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11576 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011577 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011578 }
11579 } else {
11580 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11581 }
11582 // Invariants: at this point, the target app process exists and the application
11583 // is either already running or in the process of coming up. mBackupTarget and
11584 // mBackupAppName describe the app, so that when it binds back to the AM we
11585 // know that it's scheduled for a backup-agent operation.
11586 }
11587
11588 return true;
11589 }
11590
11591 // A backup agent has just come up
11592 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11593 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11594 + " = " + agent);
11595
11596 synchronized(this) {
11597 if (!agentPackageName.equals(mBackupAppName)) {
11598 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11599 return;
11600 }
11601
Christopher Tate043dadc2009-06-02 16:11:00 -070011602 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011603 try {
11604 IBackupManager bm = IBackupManager.Stub.asInterface(
11605 ServiceManager.getService(Context.BACKUP_SERVICE));
11606 bm.agentConnected(agentPackageName, agent);
11607 } catch (RemoteException e) {
11608 // can't happen; the backup manager service is local
11609 } catch (Exception e) {
11610 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11611 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011612 } finally {
11613 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011614 }
11615 }
11616 }
11617
11618 // done with this agent
11619 public void unbindBackupAgent(ApplicationInfo appInfo) {
11620 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011621 if (appInfo == null) {
11622 Log.w(TAG, "unbind backup agent for null app");
11623 return;
11624 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011625
11626 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011627 if (mBackupAppName == null) {
11628 Log.w(TAG, "Unbinding backup agent with no active backup");
11629 return;
11630 }
11631
Christopher Tate181fafa2009-05-14 11:12:14 -070011632 if (!mBackupAppName.equals(appInfo.packageName)) {
11633 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11634 return;
11635 }
11636
Christopher Tate6fa95972009-06-05 18:43:55 -070011637 ProcessRecord proc = mBackupTarget.app;
11638 mBackupTarget = null;
11639 mBackupAppName = null;
11640
11641 // Not backing this app up any more; reset its OOM adjustment
11642 updateOomAdjLocked(proc);
11643
Christopher Tatec7b31e32009-06-10 15:49:30 -070011644 // If the app crashed during backup, 'thread' will be null here
11645 if (proc.thread != null) {
11646 try {
11647 proc.thread.scheduleDestroyBackupAgent(appInfo);
11648 } catch (Exception e) {
11649 Log.e(TAG, "Exception when unbinding backup agent:");
11650 e.printStackTrace();
11651 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011652 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011653 }
11654 }
11655 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011656 // BROADCASTS
11657 // =========================================================
11658
11659 private final List getStickies(String action, IntentFilter filter,
11660 List cur) {
11661 final ContentResolver resolver = mContext.getContentResolver();
11662 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11663 if (list == null) {
11664 return cur;
11665 }
11666 int N = list.size();
11667 for (int i=0; i<N; i++) {
11668 Intent intent = list.get(i);
11669 if (filter.match(resolver, intent, true, TAG) >= 0) {
11670 if (cur == null) {
11671 cur = new ArrayList<Intent>();
11672 }
11673 cur.add(intent);
11674 }
11675 }
11676 return cur;
11677 }
11678
11679 private final void scheduleBroadcastsLocked() {
11680 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11681 + mBroadcastsScheduled);
11682
11683 if (mBroadcastsScheduled) {
11684 return;
11685 }
11686 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11687 mBroadcastsScheduled = true;
11688 }
11689
11690 public Intent registerReceiver(IApplicationThread caller,
11691 IIntentReceiver receiver, IntentFilter filter, String permission) {
11692 synchronized(this) {
11693 ProcessRecord callerApp = null;
11694 if (caller != null) {
11695 callerApp = getRecordForAppLocked(caller);
11696 if (callerApp == null) {
11697 throw new SecurityException(
11698 "Unable to find app for caller " + caller
11699 + " (pid=" + Binder.getCallingPid()
11700 + ") when registering receiver " + receiver);
11701 }
11702 }
11703
11704 List allSticky = null;
11705
11706 // Look for any matching sticky broadcasts...
11707 Iterator actions = filter.actionsIterator();
11708 if (actions != null) {
11709 while (actions.hasNext()) {
11710 String action = (String)actions.next();
11711 allSticky = getStickies(action, filter, allSticky);
11712 }
11713 } else {
11714 allSticky = getStickies(null, filter, allSticky);
11715 }
11716
11717 // The first sticky in the list is returned directly back to
11718 // the client.
11719 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11720
11721 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11722 + ": " + sticky);
11723
11724 if (receiver == null) {
11725 return sticky;
11726 }
11727
11728 ReceiverList rl
11729 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11730 if (rl == null) {
11731 rl = new ReceiverList(this, callerApp,
11732 Binder.getCallingPid(),
11733 Binder.getCallingUid(), receiver);
11734 if (rl.app != null) {
11735 rl.app.receivers.add(rl);
11736 } else {
11737 try {
11738 receiver.asBinder().linkToDeath(rl, 0);
11739 } catch (RemoteException e) {
11740 return sticky;
11741 }
11742 rl.linkedToDeath = true;
11743 }
11744 mRegisteredReceivers.put(receiver.asBinder(), rl);
11745 }
11746 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11747 rl.add(bf);
11748 if (!bf.debugCheck()) {
11749 Log.w(TAG, "==> For Dynamic broadast");
11750 }
11751 mReceiverResolver.addFilter(bf);
11752
11753 // Enqueue broadcasts for all existing stickies that match
11754 // this filter.
11755 if (allSticky != null) {
11756 ArrayList receivers = new ArrayList();
11757 receivers.add(bf);
11758
11759 int N = allSticky.size();
11760 for (int i=0; i<N; i++) {
11761 Intent intent = (Intent)allSticky.get(i);
11762 BroadcastRecord r = new BroadcastRecord(intent, null,
11763 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011764 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011765 if (mParallelBroadcasts.size() == 0) {
11766 scheduleBroadcastsLocked();
11767 }
11768 mParallelBroadcasts.add(r);
11769 }
11770 }
11771
11772 return sticky;
11773 }
11774 }
11775
11776 public void unregisterReceiver(IIntentReceiver receiver) {
11777 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11778
11779 boolean doNext = false;
11780
11781 synchronized(this) {
11782 ReceiverList rl
11783 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11784 if (rl != null) {
11785 if (rl.curBroadcast != null) {
11786 BroadcastRecord r = rl.curBroadcast;
11787 doNext = finishReceiverLocked(
11788 receiver.asBinder(), r.resultCode, r.resultData,
11789 r.resultExtras, r.resultAbort, true);
11790 }
11791
11792 if (rl.app != null) {
11793 rl.app.receivers.remove(rl);
11794 }
11795 removeReceiverLocked(rl);
11796 if (rl.linkedToDeath) {
11797 rl.linkedToDeath = false;
11798 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11799 }
11800 }
11801 }
11802
11803 if (!doNext) {
11804 return;
11805 }
11806
11807 final long origId = Binder.clearCallingIdentity();
11808 processNextBroadcast(false);
11809 trimApplications();
11810 Binder.restoreCallingIdentity(origId);
11811 }
11812
11813 void removeReceiverLocked(ReceiverList rl) {
11814 mRegisteredReceivers.remove(rl.receiver.asBinder());
11815 int N = rl.size();
11816 for (int i=0; i<N; i++) {
11817 mReceiverResolver.removeFilter(rl.get(i));
11818 }
11819 }
11820
11821 private final int broadcastIntentLocked(ProcessRecord callerApp,
11822 String callerPackage, Intent intent, String resolvedType,
11823 IIntentReceiver resultTo, int resultCode, String resultData,
11824 Bundle map, String requiredPermission,
11825 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11826 intent = new Intent(intent);
11827
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011828 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011829 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11830 + " ordered=" + ordered);
11831 if ((resultTo != null) && !ordered) {
11832 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11833 }
11834
11835 // Handle special intents: if this broadcast is from the package
11836 // manager about a package being removed, we need to remove all of
11837 // its activities from the history stack.
11838 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11839 intent.getAction());
11840 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11841 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11842 || uidRemoved) {
11843 if (checkComponentPermission(
11844 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11845 callingPid, callingUid, -1)
11846 == PackageManager.PERMISSION_GRANTED) {
11847 if (uidRemoved) {
11848 final Bundle intentExtras = intent.getExtras();
11849 final int uid = intentExtras != null
11850 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11851 if (uid >= 0) {
11852 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11853 synchronized (bs) {
11854 bs.removeUidStatsLocked(uid);
11855 }
11856 }
11857 } else {
11858 Uri data = intent.getData();
11859 String ssp;
11860 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11861 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11862 uninstallPackageLocked(ssp,
11863 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011864 AttributeCache ac = AttributeCache.instance();
11865 if (ac != null) {
11866 ac.removePackage(ssp);
11867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011868 }
11869 }
11870 }
11871 } else {
11872 String msg = "Permission Denial: " + intent.getAction()
11873 + " broadcast from " + callerPackage + " (pid=" + callingPid
11874 + ", uid=" + callingUid + ")"
11875 + " requires "
11876 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11877 Log.w(TAG, msg);
11878 throw new SecurityException(msg);
11879 }
11880 }
11881
11882 /*
11883 * If this is the time zone changed action, queue up a message that will reset the timezone
11884 * of all currently running processes. This message will get queued up before the broadcast
11885 * happens.
11886 */
11887 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11888 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11889 }
11890
Dianne Hackborn854060af2009-07-09 18:14:31 -070011891 /*
11892 * Prevent non-system code (defined here to be non-persistent
11893 * processes) from sending protected broadcasts.
11894 */
11895 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11896 || callingUid == Process.SHELL_UID || callingUid == 0) {
11897 // Always okay.
11898 } else if (callerApp == null || !callerApp.persistent) {
11899 try {
11900 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11901 intent.getAction())) {
11902 String msg = "Permission Denial: not allowed to send broadcast "
11903 + intent.getAction() + " from pid="
11904 + callingPid + ", uid=" + callingUid;
11905 Log.w(TAG, msg);
11906 throw new SecurityException(msg);
11907 }
11908 } catch (RemoteException e) {
11909 Log.w(TAG, "Remote exception", e);
11910 return BROADCAST_SUCCESS;
11911 }
11912 }
11913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011914 // Add to the sticky list if requested.
11915 if (sticky) {
11916 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11917 callingPid, callingUid)
11918 != PackageManager.PERMISSION_GRANTED) {
11919 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11920 + callingPid + ", uid=" + callingUid
11921 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11922 Log.w(TAG, msg);
11923 throw new SecurityException(msg);
11924 }
11925 if (requiredPermission != null) {
11926 Log.w(TAG, "Can't broadcast sticky intent " + intent
11927 + " and enforce permission " + requiredPermission);
11928 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11929 }
11930 if (intent.getComponent() != null) {
11931 throw new SecurityException(
11932 "Sticky broadcasts can't target a specific component");
11933 }
11934 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11935 if (list == null) {
11936 list = new ArrayList<Intent>();
11937 mStickyBroadcasts.put(intent.getAction(), list);
11938 }
11939 int N = list.size();
11940 int i;
11941 for (i=0; i<N; i++) {
11942 if (intent.filterEquals(list.get(i))) {
11943 // This sticky already exists, replace it.
11944 list.set(i, new Intent(intent));
11945 break;
11946 }
11947 }
11948 if (i >= N) {
11949 list.add(new Intent(intent));
11950 }
11951 }
11952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011953 // Figure out who all will receive this broadcast.
11954 List receivers = null;
11955 List<BroadcastFilter> registeredReceivers = null;
11956 try {
11957 if (intent.getComponent() != null) {
11958 // Broadcast is going to one specific receiver class...
11959 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011960 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011961 if (ai != null) {
11962 receivers = new ArrayList();
11963 ResolveInfo ri = new ResolveInfo();
11964 ri.activityInfo = ai;
11965 receivers.add(ri);
11966 }
11967 } else {
11968 // Need to resolve the intent to interested receivers...
11969 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11970 == 0) {
11971 receivers =
11972 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011973 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011974 }
Mihai Preda074edef2009-05-18 17:13:31 +020011975 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011976 }
11977 } catch (RemoteException ex) {
11978 // pm is in same process, this will never happen.
11979 }
11980
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080011981 final boolean replacePending =
11982 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
11983
11984 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
11985 + " replacePending=" + replacePending);
11986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011987 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11988 if (!ordered && NR > 0) {
11989 // If we are not serializing this broadcast, then send the
11990 // registered receivers separately so they don't wait for the
11991 // components to be launched.
11992 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11993 callerPackage, callingPid, callingUid, requiredPermission,
11994 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011995 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011996 if (DEBUG_BROADCAST) Log.v(
11997 TAG, "Enqueueing parallel broadcast " + r
11998 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080011999 boolean replaced = false;
12000 if (replacePending) {
12001 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12002 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12003 if (DEBUG_BROADCAST) Log.v(TAG,
12004 "***** DROPPING PARALLEL: " + intent);
12005 mParallelBroadcasts.set(i, r);
12006 replaced = true;
12007 break;
12008 }
12009 }
12010 }
12011 if (!replaced) {
12012 mParallelBroadcasts.add(r);
12013 scheduleBroadcastsLocked();
12014 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012015 registeredReceivers = null;
12016 NR = 0;
12017 }
12018
12019 // Merge into one list.
12020 int ir = 0;
12021 if (receivers != null) {
12022 // A special case for PACKAGE_ADDED: do not allow the package
12023 // being added to see this broadcast. This prevents them from
12024 // using this as a back door to get run as soon as they are
12025 // installed. Maybe in the future we want to have a special install
12026 // broadcast or such for apps, but we'd like to deliberately make
12027 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070012028 boolean skip = false;
12029 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070012030 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070012031 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
12032 skip = true;
12033 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12034 skip = true;
12035 }
12036 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012037 ? intent.getData().getSchemeSpecificPart()
12038 : null;
12039 if (skipPackage != null && receivers != null) {
12040 int NT = receivers.size();
12041 for (int it=0; it<NT; it++) {
12042 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12043 if (curt.activityInfo.packageName.equals(skipPackage)) {
12044 receivers.remove(it);
12045 it--;
12046 NT--;
12047 }
12048 }
12049 }
12050
12051 int NT = receivers != null ? receivers.size() : 0;
12052 int it = 0;
12053 ResolveInfo curt = null;
12054 BroadcastFilter curr = null;
12055 while (it < NT && ir < NR) {
12056 if (curt == null) {
12057 curt = (ResolveInfo)receivers.get(it);
12058 }
12059 if (curr == null) {
12060 curr = registeredReceivers.get(ir);
12061 }
12062 if (curr.getPriority() >= curt.priority) {
12063 // Insert this broadcast record into the final list.
12064 receivers.add(it, curr);
12065 ir++;
12066 curr = null;
12067 it++;
12068 NT++;
12069 } else {
12070 // Skip to the next ResolveInfo in the final list.
12071 it++;
12072 curt = null;
12073 }
12074 }
12075 }
12076 while (ir < NR) {
12077 if (receivers == null) {
12078 receivers = new ArrayList();
12079 }
12080 receivers.add(registeredReceivers.get(ir));
12081 ir++;
12082 }
12083
12084 if ((receivers != null && receivers.size() > 0)
12085 || resultTo != null) {
12086 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12087 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012088 receivers, resultTo, resultCode, resultData, map, ordered,
12089 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012090 if (DEBUG_BROADCAST) Log.v(
12091 TAG, "Enqueueing ordered broadcast " + r
12092 + ": prev had " + mOrderedBroadcasts.size());
12093 if (DEBUG_BROADCAST) {
12094 int seq = r.intent.getIntExtra("seq", -1);
12095 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12096 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012097 boolean replaced = false;
12098 if (replacePending) {
12099 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12100 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12101 if (DEBUG_BROADCAST) Log.v(TAG,
12102 "***** DROPPING ORDERED: " + intent);
12103 mOrderedBroadcasts.set(i, r);
12104 replaced = true;
12105 break;
12106 }
12107 }
12108 }
12109 if (!replaced) {
12110 mOrderedBroadcasts.add(r);
12111 scheduleBroadcastsLocked();
12112 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012113 }
12114
12115 return BROADCAST_SUCCESS;
12116 }
12117
12118 public final int broadcastIntent(IApplicationThread caller,
12119 Intent intent, String resolvedType, IIntentReceiver resultTo,
12120 int resultCode, String resultData, Bundle map,
12121 String requiredPermission, boolean serialized, boolean sticky) {
12122 // Refuse possible leaked file descriptors
12123 if (intent != null && intent.hasFileDescriptors() == true) {
12124 throw new IllegalArgumentException("File descriptors passed in Intent");
12125 }
12126
12127 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012128 int flags = intent.getFlags();
12129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012130 if (!mSystemReady) {
12131 // if the caller really truly claims to know what they're doing, go
12132 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012133 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12134 intent = new Intent(intent);
12135 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12136 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12137 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12138 + " before boot completion");
12139 throw new IllegalStateException("Cannot broadcast before boot completed");
12140 }
12141 }
12142
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012143 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12144 throw new IllegalArgumentException(
12145 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12146 }
12147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012148 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12149 final int callingPid = Binder.getCallingPid();
12150 final int callingUid = Binder.getCallingUid();
12151 final long origId = Binder.clearCallingIdentity();
12152 int res = broadcastIntentLocked(callerApp,
12153 callerApp != null ? callerApp.info.packageName : null,
12154 intent, resolvedType, resultTo,
12155 resultCode, resultData, map, requiredPermission, serialized,
12156 sticky, callingPid, callingUid);
12157 Binder.restoreCallingIdentity(origId);
12158 return res;
12159 }
12160 }
12161
12162 int broadcastIntentInPackage(String packageName, int uid,
12163 Intent intent, String resolvedType, IIntentReceiver resultTo,
12164 int resultCode, String resultData, Bundle map,
12165 String requiredPermission, boolean serialized, boolean sticky) {
12166 synchronized(this) {
12167 final long origId = Binder.clearCallingIdentity();
12168 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12169 resultTo, resultCode, resultData, map, requiredPermission,
12170 serialized, sticky, -1, uid);
12171 Binder.restoreCallingIdentity(origId);
12172 return res;
12173 }
12174 }
12175
12176 public final void unbroadcastIntent(IApplicationThread caller,
12177 Intent intent) {
12178 // Refuse possible leaked file descriptors
12179 if (intent != null && intent.hasFileDescriptors() == true) {
12180 throw new IllegalArgumentException("File descriptors passed in Intent");
12181 }
12182
12183 synchronized(this) {
12184 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12185 != PackageManager.PERMISSION_GRANTED) {
12186 String msg = "Permission Denial: unbroadcastIntent() from pid="
12187 + Binder.getCallingPid()
12188 + ", uid=" + Binder.getCallingUid()
12189 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12190 Log.w(TAG, msg);
12191 throw new SecurityException(msg);
12192 }
12193 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12194 if (list != null) {
12195 int N = list.size();
12196 int i;
12197 for (i=0; i<N; i++) {
12198 if (intent.filterEquals(list.get(i))) {
12199 list.remove(i);
12200 break;
12201 }
12202 }
12203 }
12204 }
12205 }
12206
12207 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12208 String resultData, Bundle resultExtras, boolean resultAbort,
12209 boolean explicit) {
12210 if (mOrderedBroadcasts.size() == 0) {
12211 if (explicit) {
12212 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12213 }
12214 return false;
12215 }
12216 BroadcastRecord r = mOrderedBroadcasts.get(0);
12217 if (r.receiver == null) {
12218 if (explicit) {
12219 Log.w(TAG, "finishReceiver called but none active");
12220 }
12221 return false;
12222 }
12223 if (r.receiver != receiver) {
12224 Log.w(TAG, "finishReceiver called but active receiver is different");
12225 return false;
12226 }
12227 int state = r.state;
12228 r.state = r.IDLE;
12229 if (state == r.IDLE) {
12230 if (explicit) {
12231 Log.w(TAG, "finishReceiver called but state is IDLE");
12232 }
12233 }
12234 r.receiver = null;
12235 r.intent.setComponent(null);
12236 if (r.curApp != null) {
12237 r.curApp.curReceiver = null;
12238 }
12239 if (r.curFilter != null) {
12240 r.curFilter.receiverList.curBroadcast = null;
12241 }
12242 r.curFilter = null;
12243 r.curApp = null;
12244 r.curComponent = null;
12245 r.curReceiver = null;
12246 mPendingBroadcast = null;
12247
12248 r.resultCode = resultCode;
12249 r.resultData = resultData;
12250 r.resultExtras = resultExtras;
12251 r.resultAbort = resultAbort;
12252
12253 // We will process the next receiver right now if this is finishing
12254 // an app receiver (which is always asynchronous) or after we have
12255 // come back from calling a receiver.
12256 return state == BroadcastRecord.APP_RECEIVE
12257 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12258 }
12259
12260 public void finishReceiver(IBinder who, int resultCode, String resultData,
12261 Bundle resultExtras, boolean resultAbort) {
12262 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12263
12264 // Refuse possible leaked file descriptors
12265 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12266 throw new IllegalArgumentException("File descriptors passed in Bundle");
12267 }
12268
12269 boolean doNext;
12270
12271 final long origId = Binder.clearCallingIdentity();
12272
12273 synchronized(this) {
12274 doNext = finishReceiverLocked(
12275 who, resultCode, resultData, resultExtras, resultAbort, true);
12276 }
12277
12278 if (doNext) {
12279 processNextBroadcast(false);
12280 }
12281 trimApplications();
12282
12283 Binder.restoreCallingIdentity(origId);
12284 }
12285
12286 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12287 if (r.nextReceiver > 0) {
12288 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12289 if (curReceiver instanceof BroadcastFilter) {
12290 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012291 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012292 System.identityHashCode(r),
12293 r.intent.getAction(),
12294 r.nextReceiver - 1,
12295 System.identityHashCode(bf));
12296 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012297 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012298 System.identityHashCode(r),
12299 r.intent.getAction(),
12300 r.nextReceiver - 1,
12301 ((ResolveInfo)curReceiver).toString());
12302 }
12303 } else {
12304 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12305 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012306 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012307 System.identityHashCode(r),
12308 r.intent.getAction(),
12309 r.nextReceiver,
12310 "NONE");
12311 }
12312 }
12313
12314 private final void broadcastTimeout() {
12315 synchronized (this) {
12316 if (mOrderedBroadcasts.size() == 0) {
12317 return;
12318 }
12319 long now = SystemClock.uptimeMillis();
12320 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012321 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012322 if (DEBUG_BROADCAST) Log.v(TAG,
12323 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012324 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012325 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012326 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012327 return;
12328 }
12329
12330 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012331 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012332 r.anrCount++;
12333
12334 // Current receiver has passed its expiration date.
12335 if (r.nextReceiver <= 0) {
12336 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12337 return;
12338 }
12339
12340 ProcessRecord app = null;
12341
12342 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12343 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12344 logBroadcastReceiverDiscard(r);
12345 if (curReceiver instanceof BroadcastFilter) {
12346 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12347 if (bf.receiverList.pid != 0
12348 && bf.receiverList.pid != MY_PID) {
12349 synchronized (this.mPidsSelfLocked) {
12350 app = this.mPidsSelfLocked.get(
12351 bf.receiverList.pid);
12352 }
12353 }
12354 } else {
12355 app = r.curApp;
12356 }
12357
12358 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012359 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012360 }
12361
12362 if (mPendingBroadcast == r) {
12363 mPendingBroadcast = null;
12364 }
12365
12366 // Move on to the next receiver.
12367 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12368 r.resultExtras, r.resultAbort, true);
12369 scheduleBroadcastsLocked();
12370 }
12371 }
12372
12373 private final void processCurBroadcastLocked(BroadcastRecord r,
12374 ProcessRecord app) throws RemoteException {
12375 if (app.thread == null) {
12376 throw new RemoteException();
12377 }
12378 r.receiver = app.thread.asBinder();
12379 r.curApp = app;
12380 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012381 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012382
12383 // Tell the application to launch this receiver.
12384 r.intent.setComponent(r.curComponent);
12385
12386 boolean started = false;
12387 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012388 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012389 "Delivering to component " + r.curComponent
12390 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012391 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012392 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12393 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12394 started = true;
12395 } finally {
12396 if (!started) {
12397 r.receiver = null;
12398 r.curApp = null;
12399 app.curReceiver = null;
12400 }
12401 }
12402
12403 }
12404
12405 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012406 Intent intent, int resultCode, String data, Bundle extras,
12407 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012408 if (app != null && app.thread != null) {
12409 // If we have an app thread, do the call through that so it is
12410 // correctly ordered with other one-way calls.
12411 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012412 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012413 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012414 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012415 }
12416 }
12417
12418 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12419 BroadcastFilter filter, boolean ordered) {
12420 boolean skip = false;
12421 if (filter.requiredPermission != null) {
12422 int perm = checkComponentPermission(filter.requiredPermission,
12423 r.callingPid, r.callingUid, -1);
12424 if (perm != PackageManager.PERMISSION_GRANTED) {
12425 Log.w(TAG, "Permission Denial: broadcasting "
12426 + r.intent.toString()
12427 + " from " + r.callerPackage + " (pid="
12428 + r.callingPid + ", uid=" + r.callingUid + ")"
12429 + " requires " + filter.requiredPermission
12430 + " due to registered receiver " + filter);
12431 skip = true;
12432 }
12433 }
12434 if (r.requiredPermission != null) {
12435 int perm = checkComponentPermission(r.requiredPermission,
12436 filter.receiverList.pid, filter.receiverList.uid, -1);
12437 if (perm != PackageManager.PERMISSION_GRANTED) {
12438 Log.w(TAG, "Permission Denial: receiving "
12439 + r.intent.toString()
12440 + " to " + filter.receiverList.app
12441 + " (pid=" + filter.receiverList.pid
12442 + ", uid=" + filter.receiverList.uid + ")"
12443 + " requires " + r.requiredPermission
12444 + " due to sender " + r.callerPackage
12445 + " (uid " + r.callingUid + ")");
12446 skip = true;
12447 }
12448 }
12449
12450 if (!skip) {
12451 // If this is not being sent as an ordered broadcast, then we
12452 // don't want to touch the fields that keep track of the current
12453 // state of ordered broadcasts.
12454 if (ordered) {
12455 r.receiver = filter.receiverList.receiver.asBinder();
12456 r.curFilter = filter;
12457 filter.receiverList.curBroadcast = r;
12458 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012459 if (filter.receiverList.app != null) {
12460 // Bump hosting application to no longer be in background
12461 // scheduling class. Note that we can't do that if there
12462 // isn't an app... but we can only be in that case for
12463 // things that directly call the IActivityManager API, which
12464 // are already core system stuff so don't matter for this.
12465 r.curApp = filter.receiverList.app;
12466 filter.receiverList.app.curReceiver = r;
12467 updateOomAdjLocked();
12468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012469 }
12470 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012471 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012472 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012473 Log.i(TAG, "Delivering to " + filter.receiverList.app
12474 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012475 }
12476 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12477 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012478 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012479 if (ordered) {
12480 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12481 }
12482 } catch (RemoteException e) {
12483 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12484 if (ordered) {
12485 r.receiver = null;
12486 r.curFilter = null;
12487 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012488 if (filter.receiverList.app != null) {
12489 filter.receiverList.app.curReceiver = null;
12490 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012491 }
12492 }
12493 }
12494 }
12495
Dianne Hackborn12527f92009-11-11 17:39:50 -080012496 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12497 if (r.callingUid < 0) {
12498 // This was from a registerReceiver() call; ignore it.
12499 return;
12500 }
12501 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12502 MAX_BROADCAST_HISTORY-1);
12503 r.finishTime = SystemClock.uptimeMillis();
12504 mBroadcastHistory[0] = r;
12505 }
12506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012507 private final void processNextBroadcast(boolean fromMsg) {
12508 synchronized(this) {
12509 BroadcastRecord r;
12510
12511 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12512 + mParallelBroadcasts.size() + " broadcasts, "
12513 + mOrderedBroadcasts.size() + " serialized broadcasts");
12514
12515 updateCpuStats();
12516
12517 if (fromMsg) {
12518 mBroadcastsScheduled = false;
12519 }
12520
12521 // First, deliver any non-serialized broadcasts right away.
12522 while (mParallelBroadcasts.size() > 0) {
12523 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012524 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012525 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012526 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12527 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012528 for (int i=0; i<N; i++) {
12529 Object target = r.receivers.get(i);
12530 if (DEBUG_BROADCAST) Log.v(TAG,
12531 "Delivering non-serialized to registered "
12532 + target + ": " + r);
12533 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12534 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012535 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012536 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12537 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012538 }
12539
12540 // Now take care of the next serialized one...
12541
12542 // If we are waiting for a process to come up to handle the next
12543 // broadcast, then do nothing at this point. Just in case, we
12544 // check that the process we're waiting for still exists.
12545 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012546 if (DEBUG_BROADCAST_LIGHT) {
12547 Log.v(TAG, "processNextBroadcast: waiting for "
12548 + mPendingBroadcast.curApp);
12549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012550
12551 boolean isDead;
12552 synchronized (mPidsSelfLocked) {
12553 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12554 }
12555 if (!isDead) {
12556 // It's still alive, so keep waiting
12557 return;
12558 } else {
12559 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12560 + " died before responding to broadcast");
12561 mPendingBroadcast = null;
12562 }
12563 }
12564
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012565 boolean looped = false;
12566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012567 do {
12568 if (mOrderedBroadcasts.size() == 0) {
12569 // No more broadcasts pending, so all done!
12570 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012571 if (looped) {
12572 // If we had finished the last ordered broadcast, then
12573 // make sure all processes have correct oom and sched
12574 // adjustments.
12575 updateOomAdjLocked();
12576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012577 return;
12578 }
12579 r = mOrderedBroadcasts.get(0);
12580 boolean forceReceive = false;
12581
12582 // Ensure that even if something goes awry with the timeout
12583 // detection, we catch "hung" broadcasts here, discard them,
12584 // and continue to make progress.
12585 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12586 long now = SystemClock.uptimeMillis();
12587 if (r.dispatchTime > 0) {
12588 if ((numReceivers > 0) &&
12589 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12590 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12591 + " now=" + now
12592 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012593 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012594 + " intent=" + r.intent
12595 + " numReceivers=" + numReceivers
12596 + " nextReceiver=" + r.nextReceiver
12597 + " state=" + r.state);
12598 broadcastTimeout(); // forcibly finish this broadcast
12599 forceReceive = true;
12600 r.state = BroadcastRecord.IDLE;
12601 }
12602 }
12603
12604 if (r.state != BroadcastRecord.IDLE) {
12605 if (DEBUG_BROADCAST) Log.d(TAG,
12606 "processNextBroadcast() called when not idle (state="
12607 + r.state + ")");
12608 return;
12609 }
12610
12611 if (r.receivers == null || r.nextReceiver >= numReceivers
12612 || r.resultAbort || forceReceive) {
12613 // No more receivers for this broadcast! Send the final
12614 // result if requested...
12615 if (r.resultTo != null) {
12616 try {
12617 if (DEBUG_BROADCAST) {
12618 int seq = r.intent.getIntExtra("seq", -1);
12619 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12620 + " seq=" + seq + " app=" + r.callerApp);
12621 }
12622 performReceive(r.callerApp, r.resultTo,
12623 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012624 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012625 } catch (RemoteException e) {
12626 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12627 }
12628 }
12629
12630 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12631 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12632
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012633 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12634 + r);
12635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012636 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012637 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012638 mOrderedBroadcasts.remove(0);
12639 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012640 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012641 continue;
12642 }
12643 } while (r == null);
12644
12645 // Get the next receiver...
12646 int recIdx = r.nextReceiver++;
12647
12648 // Keep track of when this receiver started, and make sure there
12649 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012650 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012651 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012652 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012653
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012654 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12655 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012656 if (DEBUG_BROADCAST) Log.v(TAG,
12657 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012658 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012659 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012660 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012661 }
12662
12663 Object nextReceiver = r.receivers.get(recIdx);
12664 if (nextReceiver instanceof BroadcastFilter) {
12665 // Simple case: this is a registered receiver who gets
12666 // a direct call.
12667 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12668 if (DEBUG_BROADCAST) Log.v(TAG,
12669 "Delivering serialized to registered "
12670 + filter + ": " + r);
12671 deliverToRegisteredReceiver(r, filter, r.ordered);
12672 if (r.receiver == null || !r.ordered) {
12673 // The receiver has already finished, so schedule to
12674 // process the next one.
12675 r.state = BroadcastRecord.IDLE;
12676 scheduleBroadcastsLocked();
12677 }
12678 return;
12679 }
12680
12681 // Hard case: need to instantiate the receiver, possibly
12682 // starting its application process to host it.
12683
12684 ResolveInfo info =
12685 (ResolveInfo)nextReceiver;
12686
12687 boolean skip = false;
12688 int perm = checkComponentPermission(info.activityInfo.permission,
12689 r.callingPid, r.callingUid,
12690 info.activityInfo.exported
12691 ? -1 : info.activityInfo.applicationInfo.uid);
12692 if (perm != PackageManager.PERMISSION_GRANTED) {
12693 Log.w(TAG, "Permission Denial: broadcasting "
12694 + r.intent.toString()
12695 + " from " + r.callerPackage + " (pid=" + r.callingPid
12696 + ", uid=" + r.callingUid + ")"
12697 + " requires " + info.activityInfo.permission
12698 + " due to receiver " + info.activityInfo.packageName
12699 + "/" + info.activityInfo.name);
12700 skip = true;
12701 }
12702 if (r.callingUid != Process.SYSTEM_UID &&
12703 r.requiredPermission != null) {
12704 try {
12705 perm = ActivityThread.getPackageManager().
12706 checkPermission(r.requiredPermission,
12707 info.activityInfo.applicationInfo.packageName);
12708 } catch (RemoteException e) {
12709 perm = PackageManager.PERMISSION_DENIED;
12710 }
12711 if (perm != PackageManager.PERMISSION_GRANTED) {
12712 Log.w(TAG, "Permission Denial: receiving "
12713 + r.intent + " to "
12714 + info.activityInfo.applicationInfo.packageName
12715 + " requires " + r.requiredPermission
12716 + " due to sender " + r.callerPackage
12717 + " (uid " + r.callingUid + ")");
12718 skip = true;
12719 }
12720 }
12721 if (r.curApp != null && r.curApp.crashing) {
12722 // If the target process is crashing, just skip it.
12723 skip = true;
12724 }
12725
12726 if (skip) {
12727 r.receiver = null;
12728 r.curFilter = null;
12729 r.state = BroadcastRecord.IDLE;
12730 scheduleBroadcastsLocked();
12731 return;
12732 }
12733
12734 r.state = BroadcastRecord.APP_RECEIVE;
12735 String targetProcess = info.activityInfo.processName;
12736 r.curComponent = new ComponentName(
12737 info.activityInfo.applicationInfo.packageName,
12738 info.activityInfo.name);
12739 r.curReceiver = info.activityInfo;
12740
12741 // Is this receiver's application already running?
12742 ProcessRecord app = getProcessRecordLocked(targetProcess,
12743 info.activityInfo.applicationInfo.uid);
12744 if (app != null && app.thread != null) {
12745 try {
12746 processCurBroadcastLocked(r, app);
12747 return;
12748 } catch (RemoteException e) {
12749 Log.w(TAG, "Exception when sending broadcast to "
12750 + r.curComponent, e);
12751 }
12752
12753 // If a dead object exception was thrown -- fall through to
12754 // restart the application.
12755 }
12756
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012757 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012758 if ((r.curApp=startProcessLocked(targetProcess,
12759 info.activityInfo.applicationInfo, true,
12760 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012761 "broadcast", r.curComponent,
12762 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12763 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012764 // Ah, this recipient is unavailable. Finish it if necessary,
12765 // and mark the broadcast record as ready for the next.
12766 Log.w(TAG, "Unable to launch app "
12767 + info.activityInfo.applicationInfo.packageName + "/"
12768 + info.activityInfo.applicationInfo.uid + " for broadcast "
12769 + r.intent + ": process is bad");
12770 logBroadcastReceiverDiscard(r);
12771 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12772 r.resultExtras, r.resultAbort, true);
12773 scheduleBroadcastsLocked();
12774 r.state = BroadcastRecord.IDLE;
12775 return;
12776 }
12777
12778 mPendingBroadcast = r;
12779 }
12780 }
12781
12782 // =========================================================
12783 // INSTRUMENTATION
12784 // =========================================================
12785
12786 public boolean startInstrumentation(ComponentName className,
12787 String profileFile, int flags, Bundle arguments,
12788 IInstrumentationWatcher watcher) {
12789 // Refuse possible leaked file descriptors
12790 if (arguments != null && arguments.hasFileDescriptors()) {
12791 throw new IllegalArgumentException("File descriptors passed in Bundle");
12792 }
12793
12794 synchronized(this) {
12795 InstrumentationInfo ii = null;
12796 ApplicationInfo ai = null;
12797 try {
12798 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012799 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012800 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012801 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012802 } catch (PackageManager.NameNotFoundException e) {
12803 }
12804 if (ii == null) {
12805 reportStartInstrumentationFailure(watcher, className,
12806 "Unable to find instrumentation info for: " + className);
12807 return false;
12808 }
12809 if (ai == null) {
12810 reportStartInstrumentationFailure(watcher, className,
12811 "Unable to find instrumentation target package: " + ii.targetPackage);
12812 return false;
12813 }
12814
12815 int match = mContext.getPackageManager().checkSignatures(
12816 ii.targetPackage, ii.packageName);
12817 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12818 String msg = "Permission Denial: starting instrumentation "
12819 + className + " from pid="
12820 + Binder.getCallingPid()
12821 + ", uid=" + Binder.getCallingPid()
12822 + " not allowed because package " + ii.packageName
12823 + " does not have a signature matching the target "
12824 + ii.targetPackage;
12825 reportStartInstrumentationFailure(watcher, className, msg);
12826 throw new SecurityException(msg);
12827 }
12828
12829 final long origId = Binder.clearCallingIdentity();
12830 uninstallPackageLocked(ii.targetPackage, -1, true);
12831 ProcessRecord app = addAppLocked(ai);
12832 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012833 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012834 app.instrumentationProfileFile = profileFile;
12835 app.instrumentationArguments = arguments;
12836 app.instrumentationWatcher = watcher;
12837 app.instrumentationResultClass = className;
12838 Binder.restoreCallingIdentity(origId);
12839 }
12840
12841 return true;
12842 }
12843
12844 /**
12845 * Report errors that occur while attempting to start Instrumentation. Always writes the
12846 * error to the logs, but if somebody is watching, send the report there too. This enables
12847 * the "am" command to report errors with more information.
12848 *
12849 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12850 * @param cn The component name of the instrumentation.
12851 * @param report The error report.
12852 */
12853 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12854 ComponentName cn, String report) {
12855 Log.w(TAG, report);
12856 try {
12857 if (watcher != null) {
12858 Bundle results = new Bundle();
12859 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12860 results.putString("Error", report);
12861 watcher.instrumentationStatus(cn, -1, results);
12862 }
12863 } catch (RemoteException e) {
12864 Log.w(TAG, e);
12865 }
12866 }
12867
12868 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12869 if (app.instrumentationWatcher != null) {
12870 try {
12871 // NOTE: IInstrumentationWatcher *must* be oneway here
12872 app.instrumentationWatcher.instrumentationFinished(
12873 app.instrumentationClass,
12874 resultCode,
12875 results);
12876 } catch (RemoteException e) {
12877 }
12878 }
12879 app.instrumentationWatcher = null;
12880 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012881 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012882 app.instrumentationProfileFile = null;
12883 app.instrumentationArguments = null;
12884
12885 uninstallPackageLocked(app.processName, -1, false);
12886 }
12887
12888 public void finishInstrumentation(IApplicationThread target,
12889 int resultCode, Bundle results) {
12890 // Refuse possible leaked file descriptors
12891 if (results != null && results.hasFileDescriptors()) {
12892 throw new IllegalArgumentException("File descriptors passed in Intent");
12893 }
12894
12895 synchronized(this) {
12896 ProcessRecord app = getRecordForAppLocked(target);
12897 if (app == null) {
12898 Log.w(TAG, "finishInstrumentation: no app for " + target);
12899 return;
12900 }
12901 final long origId = Binder.clearCallingIdentity();
12902 finishInstrumentationLocked(app, resultCode, results);
12903 Binder.restoreCallingIdentity(origId);
12904 }
12905 }
12906
12907 // =========================================================
12908 // CONFIGURATION
12909 // =========================================================
12910
12911 public ConfigurationInfo getDeviceConfigurationInfo() {
12912 ConfigurationInfo config = new ConfigurationInfo();
12913 synchronized (this) {
12914 config.reqTouchScreen = mConfiguration.touchscreen;
12915 config.reqKeyboardType = mConfiguration.keyboard;
12916 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012917 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12918 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012919 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12920 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012921 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12922 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012923 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12924 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012925 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012926 }
12927 return config;
12928 }
12929
12930 public Configuration getConfiguration() {
12931 Configuration ci;
12932 synchronized(this) {
12933 ci = new Configuration(mConfiguration);
12934 }
12935 return ci;
12936 }
12937
12938 public void updateConfiguration(Configuration values) {
12939 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12940 "updateConfiguration()");
12941
12942 synchronized(this) {
12943 if (values == null && mWindowManager != null) {
12944 // sentinel: fetch the current configuration from the window manager
12945 values = mWindowManager.computeNewConfiguration();
12946 }
12947
12948 final long origId = Binder.clearCallingIdentity();
12949 updateConfigurationLocked(values, null);
12950 Binder.restoreCallingIdentity(origId);
12951 }
12952 }
12953
12954 /**
12955 * Do either or both things: (1) change the current configuration, and (2)
12956 * make sure the given activity is running with the (now) current
12957 * configuration. Returns true if the activity has been left running, or
12958 * false if <var>starting</var> is being destroyed to match the new
12959 * configuration.
12960 */
12961 public boolean updateConfigurationLocked(Configuration values,
12962 HistoryRecord starting) {
12963 int changes = 0;
12964
12965 boolean kept = true;
12966
12967 if (values != null) {
12968 Configuration newConfig = new Configuration(mConfiguration);
12969 changes = newConfig.updateFrom(values);
12970 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012971 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012972 Log.i(TAG, "Updating configuration to: " + values);
12973 }
12974
Doug Zongker2bec3d42009-12-04 12:52:44 -080012975 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012976
12977 if (values.locale != null) {
12978 saveLocaleLocked(values.locale,
12979 !values.locale.equals(mConfiguration.locale),
12980 values.userSetLocale);
12981 }
12982
12983 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012984 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080012985
12986 AttributeCache ac = AttributeCache.instance();
12987 if (ac != null) {
12988 ac.updateConfiguration(mConfiguration);
12989 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012990
12991 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12992 msg.obj = new Configuration(mConfiguration);
12993 mHandler.sendMessage(msg);
12994
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012995 for (int i=mLruProcesses.size()-1; i>=0; i--) {
12996 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012997 try {
12998 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012999 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13000 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013001 app.thread.scheduleConfigurationChanged(mConfiguration);
13002 }
13003 } catch (Exception e) {
13004 }
13005 }
13006 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013007 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13008 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013009 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13010 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013011 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13012 broadcastIntentLocked(null, null,
13013 new Intent(Intent.ACTION_LOCALE_CHANGED),
13014 null, null, 0, null, null,
13015 null, false, false, MY_PID, Process.SYSTEM_UID);
13016 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013017 }
13018 }
13019
13020 if (changes != 0 && starting == null) {
13021 // If the configuration changed, and the caller is not already
13022 // in the process of starting an activity, then find the top
13023 // activity to check if its configuration needs to change.
13024 starting = topRunningActivityLocked(null);
13025 }
13026
13027 if (starting != null) {
13028 kept = ensureActivityConfigurationLocked(starting, changes);
13029 if (kept) {
13030 // If this didn't result in the starting activity being
13031 // destroyed, then we need to make sure at this point that all
13032 // other activities are made visible.
13033 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13034 + ", ensuring others are correct.");
13035 ensureActivitiesVisibleLocked(starting, changes);
13036 }
13037 }
13038
13039 return kept;
13040 }
13041
13042 private final boolean relaunchActivityLocked(HistoryRecord r,
13043 int changes, boolean andResume) {
13044 List<ResultInfo> results = null;
13045 List<Intent> newIntents = null;
13046 if (andResume) {
13047 results = r.results;
13048 newIntents = r.newIntents;
13049 }
13050 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13051 + " with results=" + results + " newIntents=" + newIntents
13052 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013053 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13054 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013055 r.task.taskId, r.shortComponentName);
13056
13057 r.startFreezingScreenLocked(r.app, 0);
13058
13059 try {
13060 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13061 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013062 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013063 // Note: don't need to call pauseIfSleepingLocked() here, because
13064 // the caller will only pass in 'andResume' if this activity is
13065 // currently resumed, which implies we aren't sleeping.
13066 } catch (RemoteException e) {
13067 return false;
13068 }
13069
13070 if (andResume) {
13071 r.results = null;
13072 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013073 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013074 }
13075
13076 return true;
13077 }
13078
13079 /**
13080 * Make sure the given activity matches the current configuration. Returns
13081 * false if the activity had to be destroyed. Returns true if the
13082 * configuration is the same, or the activity will remain running as-is
13083 * for whatever reason. Ensures the HistoryRecord is updated with the
13084 * correct configuration and all other bookkeeping is handled.
13085 */
13086 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13087 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013088 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13089 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013090
13091 // Short circuit: if the two configurations are the exact same
13092 // object (the common case), then there is nothing to do.
13093 Configuration newConfig = mConfiguration;
13094 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013095 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13096 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013097 return true;
13098 }
13099
13100 // We don't worry about activities that are finishing.
13101 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013102 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013103 "Configuration doesn't matter in finishing " + r);
13104 r.stopFreezingScreenLocked(false);
13105 return true;
13106 }
13107
13108 // Okay we now are going to make this activity have the new config.
13109 // But then we need to figure out how it needs to deal with that.
13110 Configuration oldConfig = r.configuration;
13111 r.configuration = newConfig;
13112
13113 // If the activity isn't currently running, just leave the new
13114 // configuration and it will pick that up next time it starts.
13115 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013116 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013117 "Configuration doesn't matter not running " + r);
13118 r.stopFreezingScreenLocked(false);
13119 return true;
13120 }
13121
13122 // If the activity isn't persistent, there is a chance we will
13123 // need to restart it.
13124 if (!r.persistent) {
13125
13126 // Figure out what has changed between the two configurations.
13127 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013128 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13129 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013130 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013131 + Integer.toHexString(r.info.configChanges)
13132 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013133 }
13134 if ((changes&(~r.info.configChanges)) != 0) {
13135 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13136 r.configChangeFlags |= changes;
13137 r.startFreezingScreenLocked(r.app, globalChanges);
13138 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013139 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13140 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013141 destroyActivityLocked(r, true);
13142 } else if (r.state == ActivityState.PAUSING) {
13143 // A little annoying: we are waiting for this activity to
13144 // finish pausing. Let's not do anything now, but just
13145 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013146 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13147 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013148 r.configDestroy = true;
13149 return true;
13150 } else if (r.state == ActivityState.RESUMED) {
13151 // Try to optimize this case: the configuration is changing
13152 // and we need to restart the top, resumed activity.
13153 // Instead of doing the normal handshaking, just say
13154 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013155 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13156 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013157 relaunchActivityLocked(r, r.configChangeFlags, true);
13158 r.configChangeFlags = 0;
13159 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013160 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13161 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013162 relaunchActivityLocked(r, r.configChangeFlags, false);
13163 r.configChangeFlags = 0;
13164 }
13165
13166 // All done... tell the caller we weren't able to keep this
13167 // activity around.
13168 return false;
13169 }
13170 }
13171
13172 // Default case: the activity can handle this new configuration, so
13173 // hand it over. Note that we don't need to give it the new
13174 // configuration, since we always send configuration changes to all
13175 // process when they happen so it can just use whatever configuration
13176 // it last got.
13177 if (r.app != null && r.app.thread != null) {
13178 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013179 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013180 r.app.thread.scheduleActivityConfigurationChanged(r);
13181 } catch (RemoteException e) {
13182 // If process died, whatever.
13183 }
13184 }
13185 r.stopFreezingScreenLocked(false);
13186
13187 return true;
13188 }
13189
13190 /**
13191 * Save the locale. You must be inside a synchronized (this) block.
13192 */
13193 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13194 if(isDiff) {
13195 SystemProperties.set("user.language", l.getLanguage());
13196 SystemProperties.set("user.region", l.getCountry());
13197 }
13198
13199 if(isPersist) {
13200 SystemProperties.set("persist.sys.language", l.getLanguage());
13201 SystemProperties.set("persist.sys.country", l.getCountry());
13202 SystemProperties.set("persist.sys.localevar", l.getVariant());
13203 }
13204 }
13205
13206 // =========================================================
13207 // LIFETIME MANAGEMENT
13208 // =========================================================
13209
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013210 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13211 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013212 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013213 // This adjustment has already been computed. If we are calling
13214 // from the top, we may have already computed our adjustment with
13215 // an earlier hidden adjustment that isn't really for us... if
13216 // so, use the new hidden adjustment.
13217 if (!recursed && app.hidden) {
13218 app.curAdj = hiddenAdj;
13219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013220 return app.curAdj;
13221 }
13222
13223 if (app.thread == null) {
13224 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013225 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013226 return (app.curAdj=EMPTY_APP_ADJ);
13227 }
13228
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013229 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13230 // The max adjustment doesn't allow this app to be anything
13231 // below foreground, so it is not worth doing work for it.
13232 app.adjType = "fixed";
13233 app.adjSeq = mAdjSeq;
13234 app.curRawAdj = app.maxAdj;
13235 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13236 return (app.curAdj=app.maxAdj);
13237 }
13238
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013239 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013240 app.adjSource = null;
13241 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013242 app.empty = false;
13243 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013244
The Android Open Source Project4df24232009-03-05 14:34:35 -080013245 // Determine the importance of the process, starting with most
13246 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013247 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013248 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013249 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013250 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013251 // The last app on the list is the foreground app.
13252 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013253 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013254 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013255 } else if (app.instrumentationClass != null) {
13256 // Don't want to kill running instrumentation.
13257 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013258 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013259 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013260 } else if (app.persistentActivities > 0) {
13261 // Special persistent activities... shouldn't be used these days.
13262 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013263 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013264 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013265 } else if (app.curReceiver != null ||
13266 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13267 // An app that is currently receiving a broadcast also
13268 // counts as being in the foreground.
13269 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013270 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013271 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013272 } else if (app.executingServices.size() > 0) {
13273 // An app that is currently executing a service callback also
13274 // counts as being in the foreground.
13275 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013276 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013277 app.adjType = "exec-service";
13278 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013279 // The user is aware of this app, so make it visible.
13280 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013281 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013282 app.adjType = "foreground-service";
13283 } else if (app.forcingToForeground != null) {
13284 // The user is aware of this app, so make it visible.
13285 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013286 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013287 app.adjType = "force-foreground";
13288 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013289 } else if (app == mHomeProcess) {
13290 // This process is hosting what we currently consider to be the
13291 // home app, so we don't want to let it go into the background.
13292 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013293 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013294 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013295 } else if ((N=app.activities.size()) != 0) {
13296 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013297 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013298 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013299 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013300 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013301 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013302 for (int j=0; j<N; j++) {
13303 if (((HistoryRecord)app.activities.get(j)).visible) {
13304 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013305 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013306 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013307 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013308 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013309 break;
13310 }
13311 }
13312 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013313 // A very not-needed process. If this is lower in the lru list,
13314 // we will push it in to the empty bucket.
13315 app.hidden = true;
13316 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013317 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013318 adj = hiddenAdj;
13319 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013320 }
13321
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013322 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13323
The Android Open Source Project4df24232009-03-05 14:34:35 -080013324 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013325 // there are applications dependent on our services or providers, but
13326 // this gives us a baseline and makes sure we don't get into an
13327 // infinite recursion.
13328 app.adjSeq = mAdjSeq;
13329 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013330
Christopher Tate6fa95972009-06-05 18:43:55 -070013331 if (mBackupTarget != null && app == mBackupTarget.app) {
13332 // If possible we want to avoid killing apps while they're being backed up
13333 if (adj > BACKUP_APP_ADJ) {
13334 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13335 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013336 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013337 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013338 }
13339 }
13340
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013341 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13342 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013343 final long now = SystemClock.uptimeMillis();
13344 // This process is more important if the top activity is
13345 // bound to the service.
13346 Iterator jt = app.services.iterator();
13347 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13348 ServiceRecord s = (ServiceRecord)jt.next();
13349 if (s.startRequested) {
13350 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13351 // This service has seen some activity within
13352 // recent memory, so we will keep its process ahead
13353 // of the background processes.
13354 if (adj > SECONDARY_SERVER_ADJ) {
13355 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013356 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013357 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013358 }
13359 }
13360 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013361 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13362 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013363 Iterator<ConnectionRecord> kt
13364 = s.connections.values().iterator();
13365 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13366 // XXX should compute this based on the max of
13367 // all connected clients.
13368 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013369 if (cr.binding.client == app) {
13370 // Binding to ourself is not interesting.
13371 continue;
13372 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013373 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13374 ProcessRecord client = cr.binding.client;
13375 int myHiddenAdj = hiddenAdj;
13376 if (myHiddenAdj > client.hiddenAdj) {
13377 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13378 myHiddenAdj = client.hiddenAdj;
13379 } else {
13380 myHiddenAdj = VISIBLE_APP_ADJ;
13381 }
13382 }
13383 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013384 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013385 if (adj > clientAdj) {
13386 adj = clientAdj > VISIBLE_APP_ADJ
13387 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013388 if (!client.hidden) {
13389 app.hidden = false;
13390 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013391 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013392 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13393 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013394 app.adjSource = cr.binding.client;
13395 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013396 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013397 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13398 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13399 schedGroup = Process.THREAD_GROUP_DEFAULT;
13400 }
13401 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013402 }
13403 HistoryRecord a = cr.activity;
13404 //if (a != null) {
13405 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13406 //}
13407 if (a != null && adj > FOREGROUND_APP_ADJ &&
13408 (a.state == ActivityState.RESUMED
13409 || a.state == ActivityState.PAUSING)) {
13410 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013411 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013412 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013413 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013414 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13415 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013416 app.adjSource = a;
13417 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013418 }
13419 }
13420 }
13421 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013422
13423 // Finally, f this process has active services running in it, we
13424 // would like to avoid killing it unless it would prevent the current
13425 // application from running. By default we put the process in
13426 // with the rest of the background processes; as we scan through
13427 // its services we may bump it up from there.
13428 if (adj > hiddenAdj) {
13429 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013430 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013431 app.adjType = "bg-services";
13432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013433 }
13434
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013435 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13436 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013437 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013438 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13439 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013440 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13441 if (cpr.clients.size() != 0) {
13442 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13443 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13444 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013445 if (client == app) {
13446 // Being our own client is not interesting.
13447 continue;
13448 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013449 int myHiddenAdj = hiddenAdj;
13450 if (myHiddenAdj > client.hiddenAdj) {
13451 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13452 myHiddenAdj = client.hiddenAdj;
13453 } else {
13454 myHiddenAdj = FOREGROUND_APP_ADJ;
13455 }
13456 }
13457 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013458 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013459 if (adj > clientAdj) {
13460 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013461 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013462 if (!client.hidden) {
13463 app.hidden = false;
13464 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013465 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013466 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13467 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013468 app.adjSource = client;
13469 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013470 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013471 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13472 schedGroup = Process.THREAD_GROUP_DEFAULT;
13473 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013474 }
13475 }
13476 // If the provider has external (non-framework) process
13477 // dependencies, ensure that its adjustment is at least
13478 // FOREGROUND_APP_ADJ.
13479 if (cpr.externals != 0) {
13480 if (adj > FOREGROUND_APP_ADJ) {
13481 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013482 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013483 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013484 app.adjType = "provider";
13485 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013486 }
13487 }
13488 }
13489 }
13490
13491 app.curRawAdj = adj;
13492
13493 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13494 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13495 if (adj > app.maxAdj) {
13496 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013497 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13498 schedGroup = Process.THREAD_GROUP_DEFAULT;
13499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013500 }
13501
13502 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013503 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013505 return adj;
13506 }
13507
13508 /**
13509 * Ask a given process to GC right now.
13510 */
13511 final void performAppGcLocked(ProcessRecord app) {
13512 try {
13513 app.lastRequestedGc = SystemClock.uptimeMillis();
13514 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013515 if (app.reportLowMemory) {
13516 app.reportLowMemory = false;
13517 app.thread.scheduleLowMemory();
13518 } else {
13519 app.thread.processInBackground();
13520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013521 }
13522 } catch (Exception e) {
13523 // whatever.
13524 }
13525 }
13526
13527 /**
13528 * Returns true if things are idle enough to perform GCs.
13529 */
13530 private final boolean canGcNow() {
13531 return mParallelBroadcasts.size() == 0
13532 && mOrderedBroadcasts.size() == 0
13533 && (mSleeping || (mResumedActivity != null &&
13534 mResumedActivity.idle));
13535 }
13536
13537 /**
13538 * Perform GCs on all processes that are waiting for it, but only
13539 * if things are idle.
13540 */
13541 final void performAppGcsLocked() {
13542 final int N = mProcessesToGc.size();
13543 if (N <= 0) {
13544 return;
13545 }
13546 if (canGcNow()) {
13547 while (mProcessesToGc.size() > 0) {
13548 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013549 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13550 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13551 <= SystemClock.uptimeMillis()) {
13552 // To avoid spamming the system, we will GC processes one
13553 // at a time, waiting a few seconds between each.
13554 performAppGcLocked(proc);
13555 scheduleAppGcsLocked();
13556 return;
13557 } else {
13558 // It hasn't been long enough since we last GCed this
13559 // process... put it in the list to wait for its time.
13560 addProcessToGcListLocked(proc);
13561 break;
13562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013563 }
13564 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013565
13566 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013567 }
13568 }
13569
13570 /**
13571 * If all looks good, perform GCs on all processes waiting for them.
13572 */
13573 final void performAppGcsIfAppropriateLocked() {
13574 if (canGcNow()) {
13575 performAppGcsLocked();
13576 return;
13577 }
13578 // Still not idle, wait some more.
13579 scheduleAppGcsLocked();
13580 }
13581
13582 /**
13583 * Schedule the execution of all pending app GCs.
13584 */
13585 final void scheduleAppGcsLocked() {
13586 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013587
13588 if (mProcessesToGc.size() > 0) {
13589 // Schedule a GC for the time to the next process.
13590 ProcessRecord proc = mProcessesToGc.get(0);
13591 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13592
13593 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13594 long now = SystemClock.uptimeMillis();
13595 if (when < (now+GC_TIMEOUT)) {
13596 when = now + GC_TIMEOUT;
13597 }
13598 mHandler.sendMessageAtTime(msg, when);
13599 }
13600 }
13601
13602 /**
13603 * Add a process to the array of processes waiting to be GCed. Keeps the
13604 * list in sorted order by the last GC time. The process can't already be
13605 * on the list.
13606 */
13607 final void addProcessToGcListLocked(ProcessRecord proc) {
13608 boolean added = false;
13609 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13610 if (mProcessesToGc.get(i).lastRequestedGc <
13611 proc.lastRequestedGc) {
13612 added = true;
13613 mProcessesToGc.add(i+1, proc);
13614 break;
13615 }
13616 }
13617 if (!added) {
13618 mProcessesToGc.add(0, proc);
13619 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013620 }
13621
13622 /**
13623 * Set up to ask a process to GC itself. This will either do it
13624 * immediately, or put it on the list of processes to gc the next
13625 * time things are idle.
13626 */
13627 final void scheduleAppGcLocked(ProcessRecord app) {
13628 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013629 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013630 return;
13631 }
13632 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013633 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013634 scheduleAppGcsLocked();
13635 }
13636 }
13637
13638 private final boolean updateOomAdjLocked(
13639 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13640 app.hiddenAdj = hiddenAdj;
13641
13642 if (app.thread == null) {
13643 return true;
13644 }
13645
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013646 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013647
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013648 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013649 if (app.curRawAdj != app.setRawAdj) {
13650 if (app.curRawAdj > FOREGROUND_APP_ADJ
13651 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13652 // If this app is transitioning from foreground to
13653 // non-foreground, have it do a gc.
13654 scheduleAppGcLocked(app);
13655 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13656 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13657 // Likewise do a gc when an app is moving in to the
13658 // background (such as a service stopping).
13659 scheduleAppGcLocked(app);
13660 }
13661 app.setRawAdj = app.curRawAdj;
13662 }
13663 if (adj != app.setAdj) {
13664 if (Process.setOomAdj(app.pid, adj)) {
13665 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13666 TAG, "Set app " + app.processName +
13667 " oom adj to " + adj);
13668 app.setAdj = adj;
13669 } else {
13670 return false;
13671 }
13672 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013673 if (app.setSchedGroup != app.curSchedGroup) {
13674 app.setSchedGroup = app.curSchedGroup;
13675 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13676 "Setting process group of " + app.processName
13677 + " to " + app.curSchedGroup);
13678 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013679 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013680 try {
13681 Process.setProcessGroup(app.pid, app.curSchedGroup);
13682 } catch (Exception e) {
13683 Log.w(TAG, "Failed setting process group of " + app.pid
13684 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013685 e.printStackTrace();
13686 } finally {
13687 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013688 }
13689 }
13690 if (false) {
13691 if (app.thread != null) {
13692 try {
13693 app.thread.setSchedulingGroup(app.curSchedGroup);
13694 } catch (RemoteException e) {
13695 }
13696 }
13697 }
13698 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013699 }
13700
13701 return true;
13702 }
13703
13704 private final HistoryRecord resumedAppLocked() {
13705 HistoryRecord resumedActivity = mResumedActivity;
13706 if (resumedActivity == null || resumedActivity.app == null) {
13707 resumedActivity = mPausingActivity;
13708 if (resumedActivity == null || resumedActivity.app == null) {
13709 resumedActivity = topRunningActivityLocked(null);
13710 }
13711 }
13712 return resumedActivity;
13713 }
13714
13715 private final boolean updateOomAdjLocked(ProcessRecord app) {
13716 final HistoryRecord TOP_ACT = resumedAppLocked();
13717 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13718 int curAdj = app.curAdj;
13719 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13720 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13721
13722 mAdjSeq++;
13723
13724 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13725 if (res) {
13726 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13727 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13728 if (nowHidden != wasHidden) {
13729 // Changed to/from hidden state, so apps after it in the LRU
13730 // list may also be changed.
13731 updateOomAdjLocked();
13732 }
13733 }
13734 return res;
13735 }
13736
13737 private final boolean updateOomAdjLocked() {
13738 boolean didOomAdj = true;
13739 final HistoryRecord TOP_ACT = resumedAppLocked();
13740 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13741
13742 if (false) {
13743 RuntimeException e = new RuntimeException();
13744 e.fillInStackTrace();
13745 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13746 }
13747
13748 mAdjSeq++;
13749
13750 // First try updating the OOM adjustment for each of the
13751 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013752 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013753 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13754 while (i > 0) {
13755 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013756 ProcessRecord app = mLruProcesses.get(i);
13757 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013758 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013759 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013760 && app.curAdj == curHiddenAdj) {
13761 curHiddenAdj++;
13762 }
13763 } else {
13764 didOomAdj = false;
13765 }
13766 }
13767
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013768 // If we return false, we will fall back on killing processes to
13769 // have a fixed limit. Do this if a limit has been requested; else
13770 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013771 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13772 }
13773
13774 private final void trimApplications() {
13775 synchronized (this) {
13776 int i;
13777
13778 // First remove any unused application processes whose package
13779 // has been removed.
13780 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13781 final ProcessRecord app = mRemovedProcesses.get(i);
13782 if (app.activities.size() == 0
13783 && app.curReceiver == null && app.services.size() == 0) {
13784 Log.i(
13785 TAG, "Exiting empty application process "
13786 + app.processName + " ("
13787 + (app.thread != null ? app.thread.asBinder() : null)
13788 + ")\n");
13789 if (app.pid > 0 && app.pid != MY_PID) {
13790 Process.killProcess(app.pid);
13791 } else {
13792 try {
13793 app.thread.scheduleExit();
13794 } catch (Exception e) {
13795 // Ignore exceptions.
13796 }
13797 }
13798 cleanUpApplicationRecordLocked(app, false, -1);
13799 mRemovedProcesses.remove(i);
13800
13801 if (app.persistent) {
13802 if (app.persistent) {
13803 addAppLocked(app.info);
13804 }
13805 }
13806 }
13807 }
13808
13809 // Now try updating the OOM adjustment for each of the
13810 // application processes based on their current state.
13811 // If the setOomAdj() API is not supported, then go with our
13812 // back-up plan...
13813 if (!updateOomAdjLocked()) {
13814
13815 // Count how many processes are running services.
13816 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013817 for (i=mLruProcesses.size()-1; i>=0; i--) {
13818 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013819
13820 if (app.persistent || app.services.size() != 0
13821 || app.curReceiver != null
13822 || app.persistentActivities > 0) {
13823 // Don't count processes holding services against our
13824 // maximum process count.
13825 if (localLOGV) Log.v(
13826 TAG, "Not trimming app " + app + " with services: "
13827 + app.services);
13828 numServiceProcs++;
13829 }
13830 }
13831
13832 int curMaxProcs = mProcessLimit;
13833 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13834 if (mAlwaysFinishActivities) {
13835 curMaxProcs = 1;
13836 }
13837 curMaxProcs += numServiceProcs;
13838
13839 // Quit as many processes as we can to get down to the desired
13840 // process count. First remove any processes that no longer
13841 // have activites running in them.
13842 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013843 i<mLruProcesses.size()
13844 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013845 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013846 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013847 // Quit an application only if it is not currently
13848 // running any activities.
13849 if (!app.persistent && app.activities.size() == 0
13850 && app.curReceiver == null && app.services.size() == 0) {
13851 Log.i(
13852 TAG, "Exiting empty application process "
13853 + app.processName + " ("
13854 + (app.thread != null ? app.thread.asBinder() : null)
13855 + ")\n");
13856 if (app.pid > 0 && app.pid != MY_PID) {
13857 Process.killProcess(app.pid);
13858 } else {
13859 try {
13860 app.thread.scheduleExit();
13861 } catch (Exception e) {
13862 // Ignore exceptions.
13863 }
13864 }
13865 // todo: For now we assume the application is not buggy
13866 // or evil, and will quit as a result of our request.
13867 // Eventually we need to drive this off of the death
13868 // notification, and kill the process if it takes too long.
13869 cleanUpApplicationRecordLocked(app, false, i);
13870 i--;
13871 }
13872 }
13873
13874 // If we still have too many processes, now from the least
13875 // recently used process we start finishing activities.
13876 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013877 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013878 " of " + curMaxProcs + " processes");
13879 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013880 i<mLruProcesses.size()
13881 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013882 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013883 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013884 // Quit the application only if we have a state saved for
13885 // all of its activities.
13886 boolean canQuit = !app.persistent && app.curReceiver == null
13887 && app.services.size() == 0
13888 && app.persistentActivities == 0;
13889 int NUMA = app.activities.size();
13890 int j;
13891 if (Config.LOGV) Log.v(
13892 TAG, "Looking to quit " + app.processName);
13893 for (j=0; j<NUMA && canQuit; j++) {
13894 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13895 if (Config.LOGV) Log.v(
13896 TAG, " " + r.intent.getComponent().flattenToShortString()
13897 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13898 canQuit = (r.haveState || !r.stateNotNeeded)
13899 && !r.visible && r.stopped;
13900 }
13901 if (canQuit) {
13902 // Finish all of the activities, and then the app itself.
13903 for (j=0; j<NUMA; j++) {
13904 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13905 if (!r.finishing) {
13906 destroyActivityLocked(r, false);
13907 }
13908 r.resultTo = null;
13909 }
13910 Log.i(TAG, "Exiting application process "
13911 + app.processName + " ("
13912 + (app.thread != null ? app.thread.asBinder() : null)
13913 + ")\n");
13914 if (app.pid > 0 && app.pid != MY_PID) {
13915 Process.killProcess(app.pid);
13916 } else {
13917 try {
13918 app.thread.scheduleExit();
13919 } catch (Exception e) {
13920 // Ignore exceptions.
13921 }
13922 }
13923 // todo: For now we assume the application is not buggy
13924 // or evil, and will quit as a result of our request.
13925 // Eventually we need to drive this off of the death
13926 // notification, and kill the process if it takes too long.
13927 cleanUpApplicationRecordLocked(app, false, i);
13928 i--;
13929 //dump();
13930 }
13931 }
13932
13933 }
13934
13935 int curMaxActivities = MAX_ACTIVITIES;
13936 if (mAlwaysFinishActivities) {
13937 curMaxActivities = 1;
13938 }
13939
13940 // Finally, if there are too many activities now running, try to
13941 // finish as many as we can to get back down to the limit.
13942 for ( i=0;
13943 i<mLRUActivities.size()
13944 && mLRUActivities.size() > curMaxActivities;
13945 i++) {
13946 final HistoryRecord r
13947 = (HistoryRecord)mLRUActivities.get(i);
13948
13949 // We can finish this one if we have its icicle saved and
13950 // it is not persistent.
13951 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13952 && r.stopped && !r.persistent && !r.finishing) {
13953 final int origSize = mLRUActivities.size();
13954 destroyActivityLocked(r, true);
13955
13956 // This will remove it from the LRU list, so keep
13957 // our index at the same value. Note that this check to
13958 // see if the size changes is just paranoia -- if
13959 // something unexpected happens, we don't want to end up
13960 // in an infinite loop.
13961 if (origSize > mLRUActivities.size()) {
13962 i--;
13963 }
13964 }
13965 }
13966 }
13967 }
13968
13969 /** This method sends the specified signal to each of the persistent apps */
13970 public void signalPersistentProcesses(int sig) throws RemoteException {
13971 if (sig != Process.SIGNAL_USR1) {
13972 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13973 }
13974
13975 synchronized (this) {
13976 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13977 != PackageManager.PERMISSION_GRANTED) {
13978 throw new SecurityException("Requires permission "
13979 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13980 }
13981
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013982 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
13983 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013984 if (r.thread != null && r.persistent) {
13985 Process.sendSignal(r.pid, sig);
13986 }
13987 }
13988 }
13989 }
13990
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013991 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013992 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013993
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013994 try {
13995 synchronized (this) {
13996 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13997 // its own permission.
13998 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13999 != PackageManager.PERMISSION_GRANTED) {
14000 throw new SecurityException("Requires permission "
14001 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014002 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014003
14004 if (start && fd == null) {
14005 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014006 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014007
14008 ProcessRecord proc = null;
14009 try {
14010 int pid = Integer.parseInt(process);
14011 synchronized (mPidsSelfLocked) {
14012 proc = mPidsSelfLocked.get(pid);
14013 }
14014 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014015 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014016
14017 if (proc == null) {
14018 HashMap<String, SparseArray<ProcessRecord>> all
14019 = mProcessNames.getMap();
14020 SparseArray<ProcessRecord> procs = all.get(process);
14021 if (procs != null && procs.size() > 0) {
14022 proc = procs.valueAt(0);
14023 }
14024 }
14025
14026 if (proc == null || proc.thread == null) {
14027 throw new IllegalArgumentException("Unknown process: " + process);
14028 }
14029
14030 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14031 if (isSecure) {
14032 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14033 throw new SecurityException("Process not debuggable: " + proc);
14034 }
14035 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014036
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014037 proc.thread.profilerControl(start, path, fd);
14038 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014039 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014040 }
14041 } catch (RemoteException e) {
14042 throw new IllegalStateException("Process disappeared");
14043 } finally {
14044 if (fd != null) {
14045 try {
14046 fd.close();
14047 } catch (IOException e) {
14048 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014049 }
14050 }
14051 }
14052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014053 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14054 public void monitor() {
14055 synchronized (this) { }
14056 }
14057}