blob: 7b647043204450cca6e84b1009a3106be10ccf2e [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;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080050import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.content.ComponentName;
52import android.content.ContentResolver;
53import android.content.Context;
54import android.content.Intent;
55import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070056import android.content.IIntentReceiver;
57import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070058import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.content.pm.ActivityInfo;
60import android.content.pm.ApplicationInfo;
61import android.content.pm.ConfigurationInfo;
62import android.content.pm.IPackageDataObserver;
63import android.content.pm.IPackageManager;
64import android.content.pm.InstrumentationInfo;
Dan Egnor66c40e72010-01-26 16:23:11 -080065import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070067import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import android.content.pm.ProviderInfo;
69import android.content.pm.ResolveInfo;
70import android.content.pm.ServiceInfo;
71import android.content.res.Configuration;
72import android.graphics.Bitmap;
73import android.net.Uri;
74import android.os.Binder;
Dan Egnor60d87622009-12-16 16:32:58 -080075import android.os.Build;
Dan Egnor42471dd2010-01-07 17:25:22 -080076import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070077import android.os.Debug;
Dan Egnor60d87622009-12-16 16:32:58 -080078import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import android.os.Environment;
Dan Egnor42471dd2010-01-07 17:25:22 -080080import android.os.FileObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.FileUtils;
82import android.os.Handler;
83import android.os.IBinder;
84import android.os.IPermissionController;
85import android.os.Looper;
86import android.os.Message;
87import android.os.Parcel;
88import android.os.ParcelFileDescriptor;
89import android.os.PowerManager;
90import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070091import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.os.RemoteException;
93import android.os.ServiceManager;
94import android.os.SystemClock;
95import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.util.Config;
98import android.util.EventLog;
99import android.util.Log;
100import android.util.PrintWriterPrinter;
101import android.util.SparseArray;
102import android.view.Gravity;
103import android.view.LayoutInflater;
104import android.view.View;
105import android.view.WindowManager;
106import android.view.WindowManagerPolicy;
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.File;
109import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import 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;
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -0800138 static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700140 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700141 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700142 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 static final boolean VALIDATE_TOKENS = false;
144 static final boolean SHOW_ACTIVITY_START_TIME = true;
145
146 // Control over CPU and battery monitoring.
147 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
148 static final boolean MONITOR_CPU_USAGE = true;
149 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
150 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
151 static final boolean MONITOR_THREAD_CPU_USAGE = false;
152
Dianne Hackborn1655be42009-05-08 14:29:01 -0700153 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700154 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 private static final String SYSTEM_SECURE = "ro.secure";
157
158 // This is the maximum number of application processes we would like
159 // to have running. Due to the asynchronous nature of things, we can
160 // temporarily go beyond this limit.
161 static final int MAX_PROCESSES = 2;
162
163 // Set to false to leave processes running indefinitely, relying on
164 // the kernel killing them as resources are required.
165 static final boolean ENFORCE_PROCESS_LIMIT = false;
166
167 // This is the maximum number of activities that we would like to have
168 // running at a given time.
169 static final int MAX_ACTIVITIES = 20;
170
171 // Maximum number of recent tasks that we can remember.
172 static final int MAX_RECENT_TASKS = 20;
173
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700174 // Amount of time after a call to stopAppSwitches() during which we will
175 // prevent further untrusted switches from happening.
176 static final long APP_SWITCH_DELAY_TIME = 5*1000;
177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 // How long until we reset a task when the user returns to it. Currently
179 // 30 minutes.
180 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
181
182 // Set to true to disable the icon that is shown while a new activity
183 // is being started.
184 static final boolean SHOW_APP_STARTING_ICON = true;
185
186 // How long we wait until giving up on the last activity to pause. This
187 // is short because it directly impacts the responsiveness of starting the
188 // next activity.
189 static final int PAUSE_TIMEOUT = 500;
190
191 /**
192 * How long we can hold the launch wake lock before giving up.
193 */
194 static final int LAUNCH_TIMEOUT = 10*1000;
195
196 // How long we wait for a launched process to attach to the activity manager
197 // before we decide it's never going to come up for real.
198 static final int PROC_START_TIMEOUT = 10*1000;
199
200 // How long we wait until giving up on the last activity telling us it
201 // is idle.
202 static final int IDLE_TIMEOUT = 10*1000;
203
204 // How long to wait after going idle before forcing apps to GC.
205 static final int GC_TIMEOUT = 5*1000;
206
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700207 // The minimum amount of time between successive GC requests for a process.
208 static final int GC_MIN_INTERVAL = 60*1000;
209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 // How long we wait until giving up on an activity telling us it has
211 // finished destroying itself.
212 static final int DESTROY_TIMEOUT = 10*1000;
213
214 // How long we allow a receiver to run before giving up on it.
215 static final int BROADCAST_TIMEOUT = 10*1000;
216
217 // How long we wait for a service to finish executing.
218 static final int SERVICE_TIMEOUT = 20*1000;
219
220 // How long a service needs to be running until restarting its process
221 // is no longer considered to be a relaunch of the service.
222 static final int SERVICE_RESTART_DURATION = 5*1000;
223
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700224 // How long a service needs to be running until it will start back at
225 // SERVICE_RESTART_DURATION after being killed.
226 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
227
228 // Multiplying factor to increase restart duration time by, for each time
229 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
230 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
231
232 // The minimum amount of time between restarting services that we allow.
233 // That is, when multiple services are restarting, we won't allow each
234 // to restart less than this amount of time from the last one.
235 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 // Maximum amount of time for there to be no activity on a service before
238 // we consider it non-essential and allow its process to go on the
239 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700240 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
242 // How long we wait until we timeout on key dispatching.
243 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
244
245 // The minimum time we allow between crashes, for us to consider this
246 // application to be bad and stop and its services and reject broadcasts.
247 static final int MIN_CRASH_INTERVAL = 60*1000;
248
249 // How long we wait until we timeout on key dispatching during instrumentation.
250 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
251
252 // OOM adjustments for processes in various states:
253
254 // This is a process without anything currently running in it. Definitely
255 // the first to go! Value set in system/rootdir/init.rc on startup.
256 // This value is initalized in the constructor, careful when refering to
257 // this static variable externally.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800258 static final int EMPTY_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
260 // This is a process only hosting activities that are not visible,
261 // so it can be killed without any disruption. Value set in
262 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800263 static final int HIDDEN_APP_MAX_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 static int HIDDEN_APP_MIN_ADJ;
265
The Android Open Source Project4df24232009-03-05 14:34:35 -0800266 // This is a process holding the home application -- we want to try
267 // avoiding killing it, even if it would normally be in the background,
268 // because the user interacts with it so much.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800269 static final int HOME_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800270
Christopher Tate6fa95972009-06-05 18:43:55 -0700271 // This is a process currently hosting a backup operation. Killing it
272 // is not entirely fatal but is generally a bad idea.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800273 static final int BACKUP_APP_ADJ;
Christopher Tate6fa95972009-06-05 18:43:55 -0700274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 // This is a process holding a secondary server -- killing it will not
276 // have much of an impact as far as the user is concerned. Value set in
277 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800278 static final int SECONDARY_SERVER_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 // This is a process only hosting activities that are visible to the
281 // user, so we'd prefer they don't disappear. Value set in
282 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800283 static final int VISIBLE_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284
285 // This is the process running the current foreground app. We'd really
286 // rather not kill it! Value set in system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800287 static final int FOREGROUND_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288
289 // This is a process running a core server, such as telephony. Definitely
290 // don't want to kill it, but doing so is not completely fatal.
291 static final int CORE_SERVER_ADJ = -12;
292
293 // The system process runs at the default adjustment.
294 static final int SYSTEM_ADJ = -16;
295
296 // Memory pages are 4K.
297 static final int PAGE_SIZE = 4*1024;
298
299 // Corresponding memory levels for above adjustments.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800300 static final int EMPTY_APP_MEM;
301 static final int HIDDEN_APP_MEM;
302 static final int HOME_APP_MEM;
303 static final int BACKUP_APP_MEM;
304 static final int SECONDARY_SERVER_MEM;
305 static final int VISIBLE_APP_MEM;
306 static final int FOREGROUND_APP_MEM;
307
308 // The minimum number of hidden apps we want to be able to keep around,
309 // without empty apps being able to push them out of memory.
310 static final int MIN_HIDDEN_APPS = 2;
311
312 // We put empty content processes after any hidden processes that have
313 // been idle for less than 30 seconds.
314 static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
315
316 // We put empty content processes after any hidden processes that have
317 // been idle for less than 60 seconds.
318 static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
319
320 static {
321 // These values are set in system/rootdir/init.rc on startup.
322 FOREGROUND_APP_ADJ =
323 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
324 VISIBLE_APP_ADJ =
325 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
326 SECONDARY_SERVER_ADJ =
327 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
328 BACKUP_APP_ADJ =
329 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
330 HOME_APP_ADJ =
331 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
332 HIDDEN_APP_MIN_ADJ =
333 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
334 EMPTY_APP_ADJ =
335 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
336 HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
337 FOREGROUND_APP_MEM =
338 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
339 VISIBLE_APP_MEM =
340 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
341 SECONDARY_SERVER_MEM =
342 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
343 BACKUP_APP_MEM =
344 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
345 HOME_APP_MEM =
346 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
347 HIDDEN_APP_MEM =
348 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
349 EMPTY_APP_MEM =
350 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
351 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352
Dan Egnor42471dd2010-01-07 17:25:22 -0800353 static final int MY_PID = Process.myPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354
355 static final String[] EMPTY_STRING_ARRAY = new String[0];
356
357 enum ActivityState {
358 INITIALIZING,
359 RESUMED,
360 PAUSING,
361 PAUSED,
362 STOPPING,
363 STOPPED,
364 FINISHING,
365 DESTROYING,
366 DESTROYED
367 }
368
369 /**
370 * The back history of all previous (and possibly still
371 * running) activities. It contains HistoryRecord objects.
372 */
373 final ArrayList mHistory = new ArrayList();
374
375 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700376 * Description of a request to start a new activity, which has been held
377 * due to app switches being disabled.
378 */
379 class PendingActivityLaunch {
380 HistoryRecord r;
381 HistoryRecord sourceRecord;
382 Uri[] grantedUriPermissions;
383 int grantedMode;
384 boolean onlyIfNeeded;
385 }
386
387 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
388 = new ArrayList<PendingActivityLaunch>();
389
390 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 * List of all active broadcasts that are to be executed immediately
392 * (without waiting for another broadcast to finish). Currently this only
393 * contains broadcasts to registered receivers, to avoid spinning up
394 * a bunch of processes to execute IntentReceiver components.
395 */
396 final ArrayList<BroadcastRecord> mParallelBroadcasts
397 = new ArrayList<BroadcastRecord>();
398
399 /**
400 * List of all active broadcasts that are to be executed one at a time.
401 * The object at the top of the list is the currently activity broadcasts;
402 * those after it are waiting for the top to finish..
403 */
404 final ArrayList<BroadcastRecord> mOrderedBroadcasts
405 = new ArrayList<BroadcastRecord>();
406
407 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800408 * Historical data of past broadcasts, for debugging.
409 */
410 static final int MAX_BROADCAST_HISTORY = 100;
411 final BroadcastRecord[] mBroadcastHistory
412 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
413
414 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 * Set when we current have a BROADCAST_INTENT_MSG in flight.
416 */
417 boolean mBroadcastsScheduled = false;
418
419 /**
420 * Set to indicate whether to issue an onUserLeaving callback when a
421 * newly launched activity is being brought in front of us.
422 */
423 boolean mUserLeaving = false;
424
425 /**
426 * When we are in the process of pausing an activity, before starting the
427 * next one, this variable holds the activity that is currently being paused.
428 */
429 HistoryRecord mPausingActivity = null;
430
431 /**
432 * Current activity that is resumed, or null if there is none.
433 */
434 HistoryRecord mResumedActivity = null;
435
436 /**
437 * Activity we have told the window manager to have key focus.
438 */
439 HistoryRecord mFocusedActivity = null;
440
441 /**
442 * This is the last activity that we put into the paused state. This is
443 * used to determine if we need to do an activity transition while sleeping,
444 * when we normally hold the top activity paused.
445 */
446 HistoryRecord mLastPausedActivity = null;
447
448 /**
449 * List of activities that are waiting for a new activity
450 * to become visible before completing whatever operation they are
451 * supposed to do.
452 */
453 final ArrayList mWaitingVisibleActivities = new ArrayList();
454
455 /**
456 * List of activities that are ready to be stopped, but waiting
457 * for the next activity to settle down before doing so. It contains
458 * HistoryRecord objects.
459 */
460 final ArrayList<HistoryRecord> mStoppingActivities
461 = new ArrayList<HistoryRecord>();
462
463 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700464 * Animations that for the current transition have requested not to
465 * be considered for the transition animation.
466 */
467 final ArrayList<HistoryRecord> mNoAnimActivities
468 = new ArrayList<HistoryRecord>();
469
470 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 * List of intents that were used to start the most recent tasks.
472 */
473 final ArrayList<TaskRecord> mRecentTasks
474 = new ArrayList<TaskRecord>();
475
476 /**
477 * List of activities that are ready to be finished, but waiting
478 * for the previous activity to settle down before doing so. It contains
479 * HistoryRecord objects.
480 */
481 final ArrayList mFinishingActivities = new ArrayList();
482
483 /**
484 * All of the applications we currently have running organized by name.
485 * The keys are strings of the application package name (as
486 * returned by the package manager), and the keys are ApplicationRecord
487 * objects.
488 */
489 final ProcessMap<ProcessRecord> mProcessNames
490 = new ProcessMap<ProcessRecord>();
491
492 /**
493 * The last time that various processes have crashed.
494 */
495 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
496
497 /**
498 * Set of applications that we consider to be bad, and will reject
499 * incoming broadcasts from (which the user has no control over).
500 * Processes are added to this set when they have crashed twice within
501 * a minimum amount of time; they are removed from it when they are
502 * later restarted (hopefully due to some user action). The value is the
503 * time it was added to the list.
504 */
505 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
506
507 /**
508 * All of the processes we currently have running organized by pid.
509 * The keys are the pid running the application.
510 *
511 * <p>NOTE: This object is protected by its own lock, NOT the global
512 * activity manager lock!
513 */
514 final SparseArray<ProcessRecord> mPidsSelfLocked
515 = new SparseArray<ProcessRecord>();
516
517 /**
518 * All of the processes that have been forced to be foreground. The key
519 * is the pid of the caller who requested it (we hold a death
520 * link on it).
521 */
522 abstract class ForegroundToken implements IBinder.DeathRecipient {
523 int pid;
524 IBinder token;
525 }
526 final SparseArray<ForegroundToken> mForegroundProcesses
527 = new SparseArray<ForegroundToken>();
528
529 /**
530 * List of records for processes that someone had tried to start before the
531 * system was ready. We don't start them at that point, but ensure they
532 * are started by the time booting is complete.
533 */
534 final ArrayList<ProcessRecord> mProcessesOnHold
535 = new ArrayList<ProcessRecord>();
536
537 /**
538 * List of records for processes that we have started and are waiting
539 * for them to call back. This is really only needed when running in
540 * single processes mode, in which case we do not have a unique pid for
541 * each process.
542 */
543 final ArrayList<ProcessRecord> mStartingProcesses
544 = new ArrayList<ProcessRecord>();
545
546 /**
547 * List of persistent applications that are in the process
548 * of being started.
549 */
550 final ArrayList<ProcessRecord> mPersistentStartingProcesses
551 = new ArrayList<ProcessRecord>();
552
553 /**
554 * Processes that are being forcibly torn down.
555 */
556 final ArrayList<ProcessRecord> mRemovedProcesses
557 = new ArrayList<ProcessRecord>();
558
559 /**
560 * List of running applications, sorted by recent usage.
561 * The first entry in the list is the least recently used.
562 * It contains ApplicationRecord objects. This list does NOT include
563 * any persistent application records (since we never want to exit them).
564 */
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800565 final ArrayList<ProcessRecord> mLruProcesses
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 = new ArrayList<ProcessRecord>();
567
568 /**
569 * List of processes that should gc as soon as things are idle.
570 */
571 final ArrayList<ProcessRecord> mProcessesToGc
572 = new ArrayList<ProcessRecord>();
573
574 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800575 * This is the process holding what we currently consider to be
576 * the "home" activity.
577 */
578 private ProcessRecord mHomeProcess;
579
580 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 * List of running activities, sorted by recent usage.
582 * The first entry in the list is the least recently used.
583 * It contains HistoryRecord objects.
584 */
585 private final ArrayList mLRUActivities = new ArrayList();
586
587 /**
588 * Set of PendingResultRecord objects that are currently active.
589 */
590 final HashSet mPendingResultRecords = new HashSet();
591
592 /**
593 * Set of IntentSenderRecord objects that are currently active.
594 */
595 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
596 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
597
598 /**
599 * Intent broadcast that we have tried to start, but are
600 * waiting for its application's process to be created. We only
601 * need one (instead of a list) because we always process broadcasts
602 * one at a time, so no others can be started while waiting for this
603 * one.
604 */
605 BroadcastRecord mPendingBroadcast = null;
606
607 /**
608 * Keeps track of all IIntentReceivers that have been registered for
609 * broadcasts. Hash keys are the receiver IBinder, hash value is
610 * a ReceiverList.
611 */
612 final HashMap mRegisteredReceivers = new HashMap();
613
614 /**
615 * Resolver for broadcast intents to registered receivers.
616 * Holds BroadcastFilter (subclass of IntentFilter).
617 */
618 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
619 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
620 @Override
621 protected boolean allowFilterResult(
622 BroadcastFilter filter, List<BroadcastFilter> dest) {
623 IBinder target = filter.receiverList.receiver.asBinder();
624 for (int i=dest.size()-1; i>=0; i--) {
625 if (dest.get(i).receiverList.receiver.asBinder() == target) {
626 return false;
627 }
628 }
629 return true;
630 }
631 };
632
633 /**
634 * State of all active sticky broadcasts. Keys are the action of the
635 * sticky Intent, values are an ArrayList of all broadcasted intents with
636 * that action (which should usually be one).
637 */
638 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
639 new HashMap<String, ArrayList<Intent>>();
640
641 /**
642 * All currently running services.
643 */
644 final HashMap<ComponentName, ServiceRecord> mServices =
645 new HashMap<ComponentName, ServiceRecord>();
646
647 /**
648 * All currently running services indexed by the Intent used to start them.
649 */
650 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
651 new HashMap<Intent.FilterComparison, ServiceRecord>();
652
653 /**
654 * All currently bound service connections. Keys are the IBinder of
655 * the client's IServiceConnection.
656 */
657 final HashMap<IBinder, ConnectionRecord> mServiceConnections
658 = new HashMap<IBinder, ConnectionRecord>();
659
660 /**
661 * List of services that we have been asked to start,
662 * but haven't yet been able to. It is used to hold start requests
663 * while waiting for their corresponding application thread to get
664 * going.
665 */
666 final ArrayList<ServiceRecord> mPendingServices
667 = new ArrayList<ServiceRecord>();
668
669 /**
670 * List of services that are scheduled to restart following a crash.
671 */
672 final ArrayList<ServiceRecord> mRestartingServices
673 = new ArrayList<ServiceRecord>();
674
675 /**
676 * List of services that are in the process of being stopped.
677 */
678 final ArrayList<ServiceRecord> mStoppingServices
679 = new ArrayList<ServiceRecord>();
680
681 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700682 * Backup/restore process management
683 */
684 String mBackupAppName = null;
685 BackupRecord mBackupTarget = null;
686
687 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 * List of PendingThumbnailsRecord objects of clients who are still
689 * waiting to receive all of the thumbnails for a task.
690 */
691 final ArrayList mPendingThumbnails = new ArrayList();
692
693 /**
694 * List of HistoryRecord objects that have been finished and must
695 * still report back to a pending thumbnail receiver.
696 */
697 final ArrayList mCancelledThumbnails = new ArrayList();
698
699 /**
700 * All of the currently running global content providers. Keys are a
701 * string containing the provider name and values are a
702 * ContentProviderRecord object containing the data about it. Note
703 * that a single provider may be published under multiple names, so
704 * there may be multiple entries here for a single one in mProvidersByClass.
705 */
706 final HashMap mProvidersByName = new HashMap();
707
708 /**
709 * All of the currently running global content providers. Keys are a
710 * string containing the provider's implementation class and values are a
711 * ContentProviderRecord object containing the data about it.
712 */
713 final HashMap mProvidersByClass = new HashMap();
714
715 /**
716 * List of content providers who have clients waiting for them. The
717 * application is currently being launched and the provider will be
718 * removed from this list once it is published.
719 */
720 final ArrayList mLaunchingProviders = new ArrayList();
721
722 /**
723 * Global set of specific Uri permissions that have been granted.
724 */
725 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
726 = new SparseArray<HashMap<Uri, UriPermission>>();
727
728 /**
729 * Thread-local storage used to carry caller permissions over through
730 * indirect content-provider access.
731 * @see #ActivityManagerService.openContentUri()
732 */
733 private class Identity {
734 public int pid;
735 public int uid;
736
737 Identity(int _pid, int _uid) {
738 pid = _pid;
739 uid = _uid;
740 }
741 }
742 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
743
744 /**
745 * All information we have collected about the runtime performance of
746 * any user id that can impact battery performance.
747 */
748 final BatteryStatsService mBatteryStatsService;
749
750 /**
751 * information about component usage
752 */
753 final UsageStatsService mUsageStatsService;
754
755 /**
756 * Current configuration information. HistoryRecord objects are given
757 * a reference to this object to indicate which configuration they are
758 * currently running in, so this object must be kept immutable.
759 */
760 Configuration mConfiguration = new Configuration();
761
762 /**
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800763 * Current sequencing integer of the configuration, for skipping old
764 * configurations.
765 */
766 int mConfigurationSeq = 0;
767
768 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700769 * Hardware-reported OpenGLES version.
770 */
771 final int GL_ES_VERSION;
772
773 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 * List of initialization arguments to pass to all processes when binding applications to them.
775 * For example, references to the commonly used services.
776 */
777 HashMap<String, IBinder> mAppBindArgs;
778
779 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700780 * Temporary to avoid allocations. Protected by main lock.
781 */
782 final StringBuilder mStringBuilder = new StringBuilder(256);
783
784 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 * Used to control how we initialize the service.
786 */
787 boolean mStartRunning = false;
788 ComponentName mTopComponent;
789 String mTopAction;
790 String mTopData;
791 boolean mSystemReady = false;
792 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700793 boolean mWaitingUpdate = false;
794 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795
796 Context mContext;
797
798 int mFactoryTest;
799
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700800 boolean mCheckedForSetup;
801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700803 * The time at which we will allow normal application switches again,
804 * after a call to {@link #stopAppSwitches()}.
805 */
806 long mAppSwitchesAllowedTime;
807
808 /**
809 * This is set to true after the first switch after mAppSwitchesAllowedTime
810 * is set; any switches after that will clear the time.
811 */
812 boolean mDidAppSwitch;
813
814 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 * Set while we are wanting to sleep, to prevent any
816 * activities from being started/resumed.
817 */
818 boolean mSleeping = false;
819
820 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700821 * Set if we are shutting down the system, similar to sleeping.
822 */
823 boolean mShuttingDown = false;
824
825 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 * Set when the system is going to sleep, until we have
827 * successfully paused the current activity and released our wake lock.
828 * At that point the system is allowed to actually sleep.
829 */
830 PowerManager.WakeLock mGoingToSleep;
831
832 /**
833 * We don't want to allow the device to go to sleep while in the process
834 * of launching an activity. This is primarily to allow alarm intent
835 * receivers to launch an activity and get that to run before the device
836 * goes back to sleep.
837 */
838 PowerManager.WakeLock mLaunchingActivity;
839
840 /**
841 * Task identifier that activities are currently being started
842 * in. Incremented each time a new task is created.
843 * todo: Replace this with a TokenSpace class that generates non-repeating
844 * integers that won't wrap.
845 */
846 int mCurTask = 1;
847
848 /**
849 * Current sequence id for oom_adj computation traversal.
850 */
851 int mAdjSeq = 0;
852
853 /**
854 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
855 * is set, indicating the user wants processes started in such a way
856 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
857 * running in each process (thus no pre-initialized process, etc).
858 */
859 boolean mSimpleProcessManagement = false;
860
861 /**
862 * System monitoring: number of processes that died since the last
863 * N procs were started.
864 */
865 int[] mProcDeaths = new int[20];
866
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700867 /**
868 * This is set if we had to do a delayed dexopt of an app before launching
869 * it, to increasing the ANR timeouts in that case.
870 */
871 boolean mDidDexOpt;
872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 String mDebugApp = null;
874 boolean mWaitForDebugger = false;
875 boolean mDebugTransient = false;
876 String mOrigDebugApp = null;
877 boolean mOrigWaitForDebugger = false;
878 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700879 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700881 final RemoteCallbackList<IActivityWatcher> mWatchers
882 = new RemoteCallbackList<IActivityWatcher>();
883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 /**
885 * Callback of last caller to {@link #requestPss}.
886 */
887 Runnable mRequestPssCallback;
888
889 /**
890 * Remaining processes for which we are waiting results from the last
891 * call to {@link #requestPss}.
892 */
893 final ArrayList<ProcessRecord> mRequestPssList
894 = new ArrayList<ProcessRecord>();
895
896 /**
897 * Runtime statistics collection thread. This object's lock is used to
898 * protect all related state.
899 */
900 final Thread mProcessStatsThread;
901
902 /**
903 * Used to collect process stats when showing not responding dialog.
904 * Protected by mProcessStatsThread.
905 */
906 final ProcessStats mProcessStats = new ProcessStats(
907 MONITOR_THREAD_CPU_USAGE);
908 long mLastCpuTime = 0;
909 long mLastWriteTime = 0;
910
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700911 long mInitialStartTime = 0;
912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 /**
914 * Set to true after the system has finished booting.
915 */
916 boolean mBooted = false;
917
918 int mProcessLimit = 0;
919
920 WindowManagerService mWindowManager;
921
922 static ActivityManagerService mSelf;
923 static ActivityThread mSystemThread;
924
925 private final class AppDeathRecipient implements IBinder.DeathRecipient {
926 final ProcessRecord mApp;
927 final int mPid;
928 final IApplicationThread mAppThread;
929
930 AppDeathRecipient(ProcessRecord app, int pid,
931 IApplicationThread thread) {
932 if (localLOGV) Log.v(
933 TAG, "New death recipient " + this
934 + " for thread " + thread.asBinder());
935 mApp = app;
936 mPid = pid;
937 mAppThread = thread;
938 }
939
940 public void binderDied() {
941 if (localLOGV) Log.v(
942 TAG, "Death received in " + this
943 + " for thread " + mAppThread.asBinder());
944 removeRequestedPss(mApp);
945 synchronized(ActivityManagerService.this) {
946 appDiedLocked(mApp, mPid, mAppThread);
947 }
948 }
949 }
950
951 static final int SHOW_ERROR_MSG = 1;
952 static final int SHOW_NOT_RESPONDING_MSG = 2;
953 static final int SHOW_FACTORY_ERROR_MSG = 3;
954 static final int UPDATE_CONFIGURATION_MSG = 4;
955 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
956 static final int WAIT_FOR_DEBUGGER_MSG = 6;
957 static final int BROADCAST_INTENT_MSG = 7;
958 static final int BROADCAST_TIMEOUT_MSG = 8;
959 static final int PAUSE_TIMEOUT_MSG = 9;
960 static final int IDLE_TIMEOUT_MSG = 10;
961 static final int IDLE_NOW_MSG = 11;
962 static final int SERVICE_TIMEOUT_MSG = 12;
963 static final int UPDATE_TIME_ZONE = 13;
964 static final int SHOW_UID_ERROR_MSG = 14;
965 static final int IM_FEELING_LUCKY_MSG = 15;
966 static final int LAUNCH_TIMEOUT_MSG = 16;
967 static final int DESTROY_TIMEOUT_MSG = 17;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 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;
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -0800972 static final int FINALIZE_PENDING_INTENT_MSG = 23;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973
974 AlertDialog mUidAlert;
975
976 final Handler mHandler = new Handler() {
977 //public Handler() {
978 // if (localLOGV) Log.v(TAG, "Handler started!");
979 //}
980
981 public void handleMessage(Message msg) {
982 switch (msg.what) {
983 case SHOW_ERROR_MSG: {
984 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 synchronized (ActivityManagerService.this) {
986 ProcessRecord proc = (ProcessRecord)data.get("app");
987 if (proc != null && proc.crashDialog != null) {
988 Log.e(TAG, "App already has crash dialog: " + proc);
989 return;
990 }
991 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700992 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -0800993 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 d.show();
995 proc.crashDialog = d;
996 } else {
997 // The device is asleep, so just pretend that the user
998 // saw a crash dialog and hit "force quit".
999 res.set(0);
1000 }
1001 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001002
1003 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 } break;
1005 case SHOW_NOT_RESPONDING_MSG: {
1006 synchronized (ActivityManagerService.this) {
1007 HashMap data = (HashMap) msg.obj;
1008 ProcessRecord proc = (ProcessRecord)data.get("app");
1009 if (proc != null && proc.anrDialog != null) {
1010 Log.e(TAG, "App already has anr dialog: " + proc);
1011 return;
1012 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001013
1014 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1015 null, null, 0, null, null, null,
1016 false, false, MY_PID, Process.SYSTEM_UID);
1017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1019 mContext, proc, (HistoryRecord)data.get("activity"));
1020 d.show();
1021 proc.anrDialog = d;
1022 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001023
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001024 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 } break;
1026 case SHOW_FACTORY_ERROR_MSG: {
1027 Dialog d = new FactoryErrorDialog(
1028 mContext, msg.getData().getCharSequence("msg"));
1029 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001030 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 } break;
1032 case UPDATE_CONFIGURATION_MSG: {
1033 final ContentResolver resolver = mContext.getContentResolver();
1034 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1035 } break;
1036 case GC_BACKGROUND_PROCESSES_MSG: {
1037 synchronized (ActivityManagerService.this) {
1038 performAppGcsIfAppropriateLocked();
1039 }
1040 } break;
1041 case WAIT_FOR_DEBUGGER_MSG: {
1042 synchronized (ActivityManagerService.this) {
1043 ProcessRecord app = (ProcessRecord)msg.obj;
1044 if (msg.arg1 != 0) {
1045 if (!app.waitedForDebugger) {
1046 Dialog d = new AppWaitingForDebuggerDialog(
1047 ActivityManagerService.this,
1048 mContext, app);
1049 app.waitDialog = d;
1050 app.waitedForDebugger = true;
1051 d.show();
1052 }
1053 } else {
1054 if (app.waitDialog != null) {
1055 app.waitDialog.dismiss();
1056 app.waitDialog = null;
1057 }
1058 }
1059 }
1060 } break;
1061 case BROADCAST_INTENT_MSG: {
1062 if (DEBUG_BROADCAST) Log.v(
1063 TAG, "Received BROADCAST_INTENT_MSG");
1064 processNextBroadcast(true);
1065 } break;
1066 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001067 if (mDidDexOpt) {
1068 mDidDexOpt = false;
1069 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1070 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1071 return;
1072 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 broadcastTimeout();
1074 } break;
1075 case PAUSE_TIMEOUT_MSG: {
1076 IBinder token = (IBinder)msg.obj;
1077 // We don't at this point know if the activity is fullscreen,
1078 // so we need to be conservative and assume it isn't.
1079 Log.w(TAG, "Activity pause timeout for " + token);
1080 activityPaused(token, null, true);
1081 } break;
1082 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001083 if (mDidDexOpt) {
1084 mDidDexOpt = false;
1085 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1086 nmsg.obj = msg.obj;
1087 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1088 return;
1089 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 // We don't at this point know if the activity is fullscreen,
1091 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001092 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001094 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 } break;
1096 case DESTROY_TIMEOUT_MSG: {
1097 IBinder token = (IBinder)msg.obj;
1098 // We don't at this point know if the activity is fullscreen,
1099 // so we need to be conservative and assume it isn't.
1100 Log.w(TAG, "Activity destroy timeout for " + token);
1101 activityDestroyed(token);
1102 } break;
1103 case IDLE_NOW_MSG: {
1104 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001105 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 } break;
1107 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001108 if (mDidDexOpt) {
1109 mDidDexOpt = false;
1110 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1111 nmsg.obj = msg.obj;
1112 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1113 return;
1114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 serviceTimeout((ProcessRecord)msg.obj);
1116 } break;
1117 case UPDATE_TIME_ZONE: {
1118 synchronized (ActivityManagerService.this) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001119 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
1120 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 if (r.thread != null) {
1122 try {
1123 r.thread.updateTimeZone();
1124 } catch (RemoteException ex) {
1125 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1126 }
1127 }
1128 }
1129 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001130 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 case SHOW_UID_ERROR_MSG: {
1132 // XXX This is a temporary dialog, no need to localize.
1133 AlertDialog d = new BaseErrorDialog(mContext);
1134 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1135 d.setCancelable(false);
1136 d.setTitle("System UIDs Inconsistent");
1137 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1138 d.setButton("I'm Feeling Lucky",
1139 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1140 mUidAlert = d;
1141 d.show();
1142 } break;
1143 case IM_FEELING_LUCKY_MSG: {
1144 if (mUidAlert != null) {
1145 mUidAlert.dismiss();
1146 mUidAlert = null;
1147 }
1148 } break;
1149 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001150 if (mDidDexOpt) {
1151 mDidDexOpt = false;
1152 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1153 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1154 return;
1155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 synchronized (ActivityManagerService.this) {
1157 if (mLaunchingActivity.isHeld()) {
1158 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1159 mLaunchingActivity.release();
1160 }
1161 }
1162 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 case RESUME_TOP_ACTIVITY_MSG: {
1164 synchronized (ActivityManagerService.this) {
1165 resumeTopActivityLocked(null);
1166 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001167 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001169 if (mDidDexOpt) {
1170 mDidDexOpt = false;
1171 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1172 nmsg.obj = msg.obj;
1173 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1174 return;
1175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 ProcessRecord app = (ProcessRecord)msg.obj;
1177 synchronized (ActivityManagerService.this) {
1178 processStartTimedOutLocked(app);
1179 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001180 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001181 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1182 synchronized (ActivityManagerService.this) {
1183 doPendingActivityLaunchesLocked(true);
1184 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001185 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001186 case KILL_APPLICATION_MSG: {
1187 synchronized (ActivityManagerService.this) {
1188 int uid = msg.arg1;
1189 boolean restart = (msg.arg2 == 1);
1190 String pkg = (String) msg.obj;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001191 forceStopPackageLocked(pkg, uid, restart, false, true);
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001192 }
1193 } break;
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08001194 case FINALIZE_PENDING_INTENT_MSG: {
1195 ((PendingIntentRecord)msg.obj).completeFinalize();
1196 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 }
1198 }
1199 };
1200
1201 public static void setSystemProcess() {
1202 try {
1203 ActivityManagerService m = mSelf;
1204
1205 ServiceManager.addService("activity", m);
1206 ServiceManager.addService("meminfo", new MemBinder(m));
1207 if (MONITOR_CPU_USAGE) {
1208 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1209 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 ServiceManager.addService("permission", new PermissionController(m));
1211
1212 ApplicationInfo info =
1213 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001214 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001215 mSystemThread.installSystemApplicationInfo(info);
1216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 synchronized (mSelf) {
1218 ProcessRecord app = mSelf.newProcessRecordLocked(
1219 mSystemThread.getApplicationThread(), info,
1220 info.processName);
1221 app.persistent = true;
Dan Egnor42471dd2010-01-07 17:25:22 -08001222 app.pid = MY_PID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 app.maxAdj = SYSTEM_ADJ;
1224 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1225 synchronized (mSelf.mPidsSelfLocked) {
1226 mSelf.mPidsSelfLocked.put(app.pid, app);
1227 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001228 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 }
1230 } catch (PackageManager.NameNotFoundException e) {
1231 throw new RuntimeException(
1232 "Unable to find android system package", e);
1233 }
1234 }
1235
1236 public void setWindowManager(WindowManagerService wm) {
1237 mWindowManager = wm;
1238 }
1239
1240 public static final Context main(int factoryTest) {
1241 AThread thr = new AThread();
1242 thr.start();
1243
1244 synchronized (thr) {
1245 while (thr.mService == null) {
1246 try {
1247 thr.wait();
1248 } catch (InterruptedException e) {
1249 }
1250 }
1251 }
1252
1253 ActivityManagerService m = thr.mService;
1254 mSelf = m;
1255 ActivityThread at = ActivityThread.systemMain();
1256 mSystemThread = at;
1257 Context context = at.getSystemContext();
1258 m.mContext = context;
1259 m.mFactoryTest = factoryTest;
1260 PowerManager pm =
1261 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1262 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1263 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1264 m.mLaunchingActivity.setReferenceCounted(false);
1265
1266 m.mBatteryStatsService.publish(context);
1267 m.mUsageStatsService.publish(context);
1268
1269 synchronized (thr) {
1270 thr.mReady = true;
1271 thr.notifyAll();
1272 }
1273
1274 m.startRunning(null, null, null, null);
1275
1276 return context;
1277 }
1278
1279 public static ActivityManagerService self() {
1280 return mSelf;
1281 }
1282
1283 static class AThread extends Thread {
1284 ActivityManagerService mService;
1285 boolean mReady = false;
1286
1287 public AThread() {
1288 super("ActivityManager");
1289 }
1290
1291 public void run() {
1292 Looper.prepare();
1293
1294 android.os.Process.setThreadPriority(
1295 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1296
1297 ActivityManagerService m = new ActivityManagerService();
1298
1299 synchronized (this) {
1300 mService = m;
1301 notifyAll();
1302 }
1303
1304 synchronized (this) {
1305 while (!mReady) {
1306 try {
1307 wait();
1308 } catch (InterruptedException e) {
1309 }
1310 }
1311 }
1312
1313 Looper.loop();
1314 }
1315 }
1316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 static class MemBinder extends Binder {
1318 ActivityManagerService mActivityManagerService;
1319 MemBinder(ActivityManagerService activityManagerService) {
1320 mActivityManagerService = activityManagerService;
1321 }
1322
1323 @Override
1324 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1325 ActivityManagerService service = mActivityManagerService;
1326 ArrayList<ProcessRecord> procs;
1327 synchronized (mActivityManagerService) {
1328 if (args != null && args.length > 0
1329 && args[0].charAt(0) != '-') {
1330 procs = new ArrayList<ProcessRecord>();
1331 int pid = -1;
1332 try {
1333 pid = Integer.parseInt(args[0]);
1334 } catch (NumberFormatException e) {
1335
1336 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001337 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1338 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 if (proc.pid == pid) {
1340 procs.add(proc);
1341 } else if (proc.processName.equals(args[0])) {
1342 procs.add(proc);
1343 }
1344 }
1345 if (procs.size() <= 0) {
1346 pw.println("No process found for: " + args[0]);
1347 return;
1348 }
1349 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001350 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 }
1352 }
1353 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1354 }
1355 }
1356
1357 static class CpuBinder extends Binder {
1358 ActivityManagerService mActivityManagerService;
1359 CpuBinder(ActivityManagerService activityManagerService) {
1360 mActivityManagerService = activityManagerService;
1361 }
1362
1363 @Override
1364 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1365 synchronized (mActivityManagerService.mProcessStatsThread) {
1366 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1367 }
1368 }
1369 }
1370
1371 private ActivityManagerService() {
1372 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1373 if (v != null && Integer.getInteger(v) != 0) {
1374 mSimpleProcessManagement = true;
1375 }
1376 v = System.getenv("ANDROID_DEBUG_APP");
1377 if (v != null) {
1378 mSimpleProcessManagement = true;
1379 }
1380
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001381 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 File dataDir = Environment.getDataDirectory();
1384 File systemDir = new File(dataDir, "system");
1385 systemDir.mkdirs();
1386 mBatteryStatsService = new BatteryStatsService(new File(
1387 systemDir, "batterystats.bin").toString());
1388 mBatteryStatsService.getActiveStatistics().readLocked();
1389 mBatteryStatsService.getActiveStatistics().writeLocked();
1390
1391 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001392 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393
Jack Palevichb90d28c2009-07-22 15:35:24 -07001394 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1395 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1396
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001397 mConfiguration.setToDefaults();
1398 mConfiguration.locale = Locale.getDefault();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 mProcessStats.init();
1400
1401 // Add ourself to the Watchdog monitors.
1402 Watchdog.getInstance().addMonitor(this);
1403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 mProcessStatsThread = new Thread("ProcessStats") {
1405 public void run() {
1406 while (true) {
1407 try {
1408 try {
1409 synchronized(this) {
1410 final long now = SystemClock.uptimeMillis();
1411 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1412 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1413 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1414 // + ", write delay=" + nextWriteDelay);
1415 if (nextWriteDelay < nextCpuDelay) {
1416 nextCpuDelay = nextWriteDelay;
1417 }
1418 if (nextCpuDelay > 0) {
1419 this.wait(nextCpuDelay);
1420 }
1421 }
1422 } catch (InterruptedException e) {
1423 }
1424
1425 updateCpuStatsNow();
1426 } catch (Exception e) {
1427 Log.e(TAG, "Unexpected exception collecting process stats", e);
1428 }
1429 }
1430 }
1431 };
1432 mProcessStatsThread.start();
1433 }
1434
1435 @Override
1436 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1437 throws RemoteException {
1438 try {
1439 return super.onTransact(code, data, reply, flags);
1440 } catch (RuntimeException e) {
1441 // The activity manager only throws security exceptions, so let's
1442 // log all others.
1443 if (!(e instanceof SecurityException)) {
1444 Log.e(TAG, "Activity Manager Crash", e);
1445 }
1446 throw e;
1447 }
1448 }
1449
1450 void updateCpuStats() {
1451 synchronized (mProcessStatsThread) {
1452 final long now = SystemClock.uptimeMillis();
1453 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1454 mProcessStatsThread.notify();
1455 }
1456 }
1457 }
1458
1459 void updateCpuStatsNow() {
1460 synchronized (mProcessStatsThread) {
1461 final long now = SystemClock.uptimeMillis();
1462 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 if (MONITOR_CPU_USAGE &&
1465 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1466 mLastCpuTime = now;
1467 haveNewCpuStats = true;
1468 mProcessStats.update();
1469 //Log.i(TAG, mProcessStats.printCurrentState());
1470 //Log.i(TAG, "Total CPU usage: "
1471 // + mProcessStats.getTotalCpuPercent() + "%");
1472
1473 // Log the cpu usage if the property is set.
1474 if ("true".equals(SystemProperties.get("events.cpu"))) {
1475 int user = mProcessStats.getLastUserTime();
1476 int system = mProcessStats.getLastSystemTime();
1477 int iowait = mProcessStats.getLastIoWaitTime();
1478 int irq = mProcessStats.getLastIrqTime();
1479 int softIrq = mProcessStats.getLastSoftIrqTime();
1480 int idle = mProcessStats.getLastIdleTime();
1481
1482 int total = user + system + iowait + irq + softIrq + idle;
1483 if (total == 0) total = 1;
1484
Doug Zongker2bec3d42009-12-04 12:52:44 -08001485 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 ((user+system+iowait+irq+softIrq) * 100) / total,
1487 (user * 100) / total,
1488 (system * 100) / total,
1489 (iowait * 100) / total,
1490 (irq * 100) / total,
1491 (softIrq * 100) / total);
1492 }
1493 }
1494
Amith Yamasanie43530a2009-08-21 13:11:37 -07001495 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001496 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001497 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 synchronized(mPidsSelfLocked) {
1499 if (haveNewCpuStats) {
1500 if (mBatteryStatsService.isOnBattery()) {
1501 final int N = mProcessStats.countWorkingStats();
1502 for (int i=0; i<N; i++) {
1503 ProcessStats.Stats st
1504 = mProcessStats.getWorkingStats(i);
1505 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1506 if (pr != null) {
1507 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1508 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001509 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001510 } else {
1511 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001512 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001513 if (ps != null) {
1514 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001515 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001516 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 }
1518 }
1519 }
1520 }
1521 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1524 mLastWriteTime = now;
1525 mBatteryStatsService.getActiveStatistics().writeLocked();
1526 }
1527 }
1528 }
1529 }
1530
1531 /**
1532 * Initialize the application bind args. These are passed to each
1533 * process when the bindApplication() IPC is sent to the process. They're
1534 * lazily setup to make sure the services are running when they're asked for.
1535 */
1536 private HashMap<String, IBinder> getCommonServicesLocked() {
1537 if (mAppBindArgs == null) {
1538 mAppBindArgs = new HashMap<String, IBinder>();
1539
1540 // Setup the application init args
1541 mAppBindArgs.put("package", ServiceManager.getService("package"));
1542 mAppBindArgs.put("window", ServiceManager.getService("window"));
1543 mAppBindArgs.put(Context.ALARM_SERVICE,
1544 ServiceManager.getService(Context.ALARM_SERVICE));
1545 }
1546 return mAppBindArgs;
1547 }
1548
1549 private final void setFocusedActivityLocked(HistoryRecord r) {
1550 if (mFocusedActivity != r) {
1551 mFocusedActivity = r;
1552 mWindowManager.setFocusedApp(r, true);
1553 }
1554 }
1555
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001556 private final void updateLruProcessLocked(ProcessRecord app,
1557 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001559 int lrui = mLruProcesses.indexOf(app);
1560 if (lrui >= 0) mLruProcesses.remove(lrui);
1561
1562 int i = mLruProcesses.size()-1;
1563 int skipTop = 0;
1564
1565 // compute the new weight for this process.
1566 if (updateActivityTime) {
1567 app.lastActivityTime = SystemClock.uptimeMillis();
1568 }
1569 if (app.activities.size() > 0) {
1570 // If this process has activities, we more strongly want to keep
1571 // it around.
1572 app.lruWeight = app.lastActivityTime;
1573 } else if (app.pubProviders.size() > 0) {
1574 // If this process contains content providers, we want to keep
1575 // it a little more strongly.
1576 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1577 // Also don't let it kick out the first few "real" hidden processes.
1578 skipTop = MIN_HIDDEN_APPS;
1579 } else {
1580 // If this process doesn't have activities, we less strongly
1581 // want to keep it around, and generally want to avoid getting
1582 // in front of any very recently used activities.
1583 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1584 // Also don't let it kick out the first few "real" hidden processes.
1585 skipTop = MIN_HIDDEN_APPS;
1586 }
1587 while (i >= 0) {
1588 ProcessRecord p = mLruProcesses.get(i);
1589 // If this app shouldn't be in front of the first N background
1590 // apps, then skip over that many that are currently hidden.
1591 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1592 skipTop--;
1593 }
1594 if (p.lruWeight <= app.lruWeight){
1595 mLruProcesses.add(i+1, app);
1596 break;
1597 }
1598 i--;
1599 }
1600 if (i < 0) {
1601 mLruProcesses.add(0, app);
1602 }
1603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 //Log.i(TAG, "Putting proc to front: " + app.processName);
1605 if (oomAdj) {
1606 updateOomAdjLocked();
1607 }
1608 }
1609
1610 private final boolean updateLRUListLocked(HistoryRecord r) {
1611 final boolean hadit = mLRUActivities.remove(r);
1612 mLRUActivities.add(r);
1613 return hadit;
1614 }
1615
1616 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1617 int i = mHistory.size()-1;
1618 while (i >= 0) {
1619 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1620 if (!r.finishing && r != notTop) {
1621 return r;
1622 }
1623 i--;
1624 }
1625 return null;
1626 }
1627
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001628 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1629 int i = mHistory.size()-1;
1630 while (i >= 0) {
1631 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1632 if (!r.finishing && !r.delayedResume && r != notTop) {
1633 return r;
1634 }
1635 i--;
1636 }
1637 return null;
1638 }
1639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 /**
1641 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001642 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 *
1644 * @param token If non-null, any history records matching this token will be skipped.
1645 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1646 *
1647 * @return Returns the HistoryRecord of the next activity on the stack.
1648 */
1649 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1650 int i = mHistory.size()-1;
1651 while (i >= 0) {
1652 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1653 // Note: the taskId check depends on real taskId fields being non-zero
1654 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1655 return r;
1656 }
1657 i--;
1658 }
1659 return null;
1660 }
1661
1662 private final ProcessRecord getProcessRecordLocked(
1663 String processName, int uid) {
1664 if (uid == Process.SYSTEM_UID) {
1665 // The system gets to run in any process. If there are multiple
1666 // processes with the same uid, just pick the first (this
1667 // should never happen).
1668 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1669 processName);
1670 return procs != null ? procs.valueAt(0) : null;
1671 }
1672 ProcessRecord proc = mProcessNames.get(processName, uid);
1673 return proc;
1674 }
1675
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001676 private void ensurePackageDexOpt(String packageName) {
1677 IPackageManager pm = ActivityThread.getPackageManager();
1678 try {
1679 if (pm.performDexOpt(packageName)) {
1680 mDidDexOpt = true;
1681 }
1682 } catch (RemoteException e) {
1683 }
1684 }
1685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 private boolean isNextTransitionForward() {
1687 int transit = mWindowManager.getPendingAppTransition();
1688 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1689 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1690 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1691 }
1692
1693 private final boolean realStartActivityLocked(HistoryRecord r,
1694 ProcessRecord app, boolean andResume, boolean checkConfig)
1695 throws RemoteException {
1696
1697 r.startFreezingScreenLocked(app, 0);
1698 mWindowManager.setAppVisibility(r, true);
1699
1700 // Have the window manager re-evaluate the orientation of
1701 // the screen based on the new activity order. Note that
1702 // as a result of this, it can call back into the activity
1703 // manager with a new orientation. We don't care about that,
1704 // because the activity is not currently running so we are
1705 // just restarting it anyway.
1706 if (checkConfig) {
1707 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001708 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 r.mayFreezeScreenLocked(app) ? r : null);
1710 updateConfigurationLocked(config, r);
1711 }
1712
1713 r.app = app;
1714
1715 if (localLOGV) Log.v(TAG, "Launching: " + r);
1716
1717 int idx = app.activities.indexOf(r);
1718 if (idx < 0) {
1719 app.activities.add(r);
1720 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001721 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722
1723 try {
1724 if (app.thread == null) {
1725 throw new RemoteException();
1726 }
1727 List<ResultInfo> results = null;
1728 List<Intent> newIntents = null;
1729 if (andResume) {
1730 results = r.results;
1731 newIntents = r.newIntents;
1732 }
1733 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1734 + " icicle=" + r.icicle
1735 + " with results=" + results + " newIntents=" + newIntents
1736 + " andResume=" + andResume);
1737 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001738 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 System.identityHashCode(r),
1740 r.task.taskId, r.shortComponentName);
1741 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001742 if (r.isHomeActivity) {
1743 mHomeProcess = app;
1744 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001745 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001747 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 r.info, r.icicle, results, newIntents, !andResume,
1749 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 } catch (RemoteException e) {
1751 if (r.launchFailed) {
1752 // This is the second time we failed -- finish activity
1753 // and give up.
1754 Log.e(TAG, "Second failure launching "
1755 + r.intent.getComponent().flattenToShortString()
1756 + ", giving up", e);
1757 appDiedLocked(app, app.pid, app.thread);
1758 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1759 "2nd-crash");
1760 return false;
1761 }
1762
1763 // This is the first time we failed -- restart process and
1764 // retry.
1765 app.activities.remove(r);
1766 throw e;
1767 }
1768
1769 r.launchFailed = false;
1770 if (updateLRUListLocked(r)) {
1771 Log.w(TAG, "Activity " + r
1772 + " being launched, but already in LRU list");
1773 }
1774
1775 if (andResume) {
1776 // As part of the process of launching, ActivityThread also performs
1777 // a resume.
1778 r.state = ActivityState.RESUMED;
1779 r.icicle = null;
1780 r.haveState = false;
1781 r.stopped = false;
1782 mResumedActivity = r;
1783 r.task.touchActiveTime();
1784 completeResumeLocked(r);
1785 pauseIfSleepingLocked();
1786 } else {
1787 // This activity is not starting in the resumed state... which
1788 // should look like we asked it to pause+stop (but remain visible),
1789 // and it has done so and reported back the current icicle and
1790 // other state.
1791 r.state = ActivityState.STOPPED;
1792 r.stopped = true;
1793 }
1794
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001795 // Launch the new version setup screen if needed. We do this -after-
1796 // launching the initial activity (that is, home), so that it can have
1797 // a chance to initialize itself while in the background, making the
1798 // switch back to it faster and look better.
1799 startSetupActivityLocked();
1800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 return true;
1802 }
1803
1804 private final void startSpecificActivityLocked(HistoryRecord r,
1805 boolean andResume, boolean checkConfig) {
1806 // Is this activity's application already running?
1807 ProcessRecord app = getProcessRecordLocked(r.processName,
1808 r.info.applicationInfo.uid);
1809
1810 if (r.startTime == 0) {
1811 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001812 if (mInitialStartTime == 0) {
1813 mInitialStartTime = r.startTime;
1814 }
1815 } else if (mInitialStartTime == 0) {
1816 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817 }
1818
1819 if (app != null && app.thread != null) {
1820 try {
1821 realStartActivityLocked(r, app, andResume, checkConfig);
1822 return;
1823 } catch (RemoteException e) {
1824 Log.w(TAG, "Exception when starting activity "
1825 + r.intent.getComponent().flattenToShortString(), e);
1826 }
1827
1828 // If a dead object exception was thrown -- fall through to
1829 // restart the application.
1830 }
1831
1832 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001833 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 }
1835
1836 private final ProcessRecord startProcessLocked(String processName,
1837 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001838 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001839 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1840 // We don't have to do anything more if:
1841 // (1) There is an existing application record; and
1842 // (2) The caller doesn't think it is dead, OR there is no thread
1843 // object attached to it so we know it couldn't have crashed; and
1844 // (3) There is a pid assigned to it, so it is either starting or
1845 // already running.
1846 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1847 + " app=" + app + " knownToBeDead=" + knownToBeDead
1848 + " thread=" + (app != null ? app.thread : null)
1849 + " pid=" + (app != null ? app.pid : -1));
1850 if (app != null &&
1851 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1852 return app;
1853 }
1854
1855 String hostingNameStr = hostingName != null
1856 ? hostingName.flattenToShortString() : null;
1857
1858 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1859 // If we are in the background, then check to see if this process
1860 // is bad. If so, we will just silently fail.
1861 if (mBadProcesses.get(info.processName, info.uid) != null) {
1862 return null;
1863 }
1864 } else {
1865 // When the user is explicitly starting a process, then clear its
1866 // crash count so that we won't make it bad until they see at
1867 // least one crash dialog again, and make the process good again
1868 // if it had been bad.
1869 mProcessCrashTimes.remove(info.processName, info.uid);
1870 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001871 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 info.processName);
1873 mBadProcesses.remove(info.processName, info.uid);
1874 if (app != null) {
1875 app.bad = false;
1876 }
1877 }
1878 }
1879
1880 if (app == null) {
1881 app = newProcessRecordLocked(null, info, processName);
1882 mProcessNames.put(processName, info.uid, app);
1883 } else {
1884 // If this is a new package in the process, add the package to the list
1885 app.addPackage(info.packageName);
1886 }
1887
1888 // If the system is not ready yet, then hold off on starting this
1889 // process until it is.
1890 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001891 && !isAllowedWhileBooting(info)
1892 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001893 if (!mProcessesOnHold.contains(app)) {
1894 mProcessesOnHold.add(app);
1895 }
1896 return app;
1897 }
1898
1899 startProcessLocked(app, hostingType, hostingNameStr);
1900 return (app.pid != 0) ? app : null;
1901 }
1902
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001903 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1904 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1905 }
1906
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 private final void startProcessLocked(ProcessRecord app,
1908 String hostingType, String hostingNameStr) {
1909 if (app.pid > 0 && app.pid != MY_PID) {
1910 synchronized (mPidsSelfLocked) {
1911 mPidsSelfLocked.remove(app.pid);
1912 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1913 }
1914 app.pid = 0;
1915 }
1916
1917 mProcessesOnHold.remove(app);
1918
1919 updateCpuStats();
1920
1921 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1922 mProcDeaths[0] = 0;
1923
1924 try {
1925 int uid = app.info.uid;
1926 int[] gids = null;
1927 try {
1928 gids = mContext.getPackageManager().getPackageGids(
1929 app.info.packageName);
1930 } catch (PackageManager.NameNotFoundException e) {
1931 Log.w(TAG, "Unable to retrieve gids", e);
1932 }
1933 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1934 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1935 && mTopComponent != null
1936 && app.processName.equals(mTopComponent.getPackageName())) {
1937 uid = 0;
1938 }
1939 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1940 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1941 uid = 0;
1942 }
1943 }
1944 int debugFlags = 0;
1945 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1946 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1947 }
Ben Cheng6c0afff2010-02-14 16:18:56 -08001948 // Run the app in safe mode if its manifest requests so or the
1949 // system is booted in safe mode.
1950 if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
1951 Zygote.systemInSafeMode == true) {
Ben Cheng23085b72010-02-08 16:06:32 -08001952 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
1953 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1955 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1956 }
1957 if ("1".equals(SystemProperties.get("debug.assert"))) {
1958 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1959 }
1960 int pid = Process.start("android.app.ActivityThread",
1961 mSimpleProcessManagement ? app.processName : null, uid, uid,
1962 gids, debugFlags, null);
1963 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1964 synchronized (bs) {
1965 if (bs.isOnBattery()) {
1966 app.batteryStats.incStartsLocked();
1967 }
1968 }
1969
Doug Zongker2bec3d42009-12-04 12:52:44 -08001970 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 app.processName, hostingType,
1972 hostingNameStr != null ? hostingNameStr : "");
1973
1974 if (app.persistent) {
1975 Watchdog.getInstance().processStarted(app, app.processName, pid);
1976 }
1977
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001978 StringBuilder buf = mStringBuilder;
1979 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 buf.append("Start proc ");
1981 buf.append(app.processName);
1982 buf.append(" for ");
1983 buf.append(hostingType);
1984 if (hostingNameStr != null) {
1985 buf.append(" ");
1986 buf.append(hostingNameStr);
1987 }
1988 buf.append(": pid=");
1989 buf.append(pid);
1990 buf.append(" uid=");
1991 buf.append(uid);
1992 buf.append(" gids={");
1993 if (gids != null) {
1994 for (int gi=0; gi<gids.length; gi++) {
1995 if (gi != 0) buf.append(", ");
1996 buf.append(gids[gi]);
1997
1998 }
1999 }
2000 buf.append("}");
2001 Log.i(TAG, buf.toString());
2002 if (pid == 0 || pid == MY_PID) {
2003 // Processes are being emulated with threads.
2004 app.pid = MY_PID;
2005 app.removed = false;
2006 mStartingProcesses.add(app);
2007 } else if (pid > 0) {
2008 app.pid = pid;
2009 app.removed = false;
2010 synchronized (mPidsSelfLocked) {
2011 this.mPidsSelfLocked.put(pid, app);
2012 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2013 msg.obj = app;
2014 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2015 }
2016 } else {
2017 app.pid = 0;
2018 RuntimeException e = new RuntimeException(
2019 "Failure starting process " + app.processName
2020 + ": returned pid=" + pid);
2021 Log.e(TAG, e.getMessage(), e);
2022 }
2023 } catch (RuntimeException e) {
2024 // XXX do better error recovery.
2025 app.pid = 0;
2026 Log.e(TAG, "Failure starting process " + app.processName, e);
2027 }
2028 }
2029
2030 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2031 if (mPausingActivity != null) {
2032 RuntimeException e = new RuntimeException();
2033 Log.e(TAG, "Trying to pause when pause is already pending for "
2034 + mPausingActivity, e);
2035 }
2036 HistoryRecord prev = mResumedActivity;
2037 if (prev == null) {
2038 RuntimeException e = new RuntimeException();
2039 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2040 resumeTopActivityLocked(null);
2041 return;
2042 }
2043 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2044 mResumedActivity = null;
2045 mPausingActivity = prev;
2046 mLastPausedActivity = prev;
2047 prev.state = ActivityState.PAUSING;
2048 prev.task.touchActiveTime();
2049
2050 updateCpuStats();
2051
2052 if (prev.app != null && prev.app.thread != null) {
2053 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2054 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002055 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 System.identityHashCode(prev),
2057 prev.shortComponentName);
2058 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2059 prev.configChangeFlags);
2060 updateUsageStats(prev, false);
2061 } catch (Exception e) {
2062 // Ignore exception, if process died other code will cleanup.
2063 Log.w(TAG, "Exception thrown during pause", e);
2064 mPausingActivity = null;
2065 mLastPausedActivity = null;
2066 }
2067 } else {
2068 mPausingActivity = null;
2069 mLastPausedActivity = null;
2070 }
2071
2072 // If we are not going to sleep, we want to ensure the device is
2073 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002074 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002075 mLaunchingActivity.acquire();
2076 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2077 // To be safe, don't allow the wake lock to be held for too long.
2078 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2079 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2080 }
2081 }
2082
2083
2084 if (mPausingActivity != null) {
2085 // Have the window manager pause its key dispatching until the new
2086 // activity has started. If we're pausing the activity just because
2087 // the screen is being turned off and the UI is sleeping, don't interrupt
2088 // key dispatch; the same activity will pick it up again on wakeup.
2089 if (!uiSleeping) {
2090 prev.pauseKeyDispatchingLocked();
2091 } else {
2092 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2093 }
2094
2095 // Schedule a pause timeout in case the app doesn't respond.
2096 // We don't give it much time because this directly impacts the
2097 // responsiveness seen by the user.
2098 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2099 msg.obj = prev;
2100 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2101 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2102 } else {
2103 // This activity failed to schedule the
2104 // pause, so just treat it as being paused now.
2105 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2106 resumeTopActivityLocked(null);
2107 }
2108 }
2109
2110 private final void completePauseLocked() {
2111 HistoryRecord prev = mPausingActivity;
2112 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2113
2114 if (prev != null) {
2115 if (prev.finishing) {
2116 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2117 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2118 } else if (prev.app != null) {
2119 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2120 if (prev.waitingVisible) {
2121 prev.waitingVisible = false;
2122 mWaitingVisibleActivities.remove(prev);
2123 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2124 TAG, "Complete pause, no longer waiting: " + prev);
2125 }
2126 if (prev.configDestroy) {
2127 // The previous is being paused because the configuration
2128 // is changing, which means it is actually stopping...
2129 // To juggle the fact that we are also starting a new
2130 // instance right now, we need to first completely stop
2131 // the current instance before starting the new one.
2132 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2133 destroyActivityLocked(prev, true);
2134 } else {
2135 mStoppingActivities.add(prev);
2136 if (mStoppingActivities.size() > 3) {
2137 // If we already have a few activities waiting to stop,
2138 // then give up on things going idle and start clearing
2139 // them out.
2140 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2141 Message msg = Message.obtain();
2142 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2143 mHandler.sendMessage(msg);
2144 }
2145 }
2146 } else {
2147 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2148 prev = null;
2149 }
2150 mPausingActivity = null;
2151 }
2152
Dianne Hackborn55280a92009-05-07 15:53:46 -07002153 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154 resumeTopActivityLocked(prev);
2155 } else {
2156 if (mGoingToSleep.isHeld()) {
2157 mGoingToSleep.release();
2158 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002159 if (mShuttingDown) {
2160 notifyAll();
2161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 }
2163
2164 if (prev != null) {
2165 prev.resumeKeyDispatchingLocked();
2166 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002167
2168 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2169 long diff = 0;
2170 synchronized (mProcessStatsThread) {
2171 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2172 }
2173 if (diff > 0) {
2174 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2175 synchronized (bsi) {
2176 BatteryStatsImpl.Uid.Proc ps =
2177 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2178 prev.info.packageName);
2179 if (ps != null) {
2180 ps.addForegroundTimeLocked(diff);
2181 }
2182 }
2183 }
2184 }
2185 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 }
2187
2188 /**
2189 * Once we know that we have asked an application to put an activity in
2190 * the resumed state (either by launching it or explicitly telling it),
2191 * this function updates the rest of our state to match that fact.
2192 */
2193 private final void completeResumeLocked(HistoryRecord next) {
2194 next.idle = false;
2195 next.results = null;
2196 next.newIntents = null;
2197
2198 // schedule an idle timeout in case the app doesn't do it for us.
2199 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2200 msg.obj = next;
2201 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2202
2203 if (false) {
2204 // The activity was never told to pause, so just keep
2205 // things going as-is. To maintain our own state,
2206 // we need to emulate it coming back and saying it is
2207 // idle.
2208 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2209 msg.obj = next;
2210 mHandler.sendMessage(msg);
2211 }
2212
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002213 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 next.thumbnail = null;
2216 setFocusedActivityLocked(next);
2217 next.resumeKeyDispatchingLocked();
2218 ensureActivitiesVisibleLocked(null, 0);
2219 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002220 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002221
2222 // Mark the point when the activity is resuming
2223 // TODO: To be more accurate, the mark should be before the onCreate,
2224 // not after the onResume. But for subsequent starts, onResume is fine.
2225 if (next.app != null) {
2226 synchronized (mProcessStatsThread) {
2227 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2228 }
2229 } else {
2230 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 }
2233
2234 /**
2235 * Make sure that all activities that need to be visible (that is, they
2236 * currently can be seen by the user) actually are.
2237 */
2238 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2239 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2240 if (DEBUG_VISBILITY) Log.v(
2241 TAG, "ensureActivitiesVisible behind " + top
2242 + " configChanges=0x" + Integer.toHexString(configChanges));
2243
2244 // If the top activity is not fullscreen, then we need to
2245 // make sure any activities under it are now visible.
2246 final int count = mHistory.size();
2247 int i = count-1;
2248 while (mHistory.get(i) != top) {
2249 i--;
2250 }
2251 HistoryRecord r;
2252 boolean behindFullscreen = false;
2253 for (; i>=0; i--) {
2254 r = (HistoryRecord)mHistory.get(i);
2255 if (DEBUG_VISBILITY) Log.v(
2256 TAG, "Make visible? " + r + " finishing=" + r.finishing
2257 + " state=" + r.state);
2258 if (r.finishing) {
2259 continue;
2260 }
2261
2262 final boolean doThisProcess = onlyThisProcess == null
2263 || onlyThisProcess.equals(r.processName);
2264
2265 // First: if this is not the current activity being started, make
2266 // sure it matches the current configuration.
2267 if (r != starting && doThisProcess) {
2268 ensureActivityConfigurationLocked(r, 0);
2269 }
2270
2271 if (r.app == null || r.app.thread == null) {
2272 if (onlyThisProcess == null
2273 || onlyThisProcess.equals(r.processName)) {
2274 // This activity needs to be visible, but isn't even
2275 // running... get it started, but don't resume it
2276 // at this point.
2277 if (DEBUG_VISBILITY) Log.v(
2278 TAG, "Start and freeze screen for " + r);
2279 if (r != starting) {
2280 r.startFreezingScreenLocked(r.app, configChanges);
2281 }
2282 if (!r.visible) {
2283 if (DEBUG_VISBILITY) Log.v(
2284 TAG, "Starting and making visible: " + r);
2285 mWindowManager.setAppVisibility(r, true);
2286 }
2287 if (r != starting) {
2288 startSpecificActivityLocked(r, false, false);
2289 }
2290 }
2291
2292 } else if (r.visible) {
2293 // If this activity is already visible, then there is nothing
2294 // else to do here.
2295 if (DEBUG_VISBILITY) Log.v(
2296 TAG, "Skipping: already visible at " + r);
2297 r.stopFreezingScreenLocked(false);
2298
2299 } else if (onlyThisProcess == null) {
2300 // This activity is not currently visible, but is running.
2301 // Tell it to become visible.
2302 r.visible = true;
2303 if (r.state != ActivityState.RESUMED && r != starting) {
2304 // If this activity is paused, tell it
2305 // to now show its window.
2306 if (DEBUG_VISBILITY) Log.v(
2307 TAG, "Making visible and scheduling visibility: " + r);
2308 try {
2309 mWindowManager.setAppVisibility(r, true);
2310 r.app.thread.scheduleWindowVisibility(r, true);
2311 r.stopFreezingScreenLocked(false);
2312 } catch (Exception e) {
2313 // Just skip on any failure; we'll make it
2314 // visible when it next restarts.
2315 Log.w(TAG, "Exception thrown making visibile: "
2316 + r.intent.getComponent(), e);
2317 }
2318 }
2319 }
2320
2321 // Aggregate current change flags.
2322 configChanges |= r.configChangeFlags;
2323
2324 if (r.fullscreen) {
2325 // At this point, nothing else needs to be shown
2326 if (DEBUG_VISBILITY) Log.v(
2327 TAG, "Stopping: fullscreen at " + r);
2328 behindFullscreen = true;
2329 i--;
2330 break;
2331 }
2332 }
2333
2334 // Now for any activities that aren't visible to the user, make
2335 // sure they no longer are keeping the screen frozen.
2336 while (i >= 0) {
2337 r = (HistoryRecord)mHistory.get(i);
2338 if (DEBUG_VISBILITY) Log.v(
2339 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2340 + " state=" + r.state
2341 + " behindFullscreen=" + behindFullscreen);
2342 if (!r.finishing) {
2343 if (behindFullscreen) {
2344 if (r.visible) {
2345 if (DEBUG_VISBILITY) Log.v(
2346 TAG, "Making invisible: " + r);
2347 r.visible = false;
2348 try {
2349 mWindowManager.setAppVisibility(r, false);
2350 if ((r.state == ActivityState.STOPPING
2351 || r.state == ActivityState.STOPPED)
2352 && r.app != null && r.app.thread != null) {
2353 if (DEBUG_VISBILITY) Log.v(
2354 TAG, "Scheduling invisibility: " + r);
2355 r.app.thread.scheduleWindowVisibility(r, false);
2356 }
2357 } catch (Exception e) {
2358 // Just skip on any failure; we'll make it
2359 // visible when it next restarts.
2360 Log.w(TAG, "Exception thrown making hidden: "
2361 + r.intent.getComponent(), e);
2362 }
2363 } else {
2364 if (DEBUG_VISBILITY) Log.v(
2365 TAG, "Already invisible: " + r);
2366 }
2367 } else if (r.fullscreen) {
2368 if (DEBUG_VISBILITY) Log.v(
2369 TAG, "Now behindFullscreen: " + r);
2370 behindFullscreen = true;
2371 }
2372 }
2373 i--;
2374 }
2375 }
2376
2377 /**
2378 * Version of ensureActivitiesVisible that can easily be called anywhere.
2379 */
2380 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2381 int configChanges) {
2382 HistoryRecord r = topRunningActivityLocked(null);
2383 if (r != null) {
2384 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2385 }
2386 }
2387
2388 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2389 if (resumed) {
2390 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2391 } else {
2392 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2393 }
2394 }
2395
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002396 private boolean startHomeActivityLocked() {
2397 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2398 && mTopAction == null) {
2399 // We are running in factory test mode, but unable to find
2400 // the factory test app, so just sit around displaying the
2401 // error message and don't try to start anything.
2402 return false;
2403 }
2404 Intent intent = new Intent(
2405 mTopAction,
2406 mTopData != null ? Uri.parse(mTopData) : null);
2407 intent.setComponent(mTopComponent);
2408 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2409 intent.addCategory(Intent.CATEGORY_HOME);
2410 }
2411 ActivityInfo aInfo =
2412 intent.resolveActivityInfo(mContext.getPackageManager(),
2413 STOCK_PM_FLAGS);
2414 if (aInfo != null) {
2415 intent.setComponent(new ComponentName(
2416 aInfo.applicationInfo.packageName, aInfo.name));
2417 // Don't do this if the home app is currently being
2418 // instrumented.
2419 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2420 aInfo.applicationInfo.uid);
2421 if (app == null || app.instrumentationClass == null) {
2422 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2423 startActivityLocked(null, intent, null, null, 0, aInfo,
2424 null, null, 0, 0, 0, false, false);
2425 }
2426 }
2427
2428
2429 return true;
2430 }
2431
2432 /**
2433 * Starts the "new version setup screen" if appropriate.
2434 */
2435 private void startSetupActivityLocked() {
2436 // Only do this once per boot.
2437 if (mCheckedForSetup) {
2438 return;
2439 }
2440
2441 // We will show this screen if the current one is a different
2442 // version than the last one shown, and we are not running in
2443 // low-level factory test mode.
2444 final ContentResolver resolver = mContext.getContentResolver();
2445 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2446 Settings.Secure.getInt(resolver,
2447 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2448 mCheckedForSetup = true;
2449
2450 // See if we should be showing the platform update setup UI.
2451 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2452 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2453 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2454
2455 // We don't allow third party apps to replace this.
2456 ResolveInfo ri = null;
2457 for (int i=0; ris != null && i<ris.size(); i++) {
2458 if ((ris.get(i).activityInfo.applicationInfo.flags
2459 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2460 ri = ris.get(i);
2461 break;
2462 }
2463 }
2464
2465 if (ri != null) {
2466 String vers = ri.activityInfo.metaData != null
2467 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2468 : null;
2469 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2470 vers = ri.activityInfo.applicationInfo.metaData.getString(
2471 Intent.METADATA_SETUP_VERSION);
2472 }
2473 String lastVers = Settings.Secure.getString(
2474 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2475 if (vers != null && !vers.equals(lastVers)) {
2476 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2477 intent.setComponent(new ComponentName(
2478 ri.activityInfo.packageName, ri.activityInfo.name));
2479 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2480 null, null, 0, 0, 0, false, false);
2481 }
2482 }
2483 }
2484 }
2485
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002486 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002487 //Log.i(TAG, "**** REPORT RESUME: " + r);
2488
2489 final int identHash = System.identityHashCode(r);
2490 updateUsageStats(r, true);
2491
2492 int i = mWatchers.beginBroadcast();
2493 while (i > 0) {
2494 i--;
2495 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2496 if (w != null) {
2497 try {
2498 w.activityResuming(identHash);
2499 } catch (RemoteException e) {
2500 }
2501 }
2502 }
2503 mWatchers.finishBroadcast();
2504 }
2505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002506 /**
2507 * Ensure that the top activity in the stack is resumed.
2508 *
2509 * @param prev The previously resumed activity, for when in the process
2510 * of pausing; can be null to call from elsewhere.
2511 *
2512 * @return Returns true if something is being resumed, or false if
2513 * nothing happened.
2514 */
2515 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2516 // Find the first activity that is not finishing.
2517 HistoryRecord next = topRunningActivityLocked(null);
2518
2519 // Remember how we'll process this pause/resume situation, and ensure
2520 // that the state is reset however we wind up proceeding.
2521 final boolean userLeaving = mUserLeaving;
2522 mUserLeaving = false;
2523
2524 if (next == null) {
2525 // There are no more activities! Let's just start up the
2526 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002527 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002528 }
2529
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002530 next.delayedResume = false;
2531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002532 // If the top activity is the resumed one, nothing to do.
2533 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2534 // Make sure we have executed any pending transitions, since there
2535 // should be nothing left to do at this point.
2536 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002537 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002538 return false;
2539 }
2540
2541 // If we are sleeping, and there is no resumed activity, and the top
2542 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002543 if ((mSleeping || mShuttingDown)
2544 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 // Make sure we have executed any pending transitions, since there
2546 // should be nothing left to do at this point.
2547 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002548 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002549 return false;
2550 }
2551
2552 // The activity may be waiting for stop, but that is no longer
2553 // appropriate for it.
2554 mStoppingActivities.remove(next);
2555 mWaitingVisibleActivities.remove(next);
2556
2557 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2558
2559 // If we are currently pausing an activity, then don't do anything
2560 // until that is done.
2561 if (mPausingActivity != null) {
2562 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2563 return false;
2564 }
2565
2566 // We need to start pausing the current activity so the top one
2567 // can be resumed...
2568 if (mResumedActivity != null) {
2569 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2570 startPausingLocked(userLeaving, false);
2571 return true;
2572 }
2573
2574 if (prev != null && prev != next) {
2575 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2576 prev.waitingVisible = true;
2577 mWaitingVisibleActivities.add(prev);
2578 if (DEBUG_SWITCH) Log.v(
2579 TAG, "Resuming top, waiting visible to hide: " + prev);
2580 } else {
2581 // The next activity is already visible, so hide the previous
2582 // activity's windows right now so we can show the new one ASAP.
2583 // We only do this if the previous is finishing, which should mean
2584 // it is on top of the one being resumed so hiding it quickly
2585 // is good. Otherwise, we want to do the normal route of allowing
2586 // the resumed activity to be shown so we can decide if the
2587 // previous should actually be hidden depending on whether the
2588 // new one is found to be full-screen or not.
2589 if (prev.finishing) {
2590 mWindowManager.setAppVisibility(prev, false);
2591 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2592 + prev + ", waitingVisible="
2593 + (prev != null ? prev.waitingVisible : null)
2594 + ", nowVisible=" + next.nowVisible);
2595 } else {
2596 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2597 + prev + ", waitingVisible="
2598 + (prev != null ? prev.waitingVisible : null)
2599 + ", nowVisible=" + next.nowVisible);
2600 }
2601 }
2602 }
2603
2604 // We are starting up the next activity, so tell the window manager
2605 // that the previous one will be hidden soon. This way it can know
2606 // to ignore it when computing the desired screen orientation.
2607 if (prev != null) {
2608 if (prev.finishing) {
2609 if (DEBUG_TRANSITION) Log.v(TAG,
2610 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002611 if (mNoAnimActivities.contains(prev)) {
2612 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2613 } else {
2614 mWindowManager.prepareAppTransition(prev.task == next.task
2615 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2616 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2617 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002618 mWindowManager.setAppWillBeHidden(prev);
2619 mWindowManager.setAppVisibility(prev, false);
2620 } else {
2621 if (DEBUG_TRANSITION) Log.v(TAG,
2622 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002623 if (mNoAnimActivities.contains(next)) {
2624 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2625 } else {
2626 mWindowManager.prepareAppTransition(prev.task == next.task
2627 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2628 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2629 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002630 }
2631 if (false) {
2632 mWindowManager.setAppWillBeHidden(prev);
2633 mWindowManager.setAppVisibility(prev, false);
2634 }
2635 } else if (mHistory.size() > 1) {
2636 if (DEBUG_TRANSITION) Log.v(TAG,
2637 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002638 if (mNoAnimActivities.contains(next)) {
2639 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2640 } else {
2641 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 }
2644
2645 if (next.app != null && next.app.thread != null) {
2646 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2647
2648 // This activity is now becoming visible.
2649 mWindowManager.setAppVisibility(next, true);
2650
2651 HistoryRecord lastResumedActivity = mResumedActivity;
2652 ActivityState lastState = next.state;
2653
2654 updateCpuStats();
2655
2656 next.state = ActivityState.RESUMED;
2657 mResumedActivity = next;
2658 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002659 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 updateLRUListLocked(next);
2661
2662 // Have the window manager re-evaluate the orientation of
2663 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002664 boolean updated;
2665 synchronized (this) {
2666 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2667 mConfiguration,
2668 next.mayFreezeScreenLocked(next.app) ? next : null);
2669 if (config != null) {
Eric Fischerd4d04de2009-10-27 18:55:57 -07002670 next.frozenBeforeDestroy = true;
2671 }
2672 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002673 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002674 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 // The configuration update wasn't able to keep the existing
2676 // instance of the activity, and instead started a new one.
2677 // We should be all done, but let's just make sure our activity
2678 // is still at the top and schedule another run if something
2679 // weird happened.
2680 HistoryRecord nextNext = topRunningActivityLocked(null);
2681 if (DEBUG_SWITCH) Log.i(TAG,
2682 "Activity config changed during resume: " + next
2683 + ", new next: " + nextNext);
2684 if (nextNext != next) {
2685 // Do over!
2686 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2687 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002688 setFocusedActivityLocked(next);
2689 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002690 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002691 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002692 return true;
2693 }
2694
2695 try {
2696 // Deliver all pending results.
2697 ArrayList a = next.results;
2698 if (a != null) {
2699 final int N = a.size();
2700 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002701 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 TAG, "Delivering results to " + next
2703 + ": " + a);
2704 next.app.thread.scheduleSendResult(next, a);
2705 }
2706 }
2707
2708 if (next.newIntents != null) {
2709 next.app.thread.scheduleNewIntent(next.newIntents, next);
2710 }
2711
Doug Zongker2bec3d42009-12-04 12:52:44 -08002712 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002713 System.identityHashCode(next),
2714 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715
2716 next.app.thread.scheduleResumeActivity(next,
2717 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719 pauseIfSleepingLocked();
2720
2721 } catch (Exception e) {
2722 // Whoops, need to restart this activity!
2723 next.state = lastState;
2724 mResumedActivity = lastResumedActivity;
Dianne Hackborn03abb812010-01-04 18:43:19 -08002725 Log.i(TAG, "Restarting because process died: " + next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 if (!next.hasBeenLaunched) {
2727 next.hasBeenLaunched = true;
2728 } else {
2729 if (SHOW_APP_STARTING_ICON) {
2730 mWindowManager.setAppStartingWindow(
2731 next, next.packageName, next.theme,
2732 next.nonLocalizedLabel,
2733 next.labelRes, next.icon, null, true);
2734 }
2735 }
2736 startSpecificActivityLocked(next, true, false);
2737 return true;
2738 }
2739
2740 // From this point on, if something goes wrong there is no way
2741 // to recover the activity.
2742 try {
2743 next.visible = true;
2744 completeResumeLocked(next);
2745 } catch (Exception e) {
2746 // If any exception gets thrown, toss away this
2747 // activity and try the next one.
2748 Log.w(TAG, "Exception thrown during resume of " + next, e);
2749 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2750 "resume-exception");
2751 return true;
2752 }
2753
2754 // Didn't need to use the icicle, and it is now out of date.
2755 next.icicle = null;
2756 next.haveState = false;
2757 next.stopped = false;
2758
2759 } else {
2760 // Whoops, need to restart this activity!
2761 if (!next.hasBeenLaunched) {
2762 next.hasBeenLaunched = true;
2763 } else {
2764 if (SHOW_APP_STARTING_ICON) {
2765 mWindowManager.setAppStartingWindow(
2766 next, next.packageName, next.theme,
2767 next.nonLocalizedLabel,
2768 next.labelRes, next.icon, null, true);
2769 }
2770 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2771 }
2772 startSpecificActivityLocked(next, true, true);
2773 }
2774
2775 return true;
2776 }
2777
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002778 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2779 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002780 final int NH = mHistory.size();
2781
2782 int addPos = -1;
2783
2784 if (!newTask) {
2785 // If starting in an existing task, find where that is...
2786 HistoryRecord next = null;
2787 boolean startIt = true;
2788 for (int i = NH-1; i >= 0; i--) {
2789 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2790 if (p.finishing) {
2791 continue;
2792 }
2793 if (p.task == r.task) {
2794 // Here it is! Now, if this is not yet visible to the
2795 // user, then just add it without starting; it will
2796 // get started when the user navigates back to it.
2797 addPos = i+1;
2798 if (!startIt) {
2799 mHistory.add(addPos, r);
2800 r.inHistory = true;
2801 r.task.numActivities++;
2802 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2803 r.info.screenOrientation, r.fullscreen);
2804 if (VALIDATE_TOKENS) {
2805 mWindowManager.validateAppTokens(mHistory);
2806 }
2807 return;
2808 }
2809 break;
2810 }
2811 if (p.fullscreen) {
2812 startIt = false;
2813 }
2814 next = p;
2815 }
2816 }
2817
2818 // Place a new activity at top of stack, so it is next to interact
2819 // with the user.
2820 if (addPos < 0) {
2821 addPos = mHistory.size();
2822 }
2823
2824 // If we are not placing the new activity frontmost, we do not want
2825 // to deliver the onUserLeaving callback to the actual frontmost
2826 // activity
2827 if (addPos < NH) {
2828 mUserLeaving = false;
2829 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2830 }
2831
2832 // Slot the activity into the history stack and proceed
2833 mHistory.add(addPos, r);
2834 r.inHistory = true;
2835 r.frontOfTask = newTask;
2836 r.task.numActivities++;
2837 if (NH > 0) {
2838 // We want to show the starting preview window if we are
2839 // switching to a new task, or the next activity's process is
2840 // not currently running.
2841 boolean showStartingIcon = newTask;
2842 ProcessRecord proc = r.app;
2843 if (proc == null) {
2844 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2845 }
2846 if (proc == null || proc.thread == null) {
2847 showStartingIcon = true;
2848 }
2849 if (DEBUG_TRANSITION) Log.v(TAG,
2850 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002851 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2852 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2853 mNoAnimActivities.add(r);
2854 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2855 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2856 mNoAnimActivities.remove(r);
2857 } else {
2858 mWindowManager.prepareAppTransition(newTask
2859 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2860 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2861 mNoAnimActivities.remove(r);
2862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002863 mWindowManager.addAppToken(
2864 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2865 boolean doShow = true;
2866 if (newTask) {
2867 // Even though this activity is starting fresh, we still need
2868 // to reset it to make sure we apply affinities to move any
2869 // existing activities from other tasks in to it.
2870 // If the caller has requested that the target task be
2871 // reset, then do so.
2872 if ((r.intent.getFlags()
2873 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2874 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002875 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002876 }
2877 }
2878 if (SHOW_APP_STARTING_ICON && doShow) {
2879 // Figure out if we are transitioning from another activity that is
2880 // "has the same starting icon" as the next one. This allows the
2881 // window manager to keep the previous window it had previously
2882 // created, if it still had one.
2883 HistoryRecord prev = mResumedActivity;
2884 if (prev != null) {
2885 // We don't want to reuse the previous starting preview if:
2886 // (1) The current activity is in a different task.
2887 if (prev.task != r.task) prev = null;
2888 // (2) The current activity is already displayed.
2889 else if (prev.nowVisible) prev = null;
2890 }
2891 mWindowManager.setAppStartingWindow(
2892 r, r.packageName, r.theme, r.nonLocalizedLabel,
2893 r.labelRes, r.icon, prev, showStartingIcon);
2894 }
2895 } else {
2896 // If this is the first activity, don't do any fancy animations,
2897 // because there is nothing for it to animate on top of.
2898 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2899 r.info.screenOrientation, r.fullscreen);
2900 }
2901 if (VALIDATE_TOKENS) {
2902 mWindowManager.validateAppTokens(mHistory);
2903 }
2904
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002905 if (doResume) {
2906 resumeTopActivityLocked(null);
2907 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908 }
2909
2910 /**
2911 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002912 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2913 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002914 * an instance of that activity in the stack and, if found, finish all
2915 * activities on top of it and return the instance.
2916 *
2917 * @param newR Description of the new activity being started.
2918 * @return Returns the old activity that should be continue to be used,
2919 * or null if none was found.
2920 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002921 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002922 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002924
2925 // First find the requested task.
2926 while (i > 0) {
2927 i--;
2928 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2929 if (r.task.taskId == taskId) {
2930 i++;
2931 break;
2932 }
2933 }
2934
2935 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002936 while (i > 0) {
2937 i--;
2938 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2939 if (r.finishing) {
2940 continue;
2941 }
2942 if (r.task.taskId != taskId) {
2943 return null;
2944 }
2945 if (r.realActivity.equals(newR.realActivity)) {
2946 // Here it is! Now finish everything in front...
2947 HistoryRecord ret = r;
2948 if (doClear) {
2949 while (i < (mHistory.size()-1)) {
2950 i++;
2951 r = (HistoryRecord)mHistory.get(i);
2952 if (r.finishing) {
2953 continue;
2954 }
2955 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2956 null, "clear")) {
2957 i--;
2958 }
2959 }
2960 }
2961
2962 // Finally, if this is a normal launch mode (that is, not
2963 // expecting onNewIntent()), then we will finish the current
2964 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002965 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2966 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002967 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002968 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002969 if (index >= 0) {
2970 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2971 null, "clear");
2972 }
2973 return null;
2974 }
2975 }
2976
2977 return ret;
2978 }
2979 }
2980
2981 return null;
2982 }
2983
2984 /**
2985 * Find the activity in the history stack within the given task. Returns
2986 * the index within the history at which it's found, or < 0 if not found.
2987 */
2988 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2989 int i = mHistory.size();
2990 while (i > 0) {
2991 i--;
2992 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2993 if (candidate.task.taskId != task) {
2994 break;
2995 }
2996 if (candidate.realActivity.equals(r.realActivity)) {
2997 return i;
2998 }
2999 }
3000
3001 return -1;
3002 }
3003
3004 /**
3005 * Reorder the history stack so that the activity at the given index is
3006 * brought to the front.
3007 */
3008 private final HistoryRecord moveActivityToFrontLocked(int where) {
3009 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3010 int top = mHistory.size();
3011 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3012 mHistory.add(top, newTop);
3013 oldTop.frontOfTask = false;
3014 newTop.frontOfTask = true;
3015 return newTop;
3016 }
3017
3018 /**
3019 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3020 * method will be called at the proper time.
3021 */
3022 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3023 boolean sent = false;
3024 if (r.state == ActivityState.RESUMED
3025 && r.app != null && r.app.thread != null) {
3026 try {
3027 ArrayList<Intent> ar = new ArrayList<Intent>();
3028 ar.add(new Intent(intent));
3029 r.app.thread.scheduleNewIntent(ar, r);
3030 sent = true;
3031 } catch (Exception e) {
3032 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3033 }
3034 }
3035 if (!sent) {
3036 r.addNewIntentLocked(new Intent(intent));
3037 }
3038 }
3039
3040 private final void logStartActivity(int tag, HistoryRecord r,
3041 TaskRecord task) {
3042 EventLog.writeEvent(tag,
3043 System.identityHashCode(r), task.taskId,
3044 r.shortComponentName, r.intent.getAction(),
3045 r.intent.getType(), r.intent.getDataString(),
3046 r.intent.getFlags());
3047 }
3048
3049 private final int startActivityLocked(IApplicationThread caller,
3050 Intent intent, String resolvedType,
3051 Uri[] grantedUriPermissions,
3052 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3053 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003054 int callingPid, int callingUid, boolean onlyIfNeeded,
3055 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003056 Log.i(TAG, "Starting activity: " + intent);
3057
3058 HistoryRecord sourceRecord = null;
3059 HistoryRecord resultRecord = null;
3060 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003061 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003062 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3064 if (index >= 0) {
3065 sourceRecord = (HistoryRecord)mHistory.get(index);
3066 if (requestCode >= 0 && !sourceRecord.finishing) {
3067 resultRecord = sourceRecord;
3068 }
3069 }
3070 }
3071
3072 int launchFlags = intent.getFlags();
3073
3074 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3075 && sourceRecord != null) {
3076 // Transfer the result target from the source activity to the new
3077 // one being started, including any failures.
3078 if (requestCode >= 0) {
3079 return START_FORWARD_AND_REQUEST_CONFLICT;
3080 }
3081 resultRecord = sourceRecord.resultTo;
3082 resultWho = sourceRecord.resultWho;
3083 requestCode = sourceRecord.requestCode;
3084 sourceRecord.resultTo = null;
3085 if (resultRecord != null) {
3086 resultRecord.removeResultsLocked(
3087 sourceRecord, resultWho, requestCode);
3088 }
3089 }
3090
3091 int err = START_SUCCESS;
3092
3093 if (intent.getComponent() == null) {
3094 // We couldn't find a class that can handle the given Intent.
3095 // That's the end of that!
3096 err = START_INTENT_NOT_RESOLVED;
3097 }
3098
3099 if (err == START_SUCCESS && aInfo == null) {
3100 // We couldn't find the specific class specified in the Intent.
3101 // Also the end of the line.
3102 err = START_CLASS_NOT_FOUND;
3103 }
3104
3105 ProcessRecord callerApp = null;
3106 if (err == START_SUCCESS && caller != null) {
3107 callerApp = getRecordForAppLocked(caller);
3108 if (callerApp != null) {
3109 callingPid = callerApp.pid;
3110 callingUid = callerApp.info.uid;
3111 } else {
3112 Log.w(TAG, "Unable to find app for caller " + caller
3113 + " (pid=" + callingPid + ") when starting: "
3114 + intent.toString());
3115 err = START_PERMISSION_DENIED;
3116 }
3117 }
3118
3119 if (err != START_SUCCESS) {
3120 if (resultRecord != null) {
3121 sendActivityResultLocked(-1,
3122 resultRecord, resultWho, requestCode,
3123 Activity.RESULT_CANCELED, null);
3124 }
3125 return err;
3126 }
3127
3128 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3129 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3130 if (perm != PackageManager.PERMISSION_GRANTED) {
3131 if (resultRecord != null) {
3132 sendActivityResultLocked(-1,
3133 resultRecord, resultWho, requestCode,
3134 Activity.RESULT_CANCELED, null);
3135 }
3136 String msg = "Permission Denial: starting " + intent.toString()
3137 + " from " + callerApp + " (pid=" + callingPid
3138 + ", uid=" + callingUid + ")"
3139 + " requires " + aInfo.permission;
3140 Log.w(TAG, msg);
3141 throw new SecurityException(msg);
3142 }
3143
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003144 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145 boolean abort = false;
3146 try {
3147 // The Intent we give to the watcher has the extra data
3148 // stripped off, since it can contain private information.
3149 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003150 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003151 aInfo.applicationInfo.packageName);
3152 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003153 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003154 }
3155
3156 if (abort) {
3157 if (resultRecord != null) {
3158 sendActivityResultLocked(-1,
3159 resultRecord, resultWho, requestCode,
3160 Activity.RESULT_CANCELED, null);
3161 }
3162 // We pretend to the caller that it was really started, but
3163 // they will just get a cancel result.
3164 return START_SUCCESS;
3165 }
3166 }
3167
3168 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3169 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003170 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003171
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003172 if (mResumedActivity == null
3173 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3174 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3175 PendingActivityLaunch pal = new PendingActivityLaunch();
3176 pal.r = r;
3177 pal.sourceRecord = sourceRecord;
3178 pal.grantedUriPermissions = grantedUriPermissions;
3179 pal.grantedMode = grantedMode;
3180 pal.onlyIfNeeded = onlyIfNeeded;
3181 mPendingActivityLaunches.add(pal);
3182 return START_SWITCHES_CANCELED;
3183 }
3184 }
3185
3186 if (mDidAppSwitch) {
3187 // This is the second allowed switch since we stopped switches,
3188 // so now just generally allow switches. Use case: user presses
3189 // home (switches disabled, switch to home, mDidAppSwitch now true);
3190 // user taps a home icon (coming from home so allowed, we hit here
3191 // and now allow anyone to switch again).
3192 mAppSwitchesAllowedTime = 0;
3193 } else {
3194 mDidAppSwitch = true;
3195 }
3196
3197 doPendingActivityLaunchesLocked(false);
3198
3199 return startActivityUncheckedLocked(r, sourceRecord,
3200 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3201 }
3202
3203 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3204 final int N = mPendingActivityLaunches.size();
3205 if (N <= 0) {
3206 return;
3207 }
3208 for (int i=0; i<N; i++) {
3209 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3210 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3211 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3212 doResume && i == (N-1));
3213 }
3214 mPendingActivityLaunches.clear();
3215 }
3216
3217 private final int startActivityUncheckedLocked(HistoryRecord r,
3218 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3219 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3220 final Intent intent = r.intent;
3221 final int callingUid = r.launchedFromUid;
3222
3223 int launchFlags = intent.getFlags();
3224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 // We'll invoke onUserLeaving before onPause only if the launching
3226 // activity did not explicitly state that this is an automated launch.
3227 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3228 if (DEBUG_USER_LEAVING) Log.v(TAG,
3229 "startActivity() => mUserLeaving=" + mUserLeaving);
3230
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003231 // If the caller has asked not to resume at this point, we make note
3232 // of this in the record so that we can skip it when trying to find
3233 // the top running activity.
3234 if (!doResume) {
3235 r.delayedResume = true;
3236 }
3237
3238 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3239 != 0 ? r : null;
3240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 // If the onlyIfNeeded flag is set, then we can do this if the activity
3242 // being launched is the same as the one making the call... or, as
3243 // a special case, if we do not know the caller then we count the
3244 // current top activity as the caller.
3245 if (onlyIfNeeded) {
3246 HistoryRecord checkedCaller = sourceRecord;
3247 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003248 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003249 }
3250 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3251 // Caller is not the same as launcher, so always needed.
3252 onlyIfNeeded = false;
3253 }
3254 }
3255
3256 if (grantedUriPermissions != null && callingUid > 0) {
3257 for (int i=0; i<grantedUriPermissions.length; i++) {
3258 grantUriPermissionLocked(callingUid, r.packageName,
3259 grantedUriPermissions[i], grantedMode, r);
3260 }
3261 }
3262
3263 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3264 intent, r);
3265
3266 if (sourceRecord == null) {
3267 // This activity is not being started from another... in this
3268 // case we -always- start a new task.
3269 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3270 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3271 + intent);
3272 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3273 }
3274 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3275 // The original activity who is starting us is running as a single
3276 // instance... this new activity it is starting must go on its
3277 // own task.
3278 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3279 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3280 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3281 // The activity being started is a single instance... it always
3282 // gets launched into its own task.
3283 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3284 }
3285
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003286 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003287 // For whatever reason this activity is being launched into a new
3288 // task... yet the caller has requested a result back. Well, that
3289 // is pretty messed up, so instead immediately send back a cancel
3290 // and let the new task continue launched as normal without a
3291 // dependency on its originator.
3292 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3293 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003294 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 Activity.RESULT_CANCELED, null);
3296 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 }
3298
3299 boolean addingToTask = false;
3300 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3301 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3302 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3303 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3304 // If bring to front is requested, and no result is requested, and
3305 // we can find a task that was started with this same
3306 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003307 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003308 // See if there is a task to bring to the front. If this is
3309 // a SINGLE_INSTANCE activity, there can be one and only one
3310 // instance of it in the history, and it is always in its own
3311 // unique task, so we do a special search.
3312 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3313 ? findTaskLocked(intent, r.info)
3314 : findActivityLocked(intent, r.info);
3315 if (taskTop != null) {
3316 if (taskTop.task.intent == null) {
3317 // This task was started because of movement of
3318 // the activity based on affinity... now that we
3319 // are actually launching it, we can assign the
3320 // base intent.
3321 taskTop.task.setIntent(intent, r.info);
3322 }
3323 // If the target task is not in the front, then we need
3324 // to bring it to the front... except... well, with
3325 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3326 // to have the same behavior as if a new instance was
3327 // being started, which means not bringing it to the front
3328 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003329 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003330 if (curTop.task != taskTop.task) {
3331 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3332 boolean callerAtFront = sourceRecord == null
3333 || curTop.task == sourceRecord.task;
3334 if (callerAtFront) {
3335 // We really do want to push this one into the
3336 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003337 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003338 }
3339 }
3340 // If the caller has requested that the target task be
3341 // reset, then do so.
3342 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3343 taskTop = resetTaskIfNeededLocked(taskTop, r);
3344 }
3345 if (onlyIfNeeded) {
3346 // We don't need to start a new activity, and
3347 // the client said not to do anything if that
3348 // is the case, so this is it! And for paranoia, make
3349 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003350 if (doResume) {
3351 resumeTopActivityLocked(null);
3352 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003353 return START_RETURN_INTENT_TO_CALLER;
3354 }
3355 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3356 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3357 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3358 // In this situation we want to remove all activities
3359 // from the task up to the one being started. In most
3360 // cases this means we are resetting the task to its
3361 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003362 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003363 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 if (top != null) {
3365 if (top.frontOfTask) {
3366 // Activity aliases may mean we use different
3367 // intents for the top activity, so make sure
3368 // the task now has the identity of the new
3369 // intent.
3370 top.task.setIntent(r.intent, r.info);
3371 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003372 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003373 deliverNewIntentLocked(top, r.intent);
3374 } else {
3375 // A special case: we need to
3376 // start the activity because it is not currently
3377 // running, and the caller has asked to clear the
3378 // current task to have this activity at the top.
3379 addingToTask = true;
3380 // Now pretend like this activity is being started
3381 // by the top of its task, so it is put in the
3382 // right place.
3383 sourceRecord = taskTop;
3384 }
3385 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3386 // In this case the top activity on the task is the
3387 // same as the one being launched, so we take that
3388 // as a request to bring the task to the foreground.
3389 // If the top activity in the task is the root
3390 // activity, deliver this new intent to it if it
3391 // desires.
3392 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3393 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003394 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 if (taskTop.frontOfTask) {
3396 taskTop.task.setIntent(r.intent, r.info);
3397 }
3398 deliverNewIntentLocked(taskTop, r.intent);
3399 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3400 // In this case we are launching the root activity
3401 // of the task, but with a different intent. We
3402 // should start a new instance on top.
3403 addingToTask = true;
3404 sourceRecord = taskTop;
3405 }
3406 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3407 // In this case an activity is being launched in to an
3408 // existing task, without resetting that task. This
3409 // is typically the situation of launching an activity
3410 // from a notification or shortcut. We want to place
3411 // the new activity on top of the current task.
3412 addingToTask = true;
3413 sourceRecord = taskTop;
3414 } else if (!taskTop.task.rootWasReset) {
3415 // In this case we are launching in to an existing task
3416 // that has not yet been started from its front door.
3417 // The current task has been brought to the front.
3418 // Ideally, we'd probably like to place this new task
3419 // at the bottom of its stack, but that's a little hard
3420 // to do with the current organization of the code so
3421 // for now we'll just drop it.
3422 taskTop.task.setIntent(r.intent, r.info);
3423 }
3424 if (!addingToTask) {
3425 // We didn't do anything... but it was needed (a.k.a., client
3426 // don't use that intent!) And for paranoia, make
3427 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003428 if (doResume) {
3429 resumeTopActivityLocked(null);
3430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431 return START_TASK_TO_FRONT;
3432 }
3433 }
3434 }
3435 }
3436
3437 //String uri = r.intent.toURI();
3438 //Intent intent2 = new Intent(uri);
3439 //Log.i(TAG, "Given intent: " + r.intent);
3440 //Log.i(TAG, "URI is: " + uri);
3441 //Log.i(TAG, "To intent: " + intent2);
3442
3443 if (r.packageName != null) {
3444 // If the activity being launched is the same as the one currently
3445 // at the top, then we need to check if it should only be launched
3446 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003447 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3448 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003449 if (top.realActivity.equals(r.realActivity)) {
3450 if (top.app != null && top.app.thread != null) {
3451 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3452 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3453 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003454 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003455 // For paranoia, make sure we have correctly
3456 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003457 if (doResume) {
3458 resumeTopActivityLocked(null);
3459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 if (onlyIfNeeded) {
3461 // We don't need to start a new activity, and
3462 // the client said not to do anything if that
3463 // is the case, so this is it!
3464 return START_RETURN_INTENT_TO_CALLER;
3465 }
3466 deliverNewIntentLocked(top, r.intent);
3467 return START_DELIVERED_TO_TOP;
3468 }
3469 }
3470 }
3471 }
3472
3473 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003474 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003475 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003476 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003477 Activity.RESULT_CANCELED, null);
3478 }
3479 return START_CLASS_NOT_FOUND;
3480 }
3481
3482 boolean newTask = false;
3483
3484 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003485 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3487 // todo: should do better management of integers.
3488 mCurTask++;
3489 if (mCurTask <= 0) {
3490 mCurTask = 1;
3491 }
3492 r.task = new TaskRecord(mCurTask, r.info, intent,
3493 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3494 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3495 + " in new task " + r.task);
3496 newTask = true;
3497 addRecentTask(r.task);
3498
3499 } else if (sourceRecord != null) {
3500 if (!addingToTask &&
3501 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3502 // In this case, we are adding the activity to an existing
3503 // task, but the caller has asked to clear that task if the
3504 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003505 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003506 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003508 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003509 deliverNewIntentLocked(top, r.intent);
3510 // For paranoia, make sure we have correctly
3511 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003512 if (doResume) {
3513 resumeTopActivityLocked(null);
3514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003515 return START_DELIVERED_TO_TOP;
3516 }
3517 } else if (!addingToTask &&
3518 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3519 // In this case, we are launching an activity in our own task
3520 // that may already be running somewhere in the history, and
3521 // we want to shuffle it to the front of the stack if so.
3522 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3523 if (where >= 0) {
3524 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003525 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003526 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003527 if (doResume) {
3528 resumeTopActivityLocked(null);
3529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003530 return START_DELIVERED_TO_TOP;
3531 }
3532 }
3533 // An existing activity is starting this new activity, so we want
3534 // to keep the new one in the same task as the one that is starting
3535 // it.
3536 r.task = sourceRecord.task;
3537 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3538 + " in existing task " + r.task);
3539
3540 } else {
3541 // This not being started from an existing activity, and not part
3542 // of a new task... just put it in the top task, though these days
3543 // this case should never happen.
3544 final int N = mHistory.size();
3545 HistoryRecord prev =
3546 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3547 r.task = prev != null
3548 ? prev.task
3549 : new TaskRecord(mCurTask, r.info, intent,
3550 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3551 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3552 + " in new guessed " + r.task);
3553 }
3554 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003555 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003556 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003557 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003558 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003559 return START_SUCCESS;
3560 }
3561
3562 public final int startActivity(IApplicationThread caller,
3563 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3564 int grantedMode, IBinder resultTo,
3565 String resultWho, int requestCode, boolean onlyIfNeeded,
3566 boolean debug) {
3567 // Refuse possible leaked file descriptors
3568 if (intent != null && intent.hasFileDescriptors()) {
3569 throw new IllegalArgumentException("File descriptors passed in Intent");
3570 }
3571
The Android Open Source Project4df24232009-03-05 14:34:35 -08003572 final boolean componentSpecified = intent.getComponent() != null;
3573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003574 // Don't modify the client's object!
3575 intent = new Intent(intent);
3576
3577 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 ActivityInfo aInfo;
3579 try {
3580 ResolveInfo rInfo =
3581 ActivityThread.getPackageManager().resolveIntent(
3582 intent, resolvedType,
3583 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003584 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003585 aInfo = rInfo != null ? rInfo.activityInfo : null;
3586 } catch (RemoteException e) {
3587 aInfo = null;
3588 }
3589
3590 if (aInfo != null) {
3591 // Store the found target back into the intent, because now that
3592 // we have it we never want to do this again. For example, if the
3593 // user navigates back to this point in the history, we should
3594 // always restart the exact same activity.
3595 intent.setComponent(new ComponentName(
3596 aInfo.applicationInfo.packageName, aInfo.name));
3597
3598 // Don't debug things in the system process
3599 if (debug) {
3600 if (!aInfo.processName.equals("system")) {
3601 setDebugApp(aInfo.processName, true, false);
3602 }
3603 }
3604 }
3605
3606 synchronized(this) {
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08003607 int callingPid;
3608 int callingUid;
3609 if (caller == null) {
3610 callingPid = Binder.getCallingPid();
3611 callingUid = Binder.getCallingUid();
3612 } else {
3613 callingPid = callingUid = -1;
3614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003615 final long origId = Binder.clearCallingIdentity();
3616 int res = startActivityLocked(caller, intent, resolvedType,
3617 grantedUriPermissions, grantedMode, aInfo,
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08003618 resultTo, resultWho, requestCode, callingPid, callingUid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003619 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003620 Binder.restoreCallingIdentity(origId);
3621 return res;
3622 }
3623 }
3624
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003625 public int startActivityIntentSender(IApplicationThread caller,
3626 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003627 IBinder resultTo, String resultWho, int requestCode,
3628 int flagsMask, int flagsValues) {
3629 // Refuse possible leaked file descriptors
3630 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3631 throw new IllegalArgumentException("File descriptors passed in Intent");
3632 }
3633
3634 IIntentSender sender = intent.getTarget();
3635 if (!(sender instanceof PendingIntentRecord)) {
3636 throw new IllegalArgumentException("Bad PendingIntent object");
3637 }
3638
3639 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003640
3641 synchronized (this) {
3642 // If this is coming from the currently resumed activity, it is
3643 // effectively saying that app switches are allowed at this point.
3644 if (mResumedActivity != null
3645 && mResumedActivity.info.applicationInfo.uid ==
3646 Binder.getCallingUid()) {
3647 mAppSwitchesAllowedTime = 0;
3648 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003649 }
3650
3651 return pir.sendInner(0, fillInIntent, resolvedType,
3652 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3653 }
3654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003655 public boolean startNextMatchingActivity(IBinder callingActivity,
3656 Intent intent) {
3657 // Refuse possible leaked file descriptors
3658 if (intent != null && intent.hasFileDescriptors() == true) {
3659 throw new IllegalArgumentException("File descriptors passed in Intent");
3660 }
3661
3662 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003663 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003664 if (index < 0) {
3665 return false;
3666 }
3667 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3668 if (r.app == null || r.app.thread == null) {
3669 // The caller is not running... d'oh!
3670 return false;
3671 }
3672 intent = new Intent(intent);
3673 // The caller is not allowed to change the data.
3674 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3675 // And we are resetting to find the next component...
3676 intent.setComponent(null);
3677
3678 ActivityInfo aInfo = null;
3679 try {
3680 List<ResolveInfo> resolves =
3681 ActivityThread.getPackageManager().queryIntentActivities(
3682 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003683 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003684
3685 // Look for the original activity in the list...
3686 final int N = resolves != null ? resolves.size() : 0;
3687 for (int i=0; i<N; i++) {
3688 ResolveInfo rInfo = resolves.get(i);
3689 if (rInfo.activityInfo.packageName.equals(r.packageName)
3690 && rInfo.activityInfo.name.equals(r.info.name)) {
3691 // We found the current one... the next matching is
3692 // after it.
3693 i++;
3694 if (i<N) {
3695 aInfo = resolves.get(i).activityInfo;
3696 }
3697 break;
3698 }
3699 }
3700 } catch (RemoteException e) {
3701 }
3702
3703 if (aInfo == null) {
3704 // Nobody who is next!
3705 return false;
3706 }
3707
3708 intent.setComponent(new ComponentName(
3709 aInfo.applicationInfo.packageName, aInfo.name));
3710 intent.setFlags(intent.getFlags()&~(
3711 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3712 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3713 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3714 Intent.FLAG_ACTIVITY_NEW_TASK));
3715
3716 // Okay now we need to start the new activity, replacing the
3717 // currently running activity. This is a little tricky because
3718 // we want to start the new one as if the current one is finished,
3719 // but not finish the current one first so that there is no flicker.
3720 // And thus...
3721 final boolean wasFinishing = r.finishing;
3722 r.finishing = true;
3723
3724 // Propagate reply information over to the new activity.
3725 final HistoryRecord resultTo = r.resultTo;
3726 final String resultWho = r.resultWho;
3727 final int requestCode = r.requestCode;
3728 r.resultTo = null;
3729 if (resultTo != null) {
3730 resultTo.removeResultsLocked(r, resultWho, requestCode);
3731 }
3732
3733 final long origId = Binder.clearCallingIdentity();
3734 // XXX we are not dealing with propagating grantedUriPermissions...
3735 // those are not yet exposed to user code, so there is no need.
3736 int res = startActivityLocked(r.app.thread, intent,
3737 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003738 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003739 Binder.restoreCallingIdentity(origId);
3740
3741 r.finishing = wasFinishing;
3742 if (res != START_SUCCESS) {
3743 return false;
3744 }
3745 return true;
3746 }
3747 }
3748
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003749 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003750 Intent intent, String resolvedType, IBinder resultTo,
3751 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003752
3753 // This is so super not safe, that only the system (or okay root)
3754 // can do it.
3755 final int callingUid = Binder.getCallingUid();
3756 if (callingUid != 0 && callingUid != Process.myUid()) {
3757 throw new SecurityException(
3758 "startActivityInPackage only available to the system");
3759 }
3760
The Android Open Source Project4df24232009-03-05 14:34:35 -08003761 final boolean componentSpecified = intent.getComponent() != null;
3762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003763 // Don't modify the client's object!
3764 intent = new Intent(intent);
3765
3766 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 ActivityInfo aInfo;
3768 try {
3769 ResolveInfo rInfo =
3770 ActivityThread.getPackageManager().resolveIntent(
3771 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003772 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003773 aInfo = rInfo != null ? rInfo.activityInfo : null;
3774 } catch (RemoteException e) {
3775 aInfo = null;
3776 }
3777
3778 if (aInfo != null) {
3779 // Store the found target back into the intent, because now that
3780 // we have it we never want to do this again. For example, if the
3781 // user navigates back to this point in the history, we should
3782 // always restart the exact same activity.
3783 intent.setComponent(new ComponentName(
3784 aInfo.applicationInfo.packageName, aInfo.name));
3785 }
3786
3787 synchronized(this) {
3788 return startActivityLocked(null, intent, resolvedType,
3789 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003790 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003791 }
3792 }
3793
3794 private final void addRecentTask(TaskRecord task) {
3795 // Remove any existing entries that are the same kind of task.
3796 int N = mRecentTasks.size();
3797 for (int i=0; i<N; i++) {
3798 TaskRecord tr = mRecentTasks.get(i);
3799 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3800 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3801 mRecentTasks.remove(i);
3802 i--;
3803 N--;
3804 if (task.intent == null) {
3805 // If the new recent task we are adding is not fully
3806 // specified, then replace it with the existing recent task.
3807 task = tr;
3808 }
3809 }
3810 }
3811 if (N >= MAX_RECENT_TASKS) {
3812 mRecentTasks.remove(N-1);
3813 }
3814 mRecentTasks.add(0, task);
3815 }
3816
3817 public void setRequestedOrientation(IBinder token,
3818 int requestedOrientation) {
3819 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003820 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003821 if (index < 0) {
3822 return;
3823 }
3824 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3825 final long origId = Binder.clearCallingIdentity();
3826 mWindowManager.setAppOrientation(r, requestedOrientation);
3827 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003828 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003829 r.mayFreezeScreenLocked(r.app) ? r : null);
3830 if (config != null) {
3831 r.frozenBeforeDestroy = true;
3832 if (!updateConfigurationLocked(config, r)) {
3833 resumeTopActivityLocked(null);
3834 }
3835 }
3836 Binder.restoreCallingIdentity(origId);
3837 }
3838 }
3839
3840 public int getRequestedOrientation(IBinder token) {
3841 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003842 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003843 if (index < 0) {
3844 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3845 }
3846 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3847 return mWindowManager.getAppOrientation(r);
3848 }
3849 }
3850
3851 private final void stopActivityLocked(HistoryRecord r) {
3852 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3853 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3854 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3855 if (!r.finishing) {
3856 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3857 "no-history");
3858 }
3859 } else if (r.app != null && r.app.thread != null) {
3860 if (mFocusedActivity == r) {
3861 setFocusedActivityLocked(topRunningActivityLocked(null));
3862 }
3863 r.resumeKeyDispatchingLocked();
3864 try {
3865 r.stopped = false;
3866 r.state = ActivityState.STOPPING;
3867 if (DEBUG_VISBILITY) Log.v(
3868 TAG, "Stopping visible=" + r.visible + " for " + r);
3869 if (!r.visible) {
3870 mWindowManager.setAppVisibility(r, false);
3871 }
3872 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3873 } catch (Exception e) {
3874 // Maybe just ignore exceptions here... if the process
3875 // has crashed, our death notification will clean things
3876 // up.
3877 Log.w(TAG, "Exception thrown during pause", e);
3878 // Just in case, assume it to be stopped.
3879 r.stopped = true;
3880 r.state = ActivityState.STOPPED;
3881 if (r.configDestroy) {
3882 destroyActivityLocked(r, true);
3883 }
3884 }
3885 }
3886 }
3887
3888 /**
3889 * @return Returns true if the activity is being finished, false if for
3890 * some reason it is being left as-is.
3891 */
3892 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3893 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003894 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003895 TAG, "Finishing activity: token=" + token
3896 + ", result=" + resultCode + ", data=" + resultData);
3897
Dianne Hackborn75b03852009-06-12 15:43:26 -07003898 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899 if (index < 0) {
3900 return false;
3901 }
3902 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3903
3904 // Is this the last activity left?
3905 boolean lastActivity = true;
3906 for (int i=mHistory.size()-1; i>=0; i--) {
3907 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3908 if (!p.finishing && p != r) {
3909 lastActivity = false;
3910 break;
3911 }
3912 }
3913
3914 // If this is the last activity, but it is the home activity, then
3915 // just don't finish it.
3916 if (lastActivity) {
3917 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3918 return false;
3919 }
3920 }
3921
3922 finishActivityLocked(r, index, resultCode, resultData, reason);
3923 return true;
3924 }
3925
3926 /**
3927 * @return Returns true if this activity has been removed from the history
3928 * list, or false if it is still in the list and will be removed later.
3929 */
3930 private final boolean finishActivityLocked(HistoryRecord r, int index,
3931 int resultCode, Intent resultData, String reason) {
3932 if (r.finishing) {
3933 Log.w(TAG, "Duplicate finish request for " + r);
3934 return false;
3935 }
3936
3937 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003938 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003939 System.identityHashCode(r),
3940 r.task.taskId, r.shortComponentName, reason);
3941 r.task.numActivities--;
3942 if (r.frontOfTask && index < (mHistory.size()-1)) {
3943 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3944 if (next.task == r.task) {
3945 next.frontOfTask = true;
3946 }
3947 }
3948
3949 r.pauseKeyDispatchingLocked();
3950 if (mFocusedActivity == r) {
3951 setFocusedActivityLocked(topRunningActivityLocked(null));
3952 }
3953
3954 // send the result
3955 HistoryRecord resultTo = r.resultTo;
3956 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003957 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3958 + " who=" + r.resultWho + " req=" + r.requestCode
3959 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003960 if (r.info.applicationInfo.uid > 0) {
3961 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3962 r.packageName, resultData, r);
3963 }
3964 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3965 resultData);
3966 r.resultTo = null;
3967 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003968 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003969
3970 // Make sure this HistoryRecord is not holding on to other resources,
3971 // because clients have remote IPC references to this object so we
3972 // can't assume that will go away and want to avoid circular IPC refs.
3973 r.results = null;
3974 r.pendingResults = null;
3975 r.newIntents = null;
3976 r.icicle = null;
3977
3978 if (mPendingThumbnails.size() > 0) {
3979 // There are clients waiting to receive thumbnails so, in case
3980 // this is an activity that someone is waiting for, add it
3981 // to the pending list so we can correctly update the clients.
3982 mCancelledThumbnails.add(r);
3983 }
3984
3985 if (mResumedActivity == r) {
3986 boolean endTask = index <= 0
3987 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3988 if (DEBUG_TRANSITION) Log.v(TAG,
3989 "Prepare close transition: finishing " + r);
3990 mWindowManager.prepareAppTransition(endTask
3991 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3992 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3993
3994 // Tell window manager to prepare for this one to be removed.
3995 mWindowManager.setAppVisibility(r, false);
3996
3997 if (mPausingActivity == null) {
3998 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3999 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4000 startPausingLocked(false, false);
4001 }
4002
4003 } else if (r.state != ActivityState.PAUSING) {
4004 // If the activity is PAUSING, we will complete the finish once
4005 // it is done pausing; else we can just directly finish it here.
4006 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4007 return finishCurrentActivityLocked(r, index,
4008 FINISH_AFTER_PAUSE) == null;
4009 } else {
4010 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4011 }
4012
4013 return false;
4014 }
4015
4016 private static final int FINISH_IMMEDIATELY = 0;
4017 private static final int FINISH_AFTER_PAUSE = 1;
4018 private static final int FINISH_AFTER_VISIBLE = 2;
4019
4020 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4021 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004022 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004023 if (index < 0) {
4024 return null;
4025 }
4026
4027 return finishCurrentActivityLocked(r, index, mode);
4028 }
4029
4030 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4031 int index, int mode) {
4032 // First things first: if this activity is currently visible,
4033 // and the resumed activity is not yet visible, then hold off on
4034 // finishing until the resumed one becomes visible.
4035 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4036 if (!mStoppingActivities.contains(r)) {
4037 mStoppingActivities.add(r);
4038 if (mStoppingActivities.size() > 3) {
4039 // If we already have a few activities waiting to stop,
4040 // then give up on things going idle and start clearing
4041 // them out.
4042 Message msg = Message.obtain();
4043 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4044 mHandler.sendMessage(msg);
4045 }
4046 }
4047 r.state = ActivityState.STOPPING;
4048 updateOomAdjLocked();
4049 return r;
4050 }
4051
4052 // make sure the record is cleaned out of other places.
4053 mStoppingActivities.remove(r);
4054 mWaitingVisibleActivities.remove(r);
4055 if (mResumedActivity == r) {
4056 mResumedActivity = null;
4057 }
4058 final ActivityState prevState = r.state;
4059 r.state = ActivityState.FINISHING;
4060
4061 if (mode == FINISH_IMMEDIATELY
4062 || prevState == ActivityState.STOPPED
4063 || prevState == ActivityState.INITIALIZING) {
4064 // If this activity is already stopped, we can just finish
4065 // it right now.
4066 return destroyActivityLocked(r, true) ? null : r;
4067 } else {
4068 // Need to go through the full pause cycle to get this
4069 // activity into the stopped state and then finish it.
4070 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4071 mFinishingActivities.add(r);
4072 resumeTopActivityLocked(null);
4073 }
4074 return r;
4075 }
4076
4077 /**
4078 * This is the internal entry point for handling Activity.finish().
4079 *
4080 * @param token The Binder token referencing the Activity we want to finish.
4081 * @param resultCode Result code, if any, from this Activity.
4082 * @param resultData Result data (Intent), if any, from this Activity.
4083 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004084 * @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 -08004085 */
4086 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4087 // Refuse possible leaked file descriptors
4088 if (resultData != null && resultData.hasFileDescriptors() == true) {
4089 throw new IllegalArgumentException("File descriptors passed in Intent");
4090 }
4091
4092 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004093 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004094 // Find the first activity that is not finishing.
4095 HistoryRecord next = topRunningActivityLocked(token, 0);
4096 if (next != null) {
4097 // ask watcher if this is allowed
4098 boolean resumeOK = true;
4099 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004100 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004101 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004102 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004103 }
4104
4105 if (!resumeOK) {
4106 return false;
4107 }
4108 }
4109 }
4110 final long origId = Binder.clearCallingIdentity();
4111 boolean res = requestFinishActivityLocked(token, resultCode,
4112 resultData, "app-request");
4113 Binder.restoreCallingIdentity(origId);
4114 return res;
4115 }
4116 }
4117
4118 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4119 String resultWho, int requestCode, int resultCode, Intent data) {
4120
4121 if (callingUid > 0) {
4122 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4123 data, r);
4124 }
4125
The Android Open Source Project10592532009-03-18 17:39:46 -07004126 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4127 + " : who=" + resultWho + " req=" + requestCode
4128 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004129 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4130 try {
4131 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4132 list.add(new ResultInfo(resultWho, requestCode,
4133 resultCode, data));
4134 r.app.thread.scheduleSendResult(r, list);
4135 return;
4136 } catch (Exception e) {
4137 Log.w(TAG, "Exception thrown sending result to " + r, e);
4138 }
4139 }
4140
4141 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4142 }
4143
4144 public final void finishSubActivity(IBinder token, String resultWho,
4145 int requestCode) {
4146 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004147 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004148 if (index < 0) {
4149 return;
4150 }
4151 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4152
4153 final long origId = Binder.clearCallingIdentity();
4154
4155 int i;
4156 for (i=mHistory.size()-1; i>=0; i--) {
4157 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4158 if (r.resultTo == self && r.requestCode == requestCode) {
4159 if ((r.resultWho == null && resultWho == null) ||
4160 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4161 finishActivityLocked(r, i,
4162 Activity.RESULT_CANCELED, null, "request-sub");
4163 }
4164 }
4165 }
4166
4167 Binder.restoreCallingIdentity(origId);
4168 }
4169 }
4170
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004171 public void overridePendingTransition(IBinder token, String packageName,
4172 int enterAnim, int exitAnim) {
4173 synchronized(this) {
4174 int index = indexOfTokenLocked(token);
4175 if (index < 0) {
4176 return;
4177 }
4178 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4179
4180 final long origId = Binder.clearCallingIdentity();
4181
4182 if (self.state == ActivityState.RESUMED
4183 || self.state == ActivityState.PAUSING) {
4184 mWindowManager.overridePendingAppTransition(packageName,
4185 enterAnim, exitAnim);
4186 }
4187
4188 Binder.restoreCallingIdentity(origId);
4189 }
4190 }
4191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004192 /**
4193 * Perform clean-up of service connections in an activity record.
4194 */
4195 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4196 // Throw away any services that have been bound by this activity.
4197 if (r.connections != null) {
4198 Iterator<ConnectionRecord> it = r.connections.iterator();
4199 while (it.hasNext()) {
4200 ConnectionRecord c = it.next();
4201 removeConnectionLocked(c, null, r);
4202 }
4203 r.connections = null;
4204 }
4205 }
4206
4207 /**
4208 * Perform the common clean-up of an activity record. This is called both
4209 * as part of destroyActivityLocked() (when destroying the client-side
4210 * representation) and cleaning things up as a result of its hosting
4211 * processing going away, in which case there is no remaining client-side
4212 * state to destroy so only the cleanup here is needed.
4213 */
4214 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4215 if (mResumedActivity == r) {
4216 mResumedActivity = null;
4217 }
4218 if (mFocusedActivity == r) {
4219 mFocusedActivity = null;
4220 }
4221
4222 r.configDestroy = false;
4223 r.frozenBeforeDestroy = false;
4224
4225 // Make sure this record is no longer in the pending finishes list.
4226 // This could happen, for example, if we are trimming activities
4227 // down to the max limit while they are still waiting to finish.
4228 mFinishingActivities.remove(r);
4229 mWaitingVisibleActivities.remove(r);
4230
4231 // Remove any pending results.
4232 if (r.finishing && r.pendingResults != null) {
4233 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4234 PendingIntentRecord rec = apr.get();
4235 if (rec != null) {
4236 cancelIntentSenderLocked(rec, false);
4237 }
4238 }
4239 r.pendingResults = null;
4240 }
4241
4242 if (cleanServices) {
4243 cleanUpActivityServicesLocked(r);
4244 }
4245
4246 if (mPendingThumbnails.size() > 0) {
4247 // There are clients waiting to receive thumbnails so, in case
4248 // this is an activity that someone is waiting for, add it
4249 // to the pending list so we can correctly update the clients.
4250 mCancelledThumbnails.add(r);
4251 }
4252
4253 // Get rid of any pending idle timeouts.
4254 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4255 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4256 }
4257
4258 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4259 if (r.state != ActivityState.DESTROYED) {
4260 mHistory.remove(r);
4261 r.inHistory = false;
4262 r.state = ActivityState.DESTROYED;
4263 mWindowManager.removeAppToken(r);
4264 if (VALIDATE_TOKENS) {
4265 mWindowManager.validateAppTokens(mHistory);
4266 }
4267 cleanUpActivityServicesLocked(r);
4268 removeActivityUriPermissionsLocked(r);
4269 }
4270 }
4271
4272 /**
4273 * Destroy the current CLIENT SIDE instance of an activity. This may be
4274 * called both when actually finishing an activity, or when performing
4275 * a configuration switch where we destroy the current client-side object
4276 * but then create a new client-side object for this same HistoryRecord.
4277 */
4278 private final boolean destroyActivityLocked(HistoryRecord r,
4279 boolean removeFromApp) {
4280 if (DEBUG_SWITCH) Log.v(
4281 TAG, "Removing activity: token=" + r
4282 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004283 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004284 System.identityHashCode(r),
4285 r.task.taskId, r.shortComponentName);
4286
4287 boolean removedFromHistory = false;
4288
4289 cleanUpActivityLocked(r, false);
4290
Dianne Hackborn03abb812010-01-04 18:43:19 -08004291 final boolean hadApp = r.app != null;
4292
4293 if (hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004294 if (removeFromApp) {
4295 int idx = r.app.activities.indexOf(r);
4296 if (idx >= 0) {
4297 r.app.activities.remove(idx);
4298 }
4299 if (r.persistent) {
4300 decPersistentCountLocked(r.app);
4301 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004302 if (r.app.activities.size() == 0) {
4303 // No longer have activities, so update location in
4304 // LRU list.
4305 updateLruProcessLocked(r.app, true, false);
4306 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004307 }
4308
4309 boolean skipDestroy = false;
4310
4311 try {
4312 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4313 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4314 r.configChangeFlags);
4315 } catch (Exception e) {
4316 // We can just ignore exceptions here... if the process
4317 // has crashed, our death notification will clean things
4318 // up.
4319 //Log.w(TAG, "Exception thrown during finish", e);
4320 if (r.finishing) {
4321 removeActivityFromHistoryLocked(r);
4322 removedFromHistory = true;
4323 skipDestroy = true;
4324 }
4325 }
4326
4327 r.app = null;
4328 r.nowVisible = false;
4329
4330 if (r.finishing && !skipDestroy) {
4331 r.state = ActivityState.DESTROYING;
4332 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4333 msg.obj = r;
4334 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4335 } else {
4336 r.state = ActivityState.DESTROYED;
4337 }
4338 } else {
4339 // remove this record from the history.
4340 if (r.finishing) {
4341 removeActivityFromHistoryLocked(r);
4342 removedFromHistory = true;
4343 } else {
4344 r.state = ActivityState.DESTROYED;
4345 }
4346 }
4347
4348 r.configChangeFlags = 0;
4349
Dianne Hackborn03abb812010-01-04 18:43:19 -08004350 if (!mLRUActivities.remove(r) && hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004351 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4352 }
4353
4354 return removedFromHistory;
4355 }
4356
Dianne Hackborn03abb812010-01-04 18:43:19 -08004357 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004358 int i = list.size();
4359 if (localLOGV) Log.v(
4360 TAG, "Removing app " + app + " from list " + list
4361 + " with " + i + " entries");
4362 while (i > 0) {
4363 i--;
4364 HistoryRecord r = (HistoryRecord)list.get(i);
4365 if (localLOGV) Log.v(
4366 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4367 if (r.app == app) {
4368 if (localLOGV) Log.v(TAG, "Removing this entry!");
4369 list.remove(i);
4370 }
4371 }
4372 }
4373
4374 /**
4375 * Main function for removing an existing process from the activity manager
4376 * as a result of that process going away. Clears out all connections
4377 * to the process.
4378 */
4379 private final void handleAppDiedLocked(ProcessRecord app,
4380 boolean restarting) {
4381 cleanUpApplicationRecordLocked(app, restarting, -1);
4382 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004383 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004384 }
4385
4386 // Just in case...
4387 if (mPausingActivity != null && mPausingActivity.app == app) {
4388 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4389 mPausingActivity = null;
4390 }
4391 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4392 mLastPausedActivity = null;
4393 }
4394
4395 // Remove this application's activities from active lists.
4396 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4397 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4398 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4399 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4400
4401 boolean atTop = true;
4402 boolean hasVisibleActivities = false;
4403
4404 // Clean out the history list.
4405 int i = mHistory.size();
4406 if (localLOGV) Log.v(
4407 TAG, "Removing app " + app + " from history with " + i + " entries");
4408 while (i > 0) {
4409 i--;
4410 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4411 if (localLOGV) Log.v(
4412 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4413 if (r.app == app) {
4414 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4415 if (localLOGV) Log.v(
4416 TAG, "Removing this entry! frozen=" + r.haveState
4417 + " finishing=" + r.finishing);
4418 mHistory.remove(i);
4419
4420 r.inHistory = false;
4421 mWindowManager.removeAppToken(r);
4422 if (VALIDATE_TOKENS) {
4423 mWindowManager.validateAppTokens(mHistory);
4424 }
4425 removeActivityUriPermissionsLocked(r);
4426
4427 } else {
4428 // We have the current state for this activity, so
4429 // it can be restarted later when needed.
4430 if (localLOGV) Log.v(
4431 TAG, "Keeping entry, setting app to null");
4432 if (r.visible) {
4433 hasVisibleActivities = true;
4434 }
4435 r.app = null;
4436 r.nowVisible = false;
4437 if (!r.haveState) {
4438 r.icicle = null;
4439 }
4440 }
4441
4442 cleanUpActivityLocked(r, true);
4443 r.state = ActivityState.STOPPED;
4444 }
4445 atTop = false;
4446 }
4447
4448 app.activities.clear();
4449
4450 if (app.instrumentationClass != null) {
4451 Log.w(TAG, "Crash of app " + app.processName
4452 + " running instrumentation " + app.instrumentationClass);
4453 Bundle info = new Bundle();
4454 info.putString("shortMsg", "Process crashed.");
4455 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4456 }
4457
4458 if (!restarting) {
4459 if (!resumeTopActivityLocked(null)) {
4460 // If there was nothing to resume, and we are not already
4461 // restarting this process, but there is a visible activity that
4462 // is hosted by the process... then make sure all visible
4463 // activities are running, taking care of restarting this
4464 // process.
4465 if (hasVisibleActivities) {
4466 ensureActivitiesVisibleLocked(null, 0);
4467 }
4468 }
4469 }
4470 }
4471
4472 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4473 IBinder threadBinder = thread.asBinder();
4474
4475 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004476 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4477 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004478 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4479 return i;
4480 }
4481 }
4482 return -1;
4483 }
4484
4485 private final ProcessRecord getRecordForAppLocked(
4486 IApplicationThread thread) {
4487 if (thread == null) {
4488 return null;
4489 }
4490
4491 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004492 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004493 }
4494
4495 private final void appDiedLocked(ProcessRecord app, int pid,
4496 IApplicationThread thread) {
4497
4498 mProcDeaths[0]++;
4499
4500 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4501 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4502 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004503 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004504 if (localLOGV) Log.v(
4505 TAG, "Dying app: " + app + ", pid: " + pid
4506 + ", thread: " + thread.asBinder());
4507 boolean doLowMem = app.instrumentationClass == null;
4508 handleAppDiedLocked(app, false);
4509
4510 if (doLowMem) {
4511 // If there are no longer any background processes running,
4512 // and the app that died was not running instrumentation,
4513 // then tell everyone we are now low on memory.
4514 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004515 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4516 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004517 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4518 haveBg = true;
4519 break;
4520 }
4521 }
4522
4523 if (!haveBg) {
4524 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004525 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004526 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004527 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4528 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004529 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004530 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4531 // The low memory report is overriding any current
4532 // state for a GC request. Make sure to do
4533 // visible/foreground processes first.
4534 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4535 rec.lastRequestedGc = 0;
4536 } else {
4537 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004538 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004539 rec.reportLowMemory = true;
4540 rec.lastLowMemory = now;
4541 mProcessesToGc.remove(rec);
4542 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004543 }
4544 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004545 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004546 }
4547 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004548 } else if (DEBUG_PROCESSES) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004549 Log.d(TAG, "Received spurious death notification for thread "
4550 + thread.asBinder());
4551 }
4552 }
4553
Dan Egnor42471dd2010-01-07 17:25:22 -08004554 /**
4555 * If a stack trace dump file is configured, dump process stack traces.
4556 * @param pids of dalvik VM processes to dump stack traces for
4557 * @return file containing stack traces, or null if no dump file is configured
4558 */
4559 private static File dumpStackTraces(ArrayList<Integer> pids) {
4560 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4561 if (tracesPath == null || tracesPath.length() == 0) {
4562 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004563 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004564
4565 File tracesFile = new File(tracesPath);
4566 try {
4567 File tracesDir = tracesFile.getParentFile();
4568 if (!tracesDir.exists()) tracesFile.mkdirs();
4569 FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
4570
4571 if (tracesFile.exists()) tracesFile.delete();
4572 tracesFile.createNewFile();
4573 FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
4574 } catch (IOException e) {
4575 Log.w(TAG, "Unable to prepare ANR traces file: " + tracesPath, e);
4576 return null;
4577 }
4578
4579 // Use a FileObserver to detect when traces finish writing.
4580 // The order of traces is considered important to maintain for legibility.
4581 FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
4582 public synchronized void onEvent(int event, String path) { notify(); }
4583 };
4584
4585 try {
4586 observer.startWatching();
4587 int num = pids.size();
4588 for (int i = 0; i < num; i++) {
4589 synchronized (observer) {
4590 Process.sendSignal(pids.get(i), Process.SIGNAL_QUIT);
4591 observer.wait(200); // Wait for write-close, give up after 200msec
4592 }
4593 }
4594 } catch (InterruptedException e) {
4595 Log.wtf(TAG, e);
4596 } finally {
4597 observer.stopWatching();
4598 }
4599
4600 return tracesFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004601 }
4602
Dan Egnor42471dd2010-01-07 17:25:22 -08004603 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4604 HistoryRecord parent, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004605 if (app.notResponding || app.crashing) {
4606 return;
4607 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004609 // Log the ANR to the event log.
Dan Egnor2780e732010-01-22 14:47:35 -08004610 EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
4611 annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004612
Dan Egnor42471dd2010-01-07 17:25:22 -08004613 // Dump thread traces as quickly as we can, starting with "interesting" processes.
4614 ArrayList<Integer> pids = new ArrayList<Integer>(20);
4615 pids.add(app.pid);
4616
4617 int parentPid = app.pid;
4618 if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
4619 if (parentPid != app.pid) pids.add(parentPid);
4620
4621 if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
4622
4623 for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
4624 ProcessRecord r = mLruProcesses.get(i);
4625 if (r != null && r.thread != null) {
4626 int pid = r.pid;
4627 if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004628 }
4629 }
4630
Dan Egnor42471dd2010-01-07 17:25:22 -08004631 File tracesFile = dumpStackTraces(pids);
4632
4633 // Log the ANR to the main log.
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004634 StringBuilder info = mStringBuilder;
4635 info.setLength(0);
Dan Egnor42471dd2010-01-07 17:25:22 -08004636 info.append("ANR in ").append(app.processName);
4637 if (activity != null && activity.shortComponentName != null) {
4638 info.append(" (").append(activity.shortComponentName).append(")");
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004639 }
Eric Rowe6f4f6192010-02-17 18:29:04 -08004640 info.append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004641 if (annotation != null) {
Eric Rowe6f4f6192010-02-17 18:29:04 -08004642 info.append("Reason: ").append(annotation).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004643 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004644 if (parent != null && parent != activity) {
Eric Rowe6f4f6192010-02-17 18:29:04 -08004645 info.append("Parent: ").append(parent.shortComponentName).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004647
Dan Egnor42471dd2010-01-07 17:25:22 -08004648 String cpuInfo = null;
4649 if (MONITOR_CPU_USAGE) {
4650 updateCpuStatsNow();
4651 synchronized (mProcessStatsThread) { cpuInfo = mProcessStats.printCurrentState(); }
4652 info.append(cpuInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004653 }
4654
Dan Egnor42471dd2010-01-07 17:25:22 -08004655 Log.e(TAG, info.toString());
4656 if (tracesFile == null) {
4657 // There is no trace file, so dump (only) the alleged culprit's threads to the log
4658 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4659 }
4660
4661 addErrorToDropBox("anr", app, activity, parent, annotation, cpuInfo, tracesFile, null);
4662
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004663 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004664 try {
Dan Egnor42471dd2010-01-07 17:25:22 -08004665 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
4666 int res = mController.appNotResponding(app.processName, app.pid, info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004667 if (res != 0) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004668 if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
4669 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004670 }
4671 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004672 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004673 }
4674 }
4675
Dan Egnor42471dd2010-01-07 17:25:22 -08004676 // Unless configured otherwise, swallow ANRs in background processes & kill the process.
4677 boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
4678 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
4679 if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
4680 Process.killProcess(app.pid);
4681 return;
4682 }
4683
4684 // Set the app's notResponding state, and look up the errorReportReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004685 makeAppNotRespondingLocked(app,
4686 activity != null ? activity.shortComponentName : null,
4687 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004688 info.toString());
Dan Egnor42471dd2010-01-07 17:25:22 -08004689
4690 // Bring up the infamous App Not Responding dialog
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004691 Message msg = Message.obtain();
4692 HashMap map = new HashMap();
4693 msg.what = SHOW_NOT_RESPONDING_MSG;
4694 msg.obj = map;
4695 map.put("app", app);
4696 if (activity != null) {
4697 map.put("activity", activity);
4698 }
4699
4700 mHandler.sendMessage(msg);
4701 return;
4702 }
4703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004704 private final void decPersistentCountLocked(ProcessRecord app)
4705 {
4706 app.persistentActivities--;
4707 if (app.persistentActivities > 0) {
4708 // Still more of 'em...
4709 return;
4710 }
4711 if (app.persistent) {
4712 // Ah, but the application itself is persistent. Whatever!
4713 return;
4714 }
4715
4716 // App is no longer persistent... make sure it and the ones
4717 // following it in the LRU list have the correc oom_adj.
4718 updateOomAdjLocked();
4719 }
4720
4721 public void setPersistent(IBinder token, boolean isPersistent) {
4722 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4723 != PackageManager.PERMISSION_GRANTED) {
4724 String msg = "Permission Denial: setPersistent() from pid="
4725 + Binder.getCallingPid()
4726 + ", uid=" + Binder.getCallingUid()
4727 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4728 Log.w(TAG, msg);
4729 throw new SecurityException(msg);
4730 }
4731
4732 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004733 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004734 if (index < 0) {
4735 return;
4736 }
4737 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4738 ProcessRecord app = r.app;
4739
4740 if (localLOGV) Log.v(
4741 TAG, "Setting persistence " + isPersistent + ": " + r);
4742
4743 if (isPersistent) {
4744 if (r.persistent) {
4745 // Okay okay, I heard you already!
4746 if (localLOGV) Log.v(TAG, "Already persistent!");
4747 return;
4748 }
4749 r.persistent = true;
4750 app.persistentActivities++;
4751 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4752 if (app.persistentActivities > 1) {
4753 // We aren't the first...
4754 if (localLOGV) Log.v(TAG, "Not the first!");
4755 return;
4756 }
4757 if (app.persistent) {
4758 // This would be redundant.
4759 if (localLOGV) Log.v(TAG, "App is persistent!");
4760 return;
4761 }
4762
4763 // App is now persistent... make sure it and the ones
4764 // following it now have the correct oom_adj.
4765 final long origId = Binder.clearCallingIdentity();
4766 updateOomAdjLocked();
4767 Binder.restoreCallingIdentity(origId);
4768
4769 } else {
4770 if (!r.persistent) {
4771 // Okay okay, I heard you already!
4772 return;
4773 }
4774 r.persistent = false;
4775 final long origId = Binder.clearCallingIdentity();
4776 decPersistentCountLocked(app);
4777 Binder.restoreCallingIdentity(origId);
4778
4779 }
4780 }
4781 }
4782
4783 public boolean clearApplicationUserData(final String packageName,
4784 final IPackageDataObserver observer) {
4785 int uid = Binder.getCallingUid();
4786 int pid = Binder.getCallingPid();
4787 long callingId = Binder.clearCallingIdentity();
4788 try {
4789 IPackageManager pm = ActivityThread.getPackageManager();
4790 int pkgUid = -1;
4791 synchronized(this) {
4792 try {
4793 pkgUid = pm.getPackageUid(packageName);
4794 } catch (RemoteException e) {
4795 }
4796 if (pkgUid == -1) {
4797 Log.w(TAG, "Invalid packageName:" + packageName);
4798 return false;
4799 }
4800 if (uid == pkgUid || checkComponentPermission(
4801 android.Manifest.permission.CLEAR_APP_USER_DATA,
4802 pid, uid, -1)
4803 == PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08004804 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004805 } else {
4806 throw new SecurityException(pid+" does not have permission:"+
4807 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4808 "for process:"+packageName);
4809 }
4810 }
4811
4812 try {
4813 //clear application user data
4814 pm.clearApplicationUserData(packageName, observer);
4815 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4816 Uri.fromParts("package", packageName, null));
4817 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4818 broadcastIntentLocked(null, null, intent,
4819 null, null, 0, null, null, null,
4820 false, false, MY_PID, Process.SYSTEM_UID);
4821 } catch (RemoteException e) {
4822 }
4823 } finally {
4824 Binder.restoreCallingIdentity(callingId);
4825 }
4826 return true;
4827 }
4828
Dianne Hackborn03abb812010-01-04 18:43:19 -08004829 public void killBackgroundProcesses(final String packageName) {
4830 if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
4831 != PackageManager.PERMISSION_GRANTED &&
4832 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4833 != PackageManager.PERMISSION_GRANTED) {
4834 String msg = "Permission Denial: killBackgroundProcesses() from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004835 + Binder.getCallingPid()
4836 + ", uid=" + Binder.getCallingUid()
Dianne Hackborn03abb812010-01-04 18:43:19 -08004837 + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004838 Log.w(TAG, msg);
4839 throw new SecurityException(msg);
4840 }
4841
4842 long callingId = Binder.clearCallingIdentity();
4843 try {
4844 IPackageManager pm = ActivityThread.getPackageManager();
4845 int pkgUid = -1;
4846 synchronized(this) {
4847 try {
4848 pkgUid = pm.getPackageUid(packageName);
4849 } catch (RemoteException e) {
4850 }
4851 if (pkgUid == -1) {
4852 Log.w(TAG, "Invalid packageName: " + packageName);
4853 return;
4854 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004855 killPackageProcessesLocked(packageName, pkgUid,
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004856 SECONDARY_SERVER_ADJ, false, true);
Dianne Hackborn03abb812010-01-04 18:43:19 -08004857 }
4858 } finally {
4859 Binder.restoreCallingIdentity(callingId);
4860 }
4861 }
4862
4863 public void forceStopPackage(final String packageName) {
4864 if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
4865 != PackageManager.PERMISSION_GRANTED) {
4866 String msg = "Permission Denial: forceStopPackage() from pid="
4867 + Binder.getCallingPid()
4868 + ", uid=" + Binder.getCallingUid()
4869 + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
4870 Log.w(TAG, msg);
4871 throw new SecurityException(msg);
4872 }
4873
4874 long callingId = Binder.clearCallingIdentity();
4875 try {
4876 IPackageManager pm = ActivityThread.getPackageManager();
4877 int pkgUid = -1;
4878 synchronized(this) {
4879 try {
4880 pkgUid = pm.getPackageUid(packageName);
4881 } catch (RemoteException e) {
4882 }
4883 if (pkgUid == -1) {
4884 Log.w(TAG, "Invalid packageName: " + packageName);
4885 return;
4886 }
4887 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004888 }
4889 } finally {
4890 Binder.restoreCallingIdentity(callingId);
4891 }
4892 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004893
4894 /*
4895 * The pkg name and uid have to be specified.
4896 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4897 */
4898 public void killApplicationWithUid(String pkg, int uid) {
4899 if (pkg == null) {
4900 return;
4901 }
4902 // Make sure the uid is valid.
4903 if (uid < 0) {
4904 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4905 return;
4906 }
4907 int callerUid = Binder.getCallingUid();
4908 // Only the system server can kill an application
4909 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004910 // Post an aysnc message to kill the application
4911 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4912 msg.arg1 = uid;
4913 msg.arg2 = 0;
4914 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004915 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004916 } else {
4917 throw new SecurityException(callerUid + " cannot kill pkg: " +
4918 pkg);
4919 }
4920 }
4921
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004922 public void closeSystemDialogs(String reason) {
4923 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4924 if (reason != null) {
4925 intent.putExtra("reason", reason);
4926 }
4927
4928 final int uid = Binder.getCallingUid();
4929 final long origId = Binder.clearCallingIdentity();
4930 synchronized (this) {
4931 int i = mWatchers.beginBroadcast();
4932 while (i > 0) {
4933 i--;
4934 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4935 if (w != null) {
4936 try {
4937 w.closingSystemDialogs(reason);
4938 } catch (RemoteException e) {
4939 }
4940 }
4941 }
4942 mWatchers.finishBroadcast();
4943
Dianne Hackbornffa42482009-09-23 22:20:11 -07004944 mWindowManager.closeSystemDialogs(reason);
4945
4946 for (i=mHistory.size()-1; i>=0; i--) {
4947 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4948 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4949 finishActivityLocked(r, i,
4950 Activity.RESULT_CANCELED, null, "close-sys");
4951 }
4952 }
4953
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004954 broadcastIntentLocked(null, null, intent, null,
4955 null, 0, null, null, null, false, false, -1, uid);
4956 }
4957 Binder.restoreCallingIdentity(origId);
4958 }
4959
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004960 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004961 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004962 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4963 for (int i=pids.length-1; i>=0; i--) {
4964 infos[i] = new Debug.MemoryInfo();
4965 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004966 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004967 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004968 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004969
4970 public void killApplicationProcess(String processName, int uid) {
4971 if (processName == null) {
4972 return;
4973 }
4974
4975 int callerUid = Binder.getCallingUid();
4976 // Only the system server can kill an application
4977 if (callerUid == Process.SYSTEM_UID) {
4978 synchronized (this) {
4979 ProcessRecord app = getProcessRecordLocked(processName, uid);
4980 if (app != null) {
4981 try {
4982 app.thread.scheduleSuicide();
4983 } catch (RemoteException e) {
4984 // If the other end already died, then our work here is done.
4985 }
4986 } else {
4987 Log.w(TAG, "Process/uid not found attempting kill of "
4988 + processName + " / " + uid);
4989 }
4990 }
4991 } else {
4992 throw new SecurityException(callerUid + " cannot kill app process: " +
4993 processName);
4994 }
4995 }
4996
Dianne Hackborn03abb812010-01-04 18:43:19 -08004997 private void forceStopPackageLocked(final String packageName, int uid) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004998 forceStopPackageLocked(packageName, uid, false, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004999 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5000 Uri.fromParts("package", packageName, null));
5001 intent.putExtra(Intent.EXTRA_UID, uid);
5002 broadcastIntentLocked(null, null, intent,
5003 null, null, 0, null, null, null,
5004 false, false, MY_PID, Process.SYSTEM_UID);
5005 }
5006
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005007 private final boolean killPackageProcessesLocked(String packageName, int uid,
5008 int minOomAdj, boolean callerWillRestart, boolean doit) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005009 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005010
Dianne Hackborn03abb812010-01-04 18:43:19 -08005011 // Remove all processes this package may have touched: all with the
5012 // same UID (except for the system or root user), and all whose name
5013 // matches the package name.
5014 final String procNamePrefix = packageName + ":";
5015 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5016 final int NA = apps.size();
5017 for (int ia=0; ia<NA; ia++) {
5018 ProcessRecord app = apps.valueAt(ia);
5019 if (app.removed) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005020 if (doit) {
5021 procs.add(app);
5022 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08005023 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5024 || app.processName.equals(packageName)
5025 || app.processName.startsWith(procNamePrefix)) {
5026 if (app.setAdj >= minOomAdj) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005027 if (!doit) {
5028 return true;
5029 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08005030 app.removed = true;
5031 procs.add(app);
5032 }
5033 }
5034 }
5035 }
5036
5037 int N = procs.size();
5038 for (int i=0; i<N; i++) {
5039 removeProcessLocked(procs.get(i), callerWillRestart);
5040 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005041 return N > 0;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005042 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005043
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005044 private final boolean forceStopPackageLocked(String name, int uid,
5045 boolean callerWillRestart, boolean purgeCache, boolean doit) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005046 int i, N;
5047
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005048 if (uid < 0) {
5049 try {
5050 uid = ActivityThread.getPackageManager().getPackageUid(name);
5051 } catch (RemoteException e) {
5052 }
5053 }
5054
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005055 if (doit) {
5056 Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
Dianne Hackborn03abb812010-01-04 18:43:19 -08005057
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005058 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5059 while (badApps.hasNext()) {
5060 SparseArray<Long> ba = badApps.next();
5061 if (ba.get(uid) != null) {
5062 badApps.remove();
5063 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005064 }
5065 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005066
5067 boolean didSomething = killPackageProcessesLocked(name, uid, -100,
5068 callerWillRestart, doit);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005069
5070 for (i=mHistory.size()-1; i>=0; i--) {
5071 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5072 if (r.packageName.equals(name)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005073 if (!doit) {
5074 return true;
5075 }
5076 didSomething = true;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005077 Log.i(TAG, " Force finishing activity " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005078 if (r.app != null) {
5079 r.app.removed = true;
5080 }
5081 r.app = null;
5082 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5083 }
5084 }
5085
5086 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5087 for (ServiceRecord service : mServices.values()) {
5088 if (service.packageName.equals(name)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005089 if (!doit) {
5090 return true;
5091 }
5092 didSomething = true;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005093 Log.i(TAG, " Force stopping service " + service);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005094 if (service.app != null) {
5095 service.app.removed = true;
5096 }
5097 service.app = null;
5098 services.add(service);
5099 }
5100 }
5101
5102 N = services.size();
5103 for (i=0; i<N; i++) {
5104 bringDownServiceLocked(services.get(i), true);
5105 }
5106
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005107 if (doit) {
5108 if (purgeCache) {
5109 AttributeCache ac = AttributeCache.instance();
5110 if (ac != null) {
5111 ac.removePackage(name);
5112 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005113 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005114 resumeTopActivityLocked(null);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005115 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005116
5117 return didSomething;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005118 }
5119
5120 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5121 final String name = app.processName;
5122 final int uid = app.info.uid;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005123 if (DEBUG_PROCESSES) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005124 TAG, "Force removing process " + app + " (" + name
5125 + "/" + uid + ")");
5126
5127 mProcessNames.remove(name, uid);
5128 boolean needRestart = false;
5129 if (app.pid > 0 && app.pid != MY_PID) {
5130 int pid = app.pid;
5131 synchronized (mPidsSelfLocked) {
5132 mPidsSelfLocked.remove(pid);
5133 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5134 }
5135 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005136 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005137 Process.killProcess(pid);
5138
5139 if (app.persistent) {
5140 if (!callerWillRestart) {
5141 addAppLocked(app.info);
5142 } else {
5143 needRestart = true;
5144 }
5145 }
5146 } else {
5147 mRemovedProcesses.add(app);
5148 }
5149
5150 return needRestart;
5151 }
5152
5153 private final void processStartTimedOutLocked(ProcessRecord app) {
5154 final int pid = app.pid;
5155 boolean gone = false;
5156 synchronized (mPidsSelfLocked) {
5157 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5158 if (knownApp != null && knownApp.thread == null) {
5159 mPidsSelfLocked.remove(pid);
5160 gone = true;
5161 }
5162 }
5163
5164 if (gone) {
5165 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005166 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005167 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005168 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005169 // Take care of any launching providers waiting for this process.
5170 checkAppInLaunchingProvidersLocked(app, true);
5171 // Take care of any services that are waiting for the process.
5172 for (int i=0; i<mPendingServices.size(); i++) {
5173 ServiceRecord sr = mPendingServices.get(i);
5174 if (app.info.uid == sr.appInfo.uid
5175 && app.processName.equals(sr.processName)) {
5176 Log.w(TAG, "Forcing bringing down service: " + sr);
5177 mPendingServices.remove(i);
5178 i--;
5179 bringDownServiceLocked(sr, true);
5180 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005181 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005182 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005183 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5184 Log.w(TAG, "Unattached app died before backup, skipping");
5185 try {
5186 IBackupManager bm = IBackupManager.Stub.asInterface(
5187 ServiceManager.getService(Context.BACKUP_SERVICE));
5188 bm.agentDisconnected(app.info.packageName);
5189 } catch (RemoteException e) {
5190 // Can't happen; the backup manager is local
5191 }
5192 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005193 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5194 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5195 mPendingBroadcast = null;
5196 scheduleBroadcastsLocked();
5197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005198 } else {
5199 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5200 }
5201 }
5202
5203 private final boolean attachApplicationLocked(IApplicationThread thread,
5204 int pid) {
5205
5206 // Find the application record that is being attached... either via
5207 // the pid if we are running in multiple processes, or just pull the
5208 // next app record if we are emulating process with anonymous threads.
5209 ProcessRecord app;
5210 if (pid != MY_PID && pid >= 0) {
5211 synchronized (mPidsSelfLocked) {
5212 app = mPidsSelfLocked.get(pid);
5213 }
5214 } else if (mStartingProcesses.size() > 0) {
5215 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005216 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005217 } else {
5218 app = null;
5219 }
5220
5221 if (app == null) {
5222 Log.w(TAG, "No pending application record for pid " + pid
5223 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005224 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005225 if (pid > 0 && pid != MY_PID) {
5226 Process.killProcess(pid);
5227 } else {
5228 try {
5229 thread.scheduleExit();
5230 } catch (Exception e) {
5231 // Ignore exceptions.
5232 }
5233 }
5234 return false;
5235 }
5236
5237 // If this application record is still attached to a previous
5238 // process, clean it up now.
5239 if (app.thread != null) {
5240 handleAppDiedLocked(app, true);
5241 }
5242
5243 // Tell the process all about itself.
5244
5245 if (localLOGV) Log.v(
5246 TAG, "Binding process pid " + pid + " to record " + app);
5247
5248 String processName = app.processName;
5249 try {
5250 thread.asBinder().linkToDeath(new AppDeathRecipient(
5251 app, pid, thread), 0);
5252 } catch (RemoteException e) {
5253 app.resetPackageList();
5254 startProcessLocked(app, "link fail", processName);
5255 return false;
5256 }
5257
Doug Zongker2bec3d42009-12-04 12:52:44 -08005258 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005259
5260 app.thread = thread;
5261 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005262 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5263 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005264 app.forcingToForeground = null;
5265 app.foregroundServices = false;
5266 app.debugging = false;
5267
5268 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5269
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005270 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5271 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005272
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005273 if (!normalMode) {
5274 Log.i(TAG, "Launching preboot mode app: " + app);
5275 }
5276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005277 if (localLOGV) Log.v(
5278 TAG, "New app record " + app
5279 + " thread=" + thread.asBinder() + " pid=" + pid);
5280 try {
5281 int testMode = IApplicationThread.DEBUG_OFF;
5282 if (mDebugApp != null && mDebugApp.equals(processName)) {
5283 testMode = mWaitForDebugger
5284 ? IApplicationThread.DEBUG_WAIT
5285 : IApplicationThread.DEBUG_ON;
5286 app.debugging = true;
5287 if (mDebugTransient) {
5288 mDebugApp = mOrigDebugApp;
5289 mWaitForDebugger = mOrigWaitForDebugger;
5290 }
5291 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005292
Christopher Tate181fafa2009-05-14 11:12:14 -07005293 // If the app is being launched for restore or full backup, set it up specially
5294 boolean isRestrictedBackupMode = false;
5295 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5296 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5297 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5298 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005299
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005300 ensurePackageDexOpt(app.instrumentationInfo != null
5301 ? app.instrumentationInfo.packageName
5302 : app.info.packageName);
5303 if (app.instrumentationClass != null) {
5304 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005305 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005306 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5307 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005308 thread.bindApplication(processName, app.instrumentationInfo != null
5309 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005310 app.instrumentationClass, app.instrumentationProfileFile,
5311 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005312 isRestrictedBackupMode || !normalMode,
5313 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005314 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005315 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005316 } catch (Exception e) {
5317 // todo: Yikes! What should we do? For now we will try to
5318 // start another process, but that could easily get us in
5319 // an infinite loop of restarting processes...
5320 Log.w(TAG, "Exception thrown during bind!", e);
5321
5322 app.resetPackageList();
5323 startProcessLocked(app, "bind fail", processName);
5324 return false;
5325 }
5326
5327 // Remove this record from the list of starting applications.
5328 mPersistentStartingProcesses.remove(app);
5329 mProcessesOnHold.remove(app);
5330
5331 boolean badApp = false;
5332 boolean didSomething = false;
5333
5334 // See if the top visible activity is waiting to run in this process...
5335 HistoryRecord hr = topRunningActivityLocked(null);
5336 if (hr != null) {
5337 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5338 && processName.equals(hr.processName)) {
5339 try {
5340 if (realStartActivityLocked(hr, app, true, true)) {
5341 didSomething = true;
5342 }
5343 } catch (Exception e) {
5344 Log.w(TAG, "Exception in new application when starting activity "
5345 + hr.intent.getComponent().flattenToShortString(), e);
5346 badApp = true;
5347 }
5348 } else {
5349 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5350 }
5351 }
5352
5353 // Find any services that should be running in this process...
5354 if (!badApp && mPendingServices.size() > 0) {
5355 ServiceRecord sr = null;
5356 try {
5357 for (int i=0; i<mPendingServices.size(); i++) {
5358 sr = mPendingServices.get(i);
5359 if (app.info.uid != sr.appInfo.uid
5360 || !processName.equals(sr.processName)) {
5361 continue;
5362 }
5363
5364 mPendingServices.remove(i);
5365 i--;
5366 realStartServiceLocked(sr, app);
5367 didSomething = true;
5368 }
5369 } catch (Exception e) {
5370 Log.w(TAG, "Exception in new application when starting service "
5371 + sr.shortName, e);
5372 badApp = true;
5373 }
5374 }
5375
5376 // Check if the next broadcast receiver is in this process...
5377 BroadcastRecord br = mPendingBroadcast;
5378 if (!badApp && br != null && br.curApp == app) {
5379 try {
5380 mPendingBroadcast = null;
5381 processCurBroadcastLocked(br, app);
5382 didSomething = true;
5383 } catch (Exception e) {
5384 Log.w(TAG, "Exception in new application when starting receiver "
5385 + br.curComponent.flattenToShortString(), e);
5386 badApp = true;
5387 logBroadcastReceiverDiscard(br);
5388 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5389 br.resultExtras, br.resultAbort, true);
5390 scheduleBroadcastsLocked();
5391 }
5392 }
5393
Christopher Tate181fafa2009-05-14 11:12:14 -07005394 // Check whether the next backup agent is in this process...
5395 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5396 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005397 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005398 try {
5399 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5400 } catch (Exception e) {
5401 Log.w(TAG, "Exception scheduling backup agent creation: ");
5402 e.printStackTrace();
5403 }
5404 }
5405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005406 if (badApp) {
5407 // todo: Also need to kill application to deal with all
5408 // kinds of exceptions.
5409 handleAppDiedLocked(app, false);
5410 return false;
5411 }
5412
5413 if (!didSomething) {
5414 updateOomAdjLocked();
5415 }
5416
5417 return true;
5418 }
5419
5420 public final void attachApplication(IApplicationThread thread) {
5421 synchronized (this) {
5422 int callingPid = Binder.getCallingPid();
5423 final long origId = Binder.clearCallingIdentity();
5424 attachApplicationLocked(thread, callingPid);
5425 Binder.restoreCallingIdentity(origId);
5426 }
5427 }
5428
Dianne Hackborne88846e2009-09-30 21:34:25 -07005429 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005430 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005431 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005432 Binder.restoreCallingIdentity(origId);
5433 }
5434
5435 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5436 boolean remove) {
5437 int N = mStoppingActivities.size();
5438 if (N <= 0) return null;
5439
5440 ArrayList<HistoryRecord> stops = null;
5441
5442 final boolean nowVisible = mResumedActivity != null
5443 && mResumedActivity.nowVisible
5444 && !mResumedActivity.waitingVisible;
5445 for (int i=0; i<N; i++) {
5446 HistoryRecord s = mStoppingActivities.get(i);
5447 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5448 + nowVisible + " waitingVisible=" + s.waitingVisible
5449 + " finishing=" + s.finishing);
5450 if (s.waitingVisible && nowVisible) {
5451 mWaitingVisibleActivities.remove(s);
5452 s.waitingVisible = false;
5453 if (s.finishing) {
5454 // If this activity is finishing, it is sitting on top of
5455 // everyone else but we now know it is no longer needed...
5456 // so get rid of it. Otherwise, we need to go through the
5457 // normal flow and hide it once we determine that it is
5458 // hidden by the activities in front of it.
5459 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5460 mWindowManager.setAppVisibility(s, false);
5461 }
5462 }
5463 if (!s.waitingVisible && remove) {
5464 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5465 if (stops == null) {
5466 stops = new ArrayList<HistoryRecord>();
5467 }
5468 stops.add(s);
5469 mStoppingActivities.remove(i);
5470 N--;
5471 i--;
5472 }
5473 }
5474
5475 return stops;
5476 }
5477
5478 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005479 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005480 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005481 mWindowManager.enableScreenAfterBoot();
5482 }
5483
Dianne Hackborne88846e2009-09-30 21:34:25 -07005484 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5485 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005486 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5487
5488 ArrayList<HistoryRecord> stops = null;
5489 ArrayList<HistoryRecord> finishes = null;
5490 ArrayList<HistoryRecord> thumbnails = null;
5491 int NS = 0;
5492 int NF = 0;
5493 int NT = 0;
5494 IApplicationThread sendThumbnail = null;
5495 boolean booting = false;
5496 boolean enableScreen = false;
5497
5498 synchronized (this) {
5499 if (token != null) {
5500 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5501 }
5502
5503 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005504 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005505 if (index >= 0) {
5506 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5507
Dianne Hackborne88846e2009-09-30 21:34:25 -07005508 // This is a hack to semi-deal with a race condition
5509 // in the client where it can be constructed with a
5510 // newer configuration from when we asked it to launch.
5511 // We'll update with whatever configuration it now says
5512 // it used to launch.
5513 if (config != null) {
5514 r.configuration = config;
5515 }
5516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005517 // No longer need to keep the device awake.
5518 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5519 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5520 mLaunchingActivity.release();
5521 }
5522
5523 // We are now idle. If someone is waiting for a thumbnail from
5524 // us, we can now deliver.
5525 r.idle = true;
5526 scheduleAppGcsLocked();
5527 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5528 sendThumbnail = r.app.thread;
5529 r.thumbnailNeeded = false;
5530 }
5531
5532 // If this activity is fullscreen, set up to hide those under it.
5533
5534 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5535 ensureActivitiesVisibleLocked(null, 0);
5536
5537 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5538 if (!mBooted && !fromTimeout) {
5539 mBooted = true;
5540 enableScreen = true;
5541 }
5542 }
5543
5544 // Atomically retrieve all of the other things to do.
5545 stops = processStoppingActivitiesLocked(true);
5546 NS = stops != null ? stops.size() : 0;
5547 if ((NF=mFinishingActivities.size()) > 0) {
5548 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5549 mFinishingActivities.clear();
5550 }
5551 if ((NT=mCancelledThumbnails.size()) > 0) {
5552 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5553 mCancelledThumbnails.clear();
5554 }
5555
5556 booting = mBooting;
5557 mBooting = false;
5558 }
5559
5560 int i;
5561
5562 // Send thumbnail if requested.
5563 if (sendThumbnail != null) {
5564 try {
5565 sendThumbnail.requestThumbnail(token);
5566 } catch (Exception e) {
5567 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5568 sendPendingThumbnail(null, token, null, null, true);
5569 }
5570 }
5571
5572 // Stop any activities that are scheduled to do so but have been
5573 // waiting for the next one to start.
5574 for (i=0; i<NS; i++) {
5575 HistoryRecord r = (HistoryRecord)stops.get(i);
5576 synchronized (this) {
5577 if (r.finishing) {
5578 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5579 } else {
5580 stopActivityLocked(r);
5581 }
5582 }
5583 }
5584
5585 // Finish any activities that are scheduled to do so but have been
5586 // waiting for the next one to start.
5587 for (i=0; i<NF; i++) {
5588 HistoryRecord r = (HistoryRecord)finishes.get(i);
5589 synchronized (this) {
5590 destroyActivityLocked(r, true);
5591 }
5592 }
5593
5594 // Report back to any thumbnail receivers.
5595 for (i=0; i<NT; i++) {
5596 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5597 sendPendingThumbnail(r, null, null, null, true);
5598 }
5599
5600 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005601 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005602 }
5603
5604 trimApplications();
5605 //dump();
5606 //mWindowManager.dump();
5607
5608 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005609 enableScreenAfterBoot();
5610 }
5611 }
5612
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005613 final void finishBooting() {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005614 IntentFilter pkgFilter = new IntentFilter();
5615 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
5616 pkgFilter.addDataScheme("package");
5617 mContext.registerReceiver(new BroadcastReceiver() {
5618 @Override
5619 public void onReceive(Context context, Intent intent) {
5620 String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
5621 if (pkgs != null) {
5622 for (String pkg : pkgs) {
5623 if (forceStopPackageLocked(pkg, -1, false, false, false)) {
5624 setResultCode(Activity.RESULT_OK);
5625 return;
5626 }
5627 }
5628 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005629 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005630 }, pkgFilter);
5631
5632 synchronized (this) {
5633 // Ensure that any processes we had put on hold are now started
5634 // up.
5635 final int NP = mProcessesOnHold.size();
5636 if (NP > 0) {
5637 ArrayList<ProcessRecord> procs =
5638 new ArrayList<ProcessRecord>(mProcessesOnHold);
5639 for (int ip=0; ip<NP; ip++) {
5640 this.startProcessLocked(procs.get(ip), "on-hold", null);
5641 }
5642 }
5643
5644 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5645 // Tell anyone interested that we are done booting!
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005646 broadcastIntentLocked(null, null,
5647 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5648 null, null, 0, null, null,
5649 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5650 false, false, MY_PID, Process.SYSTEM_UID);
5651 }
5652 }
5653 }
5654
5655 final void ensureBootCompleted() {
5656 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005657 boolean enableScreen;
5658 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005659 booting = mBooting;
5660 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005661 enableScreen = !mBooted;
5662 mBooted = true;
5663 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005664
5665 if (booting) {
5666 finishBooting();
5667 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005668
5669 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005670 enableScreenAfterBoot();
5671 }
5672 }
5673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005674 public final void activityPaused(IBinder token, Bundle icicle) {
5675 // Refuse possible leaked file descriptors
5676 if (icicle != null && icicle.hasFileDescriptors()) {
5677 throw new IllegalArgumentException("File descriptors passed in Bundle");
5678 }
5679
5680 final long origId = Binder.clearCallingIdentity();
5681 activityPaused(token, icicle, false);
5682 Binder.restoreCallingIdentity(origId);
5683 }
5684
5685 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5686 if (DEBUG_PAUSE) Log.v(
5687 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5688 + ", timeout=" + timeout);
5689
5690 HistoryRecord r = null;
5691
5692 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005693 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005694 if (index >= 0) {
5695 r = (HistoryRecord)mHistory.get(index);
5696 if (!timeout) {
5697 r.icicle = icicle;
5698 r.haveState = true;
5699 }
5700 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5701 if (mPausingActivity == r) {
5702 r.state = ActivityState.PAUSED;
5703 completePauseLocked();
5704 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005705 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005706 System.identityHashCode(r), r.shortComponentName,
5707 mPausingActivity != null
5708 ? mPausingActivity.shortComponentName : "(none)");
5709 }
5710 }
5711 }
5712 }
5713
5714 public final void activityStopped(IBinder token, Bitmap thumbnail,
5715 CharSequence description) {
5716 if (localLOGV) Log.v(
5717 TAG, "Activity stopped: token=" + token);
5718
5719 HistoryRecord r = null;
5720
5721 final long origId = Binder.clearCallingIdentity();
5722
5723 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005724 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005725 if (index >= 0) {
5726 r = (HistoryRecord)mHistory.get(index);
5727 r.thumbnail = thumbnail;
5728 r.description = description;
5729 r.stopped = true;
5730 r.state = ActivityState.STOPPED;
5731 if (!r.finishing) {
5732 if (r.configDestroy) {
5733 destroyActivityLocked(r, true);
5734 resumeTopActivityLocked(null);
5735 }
5736 }
5737 }
5738 }
5739
5740 if (r != null) {
5741 sendPendingThumbnail(r, null, null, null, false);
5742 }
5743
5744 trimApplications();
5745
5746 Binder.restoreCallingIdentity(origId);
5747 }
5748
5749 public final void activityDestroyed(IBinder token) {
5750 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5751 synchronized (this) {
5752 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5753
Dianne Hackborn75b03852009-06-12 15:43:26 -07005754 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005755 if (index >= 0) {
5756 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5757 if (r.state == ActivityState.DESTROYING) {
5758 final long origId = Binder.clearCallingIdentity();
5759 removeActivityFromHistoryLocked(r);
5760 Binder.restoreCallingIdentity(origId);
5761 }
5762 }
5763 }
5764 }
5765
5766 public String getCallingPackage(IBinder token) {
5767 synchronized (this) {
5768 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005769 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005770 }
5771 }
5772
5773 public ComponentName getCallingActivity(IBinder token) {
5774 synchronized (this) {
5775 HistoryRecord r = getCallingRecordLocked(token);
5776 return r != null ? r.intent.getComponent() : null;
5777 }
5778 }
5779
5780 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005781 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005782 if (index >= 0) {
5783 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5784 if (r != null) {
5785 return r.resultTo;
5786 }
5787 }
5788 return null;
5789 }
5790
5791 public ComponentName getActivityClassForToken(IBinder token) {
5792 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005793 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005794 if (index >= 0) {
5795 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5796 return r.intent.getComponent();
5797 }
5798 return null;
5799 }
5800 }
5801
5802 public String getPackageForToken(IBinder token) {
5803 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005804 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005805 if (index >= 0) {
5806 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5807 return r.packageName;
5808 }
5809 return null;
5810 }
5811 }
5812
5813 public IIntentSender getIntentSender(int type,
5814 String packageName, IBinder token, String resultWho,
5815 int requestCode, Intent intent, String resolvedType, int flags) {
5816 // Refuse possible leaked file descriptors
5817 if (intent != null && intent.hasFileDescriptors() == true) {
5818 throw new IllegalArgumentException("File descriptors passed in Intent");
5819 }
5820
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005821 if (type == INTENT_SENDER_BROADCAST) {
5822 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5823 throw new IllegalArgumentException(
5824 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5825 }
5826 }
5827
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005828 synchronized(this) {
5829 int callingUid = Binder.getCallingUid();
5830 try {
5831 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5832 Process.supportsProcesses()) {
5833 int uid = ActivityThread.getPackageManager()
5834 .getPackageUid(packageName);
5835 if (uid != Binder.getCallingUid()) {
5836 String msg = "Permission Denial: getIntentSender() from pid="
5837 + Binder.getCallingPid()
5838 + ", uid=" + Binder.getCallingUid()
5839 + ", (need uid=" + uid + ")"
5840 + " is not allowed to send as package " + packageName;
5841 Log.w(TAG, msg);
5842 throw new SecurityException(msg);
5843 }
5844 }
5845 } catch (RemoteException e) {
5846 throw new SecurityException(e);
5847 }
5848 HistoryRecord activity = null;
5849 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005850 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005851 if (index < 0) {
5852 return null;
5853 }
5854 activity = (HistoryRecord)mHistory.get(index);
5855 if (activity.finishing) {
5856 return null;
5857 }
5858 }
5859
5860 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5861 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5862 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5863 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5864 |PendingIntent.FLAG_UPDATE_CURRENT);
5865
5866 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5867 type, packageName, activity, resultWho,
5868 requestCode, intent, resolvedType, flags);
5869 WeakReference<PendingIntentRecord> ref;
5870 ref = mIntentSenderRecords.get(key);
5871 PendingIntentRecord rec = ref != null ? ref.get() : null;
5872 if (rec != null) {
5873 if (!cancelCurrent) {
5874 if (updateCurrent) {
5875 rec.key.requestIntent.replaceExtras(intent);
5876 }
5877 return rec;
5878 }
5879 rec.canceled = true;
5880 mIntentSenderRecords.remove(key);
5881 }
5882 if (noCreate) {
5883 return rec;
5884 }
5885 rec = new PendingIntentRecord(this, key, callingUid);
5886 mIntentSenderRecords.put(key, rec.ref);
5887 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5888 if (activity.pendingResults == null) {
5889 activity.pendingResults
5890 = new HashSet<WeakReference<PendingIntentRecord>>();
5891 }
5892 activity.pendingResults.add(rec.ref);
5893 }
5894 return rec;
5895 }
5896 }
5897
5898 public void cancelIntentSender(IIntentSender sender) {
5899 if (!(sender instanceof PendingIntentRecord)) {
5900 return;
5901 }
5902 synchronized(this) {
5903 PendingIntentRecord rec = (PendingIntentRecord)sender;
5904 try {
5905 int uid = ActivityThread.getPackageManager()
5906 .getPackageUid(rec.key.packageName);
5907 if (uid != Binder.getCallingUid()) {
5908 String msg = "Permission Denial: cancelIntentSender() from pid="
5909 + Binder.getCallingPid()
5910 + ", uid=" + Binder.getCallingUid()
5911 + " is not allowed to cancel packges "
5912 + rec.key.packageName;
5913 Log.w(TAG, msg);
5914 throw new SecurityException(msg);
5915 }
5916 } catch (RemoteException e) {
5917 throw new SecurityException(e);
5918 }
5919 cancelIntentSenderLocked(rec, true);
5920 }
5921 }
5922
5923 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5924 rec.canceled = true;
5925 mIntentSenderRecords.remove(rec.key);
5926 if (cleanActivity && rec.key.activity != null) {
5927 rec.key.activity.pendingResults.remove(rec.ref);
5928 }
5929 }
5930
5931 public String getPackageForIntentSender(IIntentSender pendingResult) {
5932 if (!(pendingResult instanceof PendingIntentRecord)) {
5933 return null;
5934 }
5935 synchronized(this) {
5936 try {
5937 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5938 return res.key.packageName;
5939 } catch (ClassCastException e) {
5940 }
5941 }
5942 return null;
5943 }
5944
5945 public void setProcessLimit(int max) {
5946 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5947 "setProcessLimit()");
5948 mProcessLimit = max;
5949 }
5950
5951 public int getProcessLimit() {
5952 return mProcessLimit;
5953 }
5954
5955 void foregroundTokenDied(ForegroundToken token) {
5956 synchronized (ActivityManagerService.this) {
5957 synchronized (mPidsSelfLocked) {
5958 ForegroundToken cur
5959 = mForegroundProcesses.get(token.pid);
5960 if (cur != token) {
5961 return;
5962 }
5963 mForegroundProcesses.remove(token.pid);
5964 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5965 if (pr == null) {
5966 return;
5967 }
5968 pr.forcingToForeground = null;
5969 pr.foregroundServices = false;
5970 }
5971 updateOomAdjLocked();
5972 }
5973 }
5974
5975 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5976 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5977 "setProcessForeground()");
5978 synchronized(this) {
5979 boolean changed = false;
5980
5981 synchronized (mPidsSelfLocked) {
5982 ProcessRecord pr = mPidsSelfLocked.get(pid);
5983 if (pr == null) {
5984 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5985 return;
5986 }
5987 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5988 if (oldToken != null) {
5989 oldToken.token.unlinkToDeath(oldToken, 0);
5990 mForegroundProcesses.remove(pid);
5991 pr.forcingToForeground = null;
5992 changed = true;
5993 }
5994 if (isForeground && token != null) {
5995 ForegroundToken newToken = new ForegroundToken() {
5996 public void binderDied() {
5997 foregroundTokenDied(this);
5998 }
5999 };
6000 newToken.pid = pid;
6001 newToken.token = token;
6002 try {
6003 token.linkToDeath(newToken, 0);
6004 mForegroundProcesses.put(pid, newToken);
6005 pr.forcingToForeground = token;
6006 changed = true;
6007 } catch (RemoteException e) {
6008 // If the process died while doing this, we will later
6009 // do the cleanup with the process death link.
6010 }
6011 }
6012 }
6013
6014 if (changed) {
6015 updateOomAdjLocked();
6016 }
6017 }
6018 }
6019
6020 // =========================================================
6021 // PERMISSIONS
6022 // =========================================================
6023
6024 static class PermissionController extends IPermissionController.Stub {
6025 ActivityManagerService mActivityManagerService;
6026 PermissionController(ActivityManagerService activityManagerService) {
6027 mActivityManagerService = activityManagerService;
6028 }
6029
6030 public boolean checkPermission(String permission, int pid, int uid) {
6031 return mActivityManagerService.checkPermission(permission, pid,
6032 uid) == PackageManager.PERMISSION_GRANTED;
6033 }
6034 }
6035
6036 /**
6037 * This can be called with or without the global lock held.
6038 */
6039 int checkComponentPermission(String permission, int pid, int uid,
6040 int reqUid) {
6041 // We might be performing an operation on behalf of an indirect binder
6042 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6043 // client identity accordingly before proceeding.
6044 Identity tlsIdentity = sCallerIdentity.get();
6045 if (tlsIdentity != null) {
6046 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6047 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6048 uid = tlsIdentity.uid;
6049 pid = tlsIdentity.pid;
6050 }
6051
6052 // Root, system server and our own process get to do everything.
6053 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6054 !Process.supportsProcesses()) {
6055 return PackageManager.PERMISSION_GRANTED;
6056 }
6057 // If the target requires a specific UID, always fail for others.
6058 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006059 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006060 return PackageManager.PERMISSION_DENIED;
6061 }
6062 if (permission == null) {
6063 return PackageManager.PERMISSION_GRANTED;
6064 }
6065 try {
6066 return ActivityThread.getPackageManager()
6067 .checkUidPermission(permission, uid);
6068 } catch (RemoteException e) {
6069 // Should never happen, but if it does... deny!
6070 Log.e(TAG, "PackageManager is dead?!?", e);
6071 }
6072 return PackageManager.PERMISSION_DENIED;
6073 }
6074
6075 /**
6076 * As the only public entry point for permissions checking, this method
6077 * can enforce the semantic that requesting a check on a null global
6078 * permission is automatically denied. (Internally a null permission
6079 * string is used when calling {@link #checkComponentPermission} in cases
6080 * when only uid-based security is needed.)
6081 *
6082 * This can be called with or without the global lock held.
6083 */
6084 public int checkPermission(String permission, int pid, int uid) {
6085 if (permission == null) {
6086 return PackageManager.PERMISSION_DENIED;
6087 }
6088 return checkComponentPermission(permission, pid, uid, -1);
6089 }
6090
6091 /**
6092 * Binder IPC calls go through the public entry point.
6093 * This can be called with or without the global lock held.
6094 */
6095 int checkCallingPermission(String permission) {
6096 return checkPermission(permission,
6097 Binder.getCallingPid(),
6098 Binder.getCallingUid());
6099 }
6100
6101 /**
6102 * This can be called with or without the global lock held.
6103 */
6104 void enforceCallingPermission(String permission, String func) {
6105 if (checkCallingPermission(permission)
6106 == PackageManager.PERMISSION_GRANTED) {
6107 return;
6108 }
6109
6110 String msg = "Permission Denial: " + func + " from pid="
6111 + Binder.getCallingPid()
6112 + ", uid=" + Binder.getCallingUid()
6113 + " requires " + permission;
6114 Log.w(TAG, msg);
6115 throw new SecurityException(msg);
6116 }
6117
6118 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6119 ProviderInfo pi, int uid, int modeFlags) {
6120 try {
6121 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6122 if ((pi.readPermission != null) &&
6123 (pm.checkUidPermission(pi.readPermission, uid)
6124 != PackageManager.PERMISSION_GRANTED)) {
6125 return false;
6126 }
6127 }
6128 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6129 if ((pi.writePermission != null) &&
6130 (pm.checkUidPermission(pi.writePermission, uid)
6131 != PackageManager.PERMISSION_GRANTED)) {
6132 return false;
6133 }
6134 }
6135 return true;
6136 } catch (RemoteException e) {
6137 return false;
6138 }
6139 }
6140
6141 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6142 int modeFlags) {
6143 // Root gets to do everything.
6144 if (uid == 0 || !Process.supportsProcesses()) {
6145 return true;
6146 }
6147 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6148 if (perms == null) return false;
6149 UriPermission perm = perms.get(uri);
6150 if (perm == null) return false;
6151 return (modeFlags&perm.modeFlags) == modeFlags;
6152 }
6153
6154 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6155 // Another redirected-binder-call permissions check as in
6156 // {@link checkComponentPermission}.
6157 Identity tlsIdentity = sCallerIdentity.get();
6158 if (tlsIdentity != null) {
6159 uid = tlsIdentity.uid;
6160 pid = tlsIdentity.pid;
6161 }
6162
6163 // Our own process gets to do everything.
6164 if (pid == MY_PID) {
6165 return PackageManager.PERMISSION_GRANTED;
6166 }
6167 synchronized(this) {
6168 return checkUriPermissionLocked(uri, uid, modeFlags)
6169 ? PackageManager.PERMISSION_GRANTED
6170 : PackageManager.PERMISSION_DENIED;
6171 }
6172 }
6173
6174 private void grantUriPermissionLocked(int callingUid,
6175 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6176 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6177 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6178 if (modeFlags == 0) {
6179 return;
6180 }
6181
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006182 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6183 "Requested grant " + targetPkg + " permission to " + uri);
6184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006185 final IPackageManager pm = ActivityThread.getPackageManager();
6186
6187 // If this is not a content: uri, we can't do anything with it.
6188 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006189 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6190 "Can't grant URI permission for non-content URI: " + uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006191 return;
6192 }
6193
6194 String name = uri.getAuthority();
6195 ProviderInfo pi = null;
6196 ContentProviderRecord cpr
6197 = (ContentProviderRecord)mProvidersByName.get(name);
6198 if (cpr != null) {
6199 pi = cpr.info;
6200 } else {
6201 try {
6202 pi = pm.resolveContentProvider(name,
6203 PackageManager.GET_URI_PERMISSION_PATTERNS);
6204 } catch (RemoteException ex) {
6205 }
6206 }
6207 if (pi == null) {
6208 Log.w(TAG, "No content provider found for: " + name);
6209 return;
6210 }
6211
6212 int targetUid;
6213 try {
6214 targetUid = pm.getPackageUid(targetPkg);
6215 if (targetUid < 0) {
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006216 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6217 "Can't grant URI permission no uid for: " + targetPkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006218 return;
6219 }
6220 } catch (RemoteException ex) {
6221 return;
6222 }
6223
6224 // First... does the target actually need this permission?
6225 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6226 // No need to grant the target this permission.
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006227 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6228 "Target " + targetPkg + " already has full permission to " + uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006229 return;
6230 }
6231
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006232 // Second... is the provider allowing granting of URI permissions?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006233 if (!pi.grantUriPermissions) {
6234 throw new SecurityException("Provider " + pi.packageName
6235 + "/" + pi.name
6236 + " does not allow granting of Uri permissions (uri "
6237 + uri + ")");
6238 }
6239 if (pi.uriPermissionPatterns != null) {
6240 final int N = pi.uriPermissionPatterns.length;
6241 boolean allowed = false;
6242 for (int i=0; i<N; i++) {
6243 if (pi.uriPermissionPatterns[i] != null
6244 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6245 allowed = true;
6246 break;
6247 }
6248 }
6249 if (!allowed) {
6250 throw new SecurityException("Provider " + pi.packageName
6251 + "/" + pi.name
6252 + " does not allow granting of permission to path of Uri "
6253 + uri);
6254 }
6255 }
6256
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006257 // Third... does the caller itself have permission to access
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006258 // this uri?
6259 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6260 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6261 throw new SecurityException("Uid " + callingUid
6262 + " does not have permission to uri " + uri);
6263 }
6264 }
6265
6266 // Okay! So here we are: the caller has the assumed permission
6267 // to the uri, and the target doesn't. Let's now give this to
6268 // the target.
6269
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006270 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6271 "Granting " + targetPkg + " permission to " + uri);
6272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006273 HashMap<Uri, UriPermission> targetUris
6274 = mGrantedUriPermissions.get(targetUid);
6275 if (targetUris == null) {
6276 targetUris = new HashMap<Uri, UriPermission>();
6277 mGrantedUriPermissions.put(targetUid, targetUris);
6278 }
6279
6280 UriPermission perm = targetUris.get(uri);
6281 if (perm == null) {
6282 perm = new UriPermission(targetUid, uri);
6283 targetUris.put(uri, perm);
6284
6285 }
6286 perm.modeFlags |= modeFlags;
6287 if (activity == null) {
6288 perm.globalModeFlags |= modeFlags;
6289 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6290 perm.readActivities.add(activity);
6291 if (activity.readUriPermissions == null) {
6292 activity.readUriPermissions = new HashSet<UriPermission>();
6293 }
6294 activity.readUriPermissions.add(perm);
6295 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6296 perm.writeActivities.add(activity);
6297 if (activity.writeUriPermissions == null) {
6298 activity.writeUriPermissions = new HashSet<UriPermission>();
6299 }
6300 activity.writeUriPermissions.add(perm);
6301 }
6302 }
6303
6304 private void grantUriPermissionFromIntentLocked(int callingUid,
6305 String targetPkg, Intent intent, HistoryRecord activity) {
6306 if (intent == null) {
6307 return;
6308 }
6309 Uri data = intent.getData();
6310 if (data == null) {
6311 return;
6312 }
6313 grantUriPermissionLocked(callingUid, targetPkg, data,
6314 intent.getFlags(), activity);
6315 }
6316
6317 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6318 Uri uri, int modeFlags) {
6319 synchronized(this) {
6320 final ProcessRecord r = getRecordForAppLocked(caller);
6321 if (r == null) {
6322 throw new SecurityException("Unable to find app for caller "
6323 + caller
6324 + " when granting permission to uri " + uri);
6325 }
6326 if (targetPkg == null) {
6327 Log.w(TAG, "grantUriPermission: null target");
6328 return;
6329 }
6330 if (uri == null) {
6331 Log.w(TAG, "grantUriPermission: null uri");
6332 return;
6333 }
6334
6335 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6336 null);
6337 }
6338 }
6339
6340 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6341 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6342 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6343 HashMap<Uri, UriPermission> perms
6344 = mGrantedUriPermissions.get(perm.uid);
6345 if (perms != null) {
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006346 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6347 "Removing " + perm.uid + " permission to " + perm.uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006348 perms.remove(perm.uri);
6349 if (perms.size() == 0) {
6350 mGrantedUriPermissions.remove(perm.uid);
6351 }
6352 }
6353 }
6354 }
6355
6356 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6357 if (activity.readUriPermissions != null) {
6358 for (UriPermission perm : activity.readUriPermissions) {
6359 perm.readActivities.remove(activity);
6360 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6361 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6362 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6363 removeUriPermissionIfNeededLocked(perm);
6364 }
6365 }
6366 }
6367 if (activity.writeUriPermissions != null) {
6368 for (UriPermission perm : activity.writeUriPermissions) {
6369 perm.writeActivities.remove(activity);
6370 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6371 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6372 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6373 removeUriPermissionIfNeededLocked(perm);
6374 }
6375 }
6376 }
6377 }
6378
6379 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6380 int modeFlags) {
6381 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6382 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6383 if (modeFlags == 0) {
6384 return;
6385 }
6386
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006387 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6388 "Revoking all granted permissions to " + uri);
6389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006390 final IPackageManager pm = ActivityThread.getPackageManager();
6391
6392 final String authority = uri.getAuthority();
6393 ProviderInfo pi = null;
6394 ContentProviderRecord cpr
6395 = (ContentProviderRecord)mProvidersByName.get(authority);
6396 if (cpr != null) {
6397 pi = cpr.info;
6398 } else {
6399 try {
6400 pi = pm.resolveContentProvider(authority,
6401 PackageManager.GET_URI_PERMISSION_PATTERNS);
6402 } catch (RemoteException ex) {
6403 }
6404 }
6405 if (pi == null) {
6406 Log.w(TAG, "No content provider found for: " + authority);
6407 return;
6408 }
6409
6410 // Does the caller have this permission on the URI?
6411 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6412 // Right now, if you are not the original owner of the permission,
6413 // you are not allowed to revoke it.
6414 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6415 throw new SecurityException("Uid " + callingUid
6416 + " does not have permission to uri " + uri);
6417 //}
6418 }
6419
6420 // Go through all of the permissions and remove any that match.
6421 final List<String> SEGMENTS = uri.getPathSegments();
6422 if (SEGMENTS != null) {
6423 final int NS = SEGMENTS.size();
6424 int N = mGrantedUriPermissions.size();
6425 for (int i=0; i<N; i++) {
6426 HashMap<Uri, UriPermission> perms
6427 = mGrantedUriPermissions.valueAt(i);
6428 Iterator<UriPermission> it = perms.values().iterator();
6429 toploop:
6430 while (it.hasNext()) {
6431 UriPermission perm = it.next();
6432 Uri targetUri = perm.uri;
6433 if (!authority.equals(targetUri.getAuthority())) {
6434 continue;
6435 }
6436 List<String> targetSegments = targetUri.getPathSegments();
6437 if (targetSegments == null) {
6438 continue;
6439 }
6440 if (targetSegments.size() < NS) {
6441 continue;
6442 }
6443 for (int j=0; j<NS; j++) {
6444 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6445 continue toploop;
6446 }
6447 }
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006448 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6449 "Revoking " + perm.uid + " permission to " + perm.uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006450 perm.clearModes(modeFlags);
6451 if (perm.modeFlags == 0) {
6452 it.remove();
6453 }
6454 }
6455 if (perms.size() == 0) {
6456 mGrantedUriPermissions.remove(
6457 mGrantedUriPermissions.keyAt(i));
6458 N--;
6459 i--;
6460 }
6461 }
6462 }
6463 }
6464
6465 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6466 int modeFlags) {
6467 synchronized(this) {
6468 final ProcessRecord r = getRecordForAppLocked(caller);
6469 if (r == null) {
6470 throw new SecurityException("Unable to find app for caller "
6471 + caller
6472 + " when revoking permission to uri " + uri);
6473 }
6474 if (uri == null) {
6475 Log.w(TAG, "revokeUriPermission: null uri");
6476 return;
6477 }
6478
6479 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6480 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6481 if (modeFlags == 0) {
6482 return;
6483 }
6484
6485 final IPackageManager pm = ActivityThread.getPackageManager();
6486
6487 final String authority = uri.getAuthority();
6488 ProviderInfo pi = null;
6489 ContentProviderRecord cpr
6490 = (ContentProviderRecord)mProvidersByName.get(authority);
6491 if (cpr != null) {
6492 pi = cpr.info;
6493 } else {
6494 try {
6495 pi = pm.resolveContentProvider(authority,
6496 PackageManager.GET_URI_PERMISSION_PATTERNS);
6497 } catch (RemoteException ex) {
6498 }
6499 }
6500 if (pi == null) {
6501 Log.w(TAG, "No content provider found for: " + authority);
6502 return;
6503 }
6504
6505 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6506 }
6507 }
6508
6509 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6510 synchronized (this) {
6511 ProcessRecord app =
6512 who != null ? getRecordForAppLocked(who) : null;
6513 if (app == null) return;
6514
6515 Message msg = Message.obtain();
6516 msg.what = WAIT_FOR_DEBUGGER_MSG;
6517 msg.obj = app;
6518 msg.arg1 = waiting ? 1 : 0;
6519 mHandler.sendMessage(msg);
6520 }
6521 }
6522
6523 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6524 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006525 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006526 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006527 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006528 }
6529
6530 // =========================================================
6531 // TASK MANAGEMENT
6532 // =========================================================
6533
6534 public List getTasks(int maxNum, int flags,
6535 IThumbnailReceiver receiver) {
6536 ArrayList list = new ArrayList();
6537
6538 PendingThumbnailsRecord pending = null;
6539 IApplicationThread topThumbnail = null;
6540 HistoryRecord topRecord = null;
6541
6542 synchronized(this) {
6543 if (localLOGV) Log.v(
6544 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6545 + ", receiver=" + receiver);
6546
6547 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6548 != PackageManager.PERMISSION_GRANTED) {
6549 if (receiver != null) {
6550 // If the caller wants to wait for pending thumbnails,
6551 // it ain't gonna get them.
6552 try {
6553 receiver.finished();
6554 } catch (RemoteException ex) {
6555 }
6556 }
6557 String msg = "Permission Denial: getTasks() from pid="
6558 + Binder.getCallingPid()
6559 + ", uid=" + Binder.getCallingUid()
6560 + " requires " + android.Manifest.permission.GET_TASKS;
6561 Log.w(TAG, msg);
6562 throw new SecurityException(msg);
6563 }
6564
6565 int pos = mHistory.size()-1;
6566 HistoryRecord next =
6567 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6568 HistoryRecord top = null;
6569 CharSequence topDescription = null;
6570 TaskRecord curTask = null;
6571 int numActivities = 0;
6572 int numRunning = 0;
6573 while (pos >= 0 && maxNum > 0) {
6574 final HistoryRecord r = next;
6575 pos--;
6576 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6577
6578 // Initialize state for next task if needed.
6579 if (top == null ||
6580 (top.state == ActivityState.INITIALIZING
6581 && top.task == r.task)) {
6582 top = r;
6583 topDescription = r.description;
6584 curTask = r.task;
6585 numActivities = numRunning = 0;
6586 }
6587
6588 // Add 'r' into the current task.
6589 numActivities++;
6590 if (r.app != null && r.app.thread != null) {
6591 numRunning++;
6592 }
6593 if (topDescription == null) {
6594 topDescription = r.description;
6595 }
6596
6597 if (localLOGV) Log.v(
6598 TAG, r.intent.getComponent().flattenToShortString()
6599 + ": task=" + r.task);
6600
6601 // If the next one is a different task, generate a new
6602 // TaskInfo entry for what we have.
6603 if (next == null || next.task != curTask) {
6604 ActivityManager.RunningTaskInfo ci
6605 = new ActivityManager.RunningTaskInfo();
6606 ci.id = curTask.taskId;
6607 ci.baseActivity = r.intent.getComponent();
6608 ci.topActivity = top.intent.getComponent();
6609 ci.thumbnail = top.thumbnail;
6610 ci.description = topDescription;
6611 ci.numActivities = numActivities;
6612 ci.numRunning = numRunning;
6613 //System.out.println(
6614 // "#" + maxNum + ": " + " descr=" + ci.description);
6615 if (ci.thumbnail == null && receiver != null) {
6616 if (localLOGV) Log.v(
6617 TAG, "State=" + top.state + "Idle=" + top.idle
6618 + " app=" + top.app
6619 + " thr=" + (top.app != null ? top.app.thread : null));
6620 if (top.state == ActivityState.RESUMED
6621 || top.state == ActivityState.PAUSING) {
6622 if (top.idle && top.app != null
6623 && top.app.thread != null) {
6624 topRecord = top;
6625 topThumbnail = top.app.thread;
6626 } else {
6627 top.thumbnailNeeded = true;
6628 }
6629 }
6630 if (pending == null) {
6631 pending = new PendingThumbnailsRecord(receiver);
6632 }
6633 pending.pendingRecords.add(top);
6634 }
6635 list.add(ci);
6636 maxNum--;
6637 top = null;
6638 }
6639 }
6640
6641 if (pending != null) {
6642 mPendingThumbnails.add(pending);
6643 }
6644 }
6645
6646 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6647
6648 if (topThumbnail != null) {
6649 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6650 try {
6651 topThumbnail.requestThumbnail(topRecord);
6652 } catch (Exception e) {
6653 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6654 sendPendingThumbnail(null, topRecord, null, null, true);
6655 }
6656 }
6657
6658 if (pending == null && receiver != null) {
6659 // In this case all thumbnails were available and the client
6660 // is being asked to be told when the remaining ones come in...
6661 // which is unusually, since the top-most currently running
6662 // activity should never have a canned thumbnail! Oh well.
6663 try {
6664 receiver.finished();
6665 } catch (RemoteException ex) {
6666 }
6667 }
6668
6669 return list;
6670 }
6671
6672 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6673 int flags) {
6674 synchronized (this) {
6675 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6676 "getRecentTasks()");
6677
6678 final int N = mRecentTasks.size();
6679 ArrayList<ActivityManager.RecentTaskInfo> res
6680 = new ArrayList<ActivityManager.RecentTaskInfo>(
6681 maxNum < N ? maxNum : N);
6682 for (int i=0; i<N && maxNum > 0; i++) {
6683 TaskRecord tr = mRecentTasks.get(i);
6684 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6685 || (tr.intent == null)
6686 || ((tr.intent.getFlags()
6687 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6688 ActivityManager.RecentTaskInfo rti
6689 = new ActivityManager.RecentTaskInfo();
6690 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6691 rti.baseIntent = new Intent(
6692 tr.intent != null ? tr.intent : tr.affinityIntent);
6693 rti.origActivity = tr.origActivity;
6694 res.add(rti);
6695 maxNum--;
6696 }
6697 }
6698 return res;
6699 }
6700 }
6701
6702 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6703 int j;
6704 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6705 TaskRecord jt = startTask;
6706
6707 // First look backwards
6708 for (j=startIndex-1; j>=0; j--) {
6709 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6710 if (r.task != jt) {
6711 jt = r.task;
6712 if (affinity.equals(jt.affinity)) {
6713 return j;
6714 }
6715 }
6716 }
6717
6718 // Now look forwards
6719 final int N = mHistory.size();
6720 jt = startTask;
6721 for (j=startIndex+1; j<N; j++) {
6722 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6723 if (r.task != jt) {
6724 if (affinity.equals(jt.affinity)) {
6725 return j;
6726 }
6727 jt = r.task;
6728 }
6729 }
6730
6731 // Might it be at the top?
6732 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6733 return N-1;
6734 }
6735
6736 return -1;
6737 }
6738
6739 /**
6740 * Perform a reset of the given task, if needed as part of launching it.
6741 * Returns the new HistoryRecord at the top of the task.
6742 */
6743 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6744 HistoryRecord newActivity) {
6745 boolean forceReset = (newActivity.info.flags
6746 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6747 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6748 if ((newActivity.info.flags
6749 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6750 forceReset = true;
6751 }
6752 }
6753
6754 final TaskRecord task = taskTop.task;
6755
6756 // We are going to move through the history list so that we can look
6757 // at each activity 'target' with 'below' either the interesting
6758 // activity immediately below it in the stack or null.
6759 HistoryRecord target = null;
6760 int targetI = 0;
6761 int taskTopI = -1;
6762 int replyChainEnd = -1;
6763 int lastReparentPos = -1;
6764 for (int i=mHistory.size()-1; i>=-1; i--) {
6765 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6766
6767 if (below != null && below.finishing) {
6768 continue;
6769 }
6770 if (target == null) {
6771 target = below;
6772 targetI = i;
6773 // If we were in the middle of a reply chain before this
6774 // task, it doesn't appear like the root of the chain wants
6775 // anything interesting, so drop it.
6776 replyChainEnd = -1;
6777 continue;
6778 }
6779
6780 final int flags = target.info.flags;
6781
6782 final boolean finishOnTaskLaunch =
6783 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6784 final boolean allowTaskReparenting =
6785 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6786
6787 if (target.task == task) {
6788 // We are inside of the task being reset... we'll either
6789 // finish this activity, push it out for another task,
6790 // or leave it as-is. We only do this
6791 // for activities that are not the root of the task (since
6792 // if we finish the root, we may no longer have the task!).
6793 if (taskTopI < 0) {
6794 taskTopI = targetI;
6795 }
6796 if (below != null && below.task == task) {
6797 final boolean clearWhenTaskReset =
6798 (target.intent.getFlags()
6799 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006800 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006801 // If this activity is sending a reply to a previous
6802 // activity, we can't do anything with it now until
6803 // we reach the start of the reply chain.
6804 // XXX note that we are assuming the result is always
6805 // to the previous activity, which is almost always
6806 // the case but we really shouldn't count on.
6807 if (replyChainEnd < 0) {
6808 replyChainEnd = targetI;
6809 }
Ed Heyl73798232009-03-24 21:32:21 -07006810 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006811 && target.taskAffinity != null
6812 && !target.taskAffinity.equals(task.affinity)) {
6813 // If this activity has an affinity for another
6814 // task, then we need to move it out of here. We will
6815 // move it as far out of the way as possible, to the
6816 // bottom of the activity stack. This also keeps it
6817 // correctly ordered with any activities we previously
6818 // moved.
6819 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6820 if (target.taskAffinity != null
6821 && target.taskAffinity.equals(p.task.affinity)) {
6822 // If the activity currently at the bottom has the
6823 // same task affinity as the one we are moving,
6824 // then merge it into the same task.
6825 target.task = p.task;
6826 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6827 + " out to bottom task " + p.task);
6828 } else {
6829 mCurTask++;
6830 if (mCurTask <= 0) {
6831 mCurTask = 1;
6832 }
6833 target.task = new TaskRecord(mCurTask, target.info, null,
6834 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6835 target.task.affinityIntent = target.intent;
6836 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6837 + " out to new task " + target.task);
6838 }
6839 mWindowManager.setAppGroupId(target, task.taskId);
6840 if (replyChainEnd < 0) {
6841 replyChainEnd = targetI;
6842 }
6843 int dstPos = 0;
6844 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6845 p = (HistoryRecord)mHistory.get(srcPos);
6846 if (p.finishing) {
6847 continue;
6848 }
6849 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6850 + " out to target's task " + target.task);
6851 task.numActivities--;
6852 p.task = target.task;
6853 target.task.numActivities++;
6854 mHistory.remove(srcPos);
6855 mHistory.add(dstPos, p);
6856 mWindowManager.moveAppToken(dstPos, p);
6857 mWindowManager.setAppGroupId(p, p.task.taskId);
6858 dstPos++;
6859 if (VALIDATE_TOKENS) {
6860 mWindowManager.validateAppTokens(mHistory);
6861 }
6862 i++;
6863 }
6864 if (taskTop == p) {
6865 taskTop = below;
6866 }
6867 if (taskTopI == replyChainEnd) {
6868 taskTopI = -1;
6869 }
6870 replyChainEnd = -1;
6871 addRecentTask(target.task);
6872 } else if (forceReset || finishOnTaskLaunch
6873 || clearWhenTaskReset) {
6874 // If the activity should just be removed -- either
6875 // because it asks for it, or the task should be
6876 // cleared -- then finish it and anything that is
6877 // part of its reply chain.
6878 if (clearWhenTaskReset) {
6879 // In this case, we want to finish this activity
6880 // and everything above it, so be sneaky and pretend
6881 // like these are all in the reply chain.
6882 replyChainEnd = targetI+1;
6883 while (replyChainEnd < mHistory.size() &&
6884 ((HistoryRecord)mHistory.get(
6885 replyChainEnd)).task == task) {
6886 replyChainEnd++;
6887 }
6888 replyChainEnd--;
6889 } else if (replyChainEnd < 0) {
6890 replyChainEnd = targetI;
6891 }
6892 HistoryRecord p = null;
6893 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6894 p = (HistoryRecord)mHistory.get(srcPos);
6895 if (p.finishing) {
6896 continue;
6897 }
6898 if (finishActivityLocked(p, srcPos,
6899 Activity.RESULT_CANCELED, null, "reset")) {
6900 replyChainEnd--;
6901 srcPos--;
6902 }
6903 }
6904 if (taskTop == p) {
6905 taskTop = below;
6906 }
6907 if (taskTopI == replyChainEnd) {
6908 taskTopI = -1;
6909 }
6910 replyChainEnd = -1;
6911 } else {
6912 // If we were in the middle of a chain, well the
6913 // activity that started it all doesn't want anything
6914 // special, so leave it all as-is.
6915 replyChainEnd = -1;
6916 }
6917 } else {
6918 // Reached the bottom of the task -- any reply chain
6919 // should be left as-is.
6920 replyChainEnd = -1;
6921 }
6922
6923 } else if (target.resultTo != null) {
6924 // If this activity is sending a reply to a previous
6925 // activity, we can't do anything with it now until
6926 // we reach the start of the reply chain.
6927 // XXX note that we are assuming the result is always
6928 // to the previous activity, which is almost always
6929 // the case but we really shouldn't count on.
6930 if (replyChainEnd < 0) {
6931 replyChainEnd = targetI;
6932 }
6933
6934 } else if (taskTopI >= 0 && allowTaskReparenting
6935 && task.affinity != null
6936 && task.affinity.equals(target.taskAffinity)) {
6937 // We are inside of another task... if this activity has
6938 // an affinity for our task, then either remove it if we are
6939 // clearing or move it over to our task. Note that
6940 // we currently punt on the case where we are resetting a
6941 // task that is not at the top but who has activities above
6942 // with an affinity to it... this is really not a normal
6943 // case, and we will need to later pull that task to the front
6944 // and usually at that point we will do the reset and pick
6945 // up those remaining activities. (This only happens if
6946 // someone starts an activity in a new task from an activity
6947 // in a task that is not currently on top.)
6948 if (forceReset || finishOnTaskLaunch) {
6949 if (replyChainEnd < 0) {
6950 replyChainEnd = targetI;
6951 }
6952 HistoryRecord p = null;
6953 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6954 p = (HistoryRecord)mHistory.get(srcPos);
6955 if (p.finishing) {
6956 continue;
6957 }
6958 if (finishActivityLocked(p, srcPos,
6959 Activity.RESULT_CANCELED, null, "reset")) {
6960 taskTopI--;
6961 lastReparentPos--;
6962 replyChainEnd--;
6963 srcPos--;
6964 }
6965 }
6966 replyChainEnd = -1;
6967 } else {
6968 if (replyChainEnd < 0) {
6969 replyChainEnd = targetI;
6970 }
6971 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6972 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6973 if (p.finishing) {
6974 continue;
6975 }
6976 if (lastReparentPos < 0) {
6977 lastReparentPos = taskTopI;
6978 taskTop = p;
6979 } else {
6980 lastReparentPos--;
6981 }
6982 mHistory.remove(srcPos);
6983 p.task.numActivities--;
6984 p.task = task;
6985 mHistory.add(lastReparentPos, p);
6986 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6987 + " in to resetting task " + task);
6988 task.numActivities++;
6989 mWindowManager.moveAppToken(lastReparentPos, p);
6990 mWindowManager.setAppGroupId(p, p.task.taskId);
6991 if (VALIDATE_TOKENS) {
6992 mWindowManager.validateAppTokens(mHistory);
6993 }
6994 }
6995 replyChainEnd = -1;
6996
6997 // Now we've moved it in to place... but what if this is
6998 // a singleTop activity and we have put it on top of another
6999 // instance of the same activity? Then we drop the instance
7000 // below so it remains singleTop.
7001 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
7002 for (int j=lastReparentPos-1; j>=0; j--) {
7003 HistoryRecord p = (HistoryRecord)mHistory.get(j);
7004 if (p.finishing) {
7005 continue;
7006 }
7007 if (p.intent.getComponent().equals(target.intent.getComponent())) {
7008 if (finishActivityLocked(p, j,
7009 Activity.RESULT_CANCELED, null, "replace")) {
7010 taskTopI--;
7011 lastReparentPos--;
7012 }
7013 }
7014 }
7015 }
7016 }
7017 }
7018
7019 target = below;
7020 targetI = i;
7021 }
7022
7023 return taskTop;
7024 }
7025
7026 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007027 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007028 */
7029 public void moveTaskToFront(int task) {
7030 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7031 "moveTaskToFront()");
7032
7033 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007034 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7035 Binder.getCallingUid(), "Task to front")) {
7036 return;
7037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007038 final long origId = Binder.clearCallingIdentity();
7039 try {
7040 int N = mRecentTasks.size();
7041 for (int i=0; i<N; i++) {
7042 TaskRecord tr = mRecentTasks.get(i);
7043 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007044 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007045 return;
7046 }
7047 }
7048 for (int i=mHistory.size()-1; i>=0; i--) {
7049 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7050 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007051 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007052 return;
7053 }
7054 }
7055 } finally {
7056 Binder.restoreCallingIdentity(origId);
7057 }
7058 }
7059 }
7060
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007061 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007062 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7063
7064 final int task = tr.taskId;
7065 int top = mHistory.size()-1;
7066
7067 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7068 // nothing to do!
7069 return;
7070 }
7071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007072 ArrayList moved = new ArrayList();
7073
7074 // Applying the affinities may have removed entries from the history,
7075 // so get the size again.
7076 top = mHistory.size()-1;
7077 int pos = top;
7078
7079 // Shift all activities with this task up to the top
7080 // of the stack, keeping them in the same internal order.
7081 while (pos >= 0) {
7082 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7083 if (localLOGV) Log.v(
7084 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7085 boolean first = true;
7086 if (r.task.taskId == task) {
7087 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7088 mHistory.remove(pos);
7089 mHistory.add(top, r);
7090 moved.add(0, r);
7091 top--;
7092 if (first) {
7093 addRecentTask(r.task);
7094 first = false;
7095 }
7096 }
7097 pos--;
7098 }
7099
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007100 if (DEBUG_TRANSITION) Log.v(TAG,
7101 "Prepare to front transition: task=" + tr);
7102 if (reason != null &&
7103 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7104 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7105 HistoryRecord r = topRunningActivityLocked(null);
7106 if (r != null) {
7107 mNoAnimActivities.add(r);
7108 }
7109 } else {
7110 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7111 }
7112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007113 mWindowManager.moveAppTokensToTop(moved);
7114 if (VALIDATE_TOKENS) {
7115 mWindowManager.validateAppTokens(mHistory);
7116 }
7117
7118 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007119 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007120 }
7121
7122 private final void finishTaskMove(int task) {
7123 resumeTopActivityLocked(null);
7124 }
7125
7126 public void moveTaskToBack(int task) {
7127 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7128 "moveTaskToBack()");
7129
7130 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007131 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7132 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7133 Binder.getCallingUid(), "Task to back")) {
7134 return;
7135 }
7136 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007137 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007138 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007139 Binder.restoreCallingIdentity(origId);
7140 }
7141 }
7142
7143 /**
7144 * Moves an activity, and all of the other activities within the same task, to the bottom
7145 * of the history stack. The activity's order within the task is unchanged.
7146 *
7147 * @param token A reference to the activity we wish to move
7148 * @param nonRoot If false then this only works if the activity is the root
7149 * of a task; if true it will work for any activity in a task.
7150 * @return Returns true if the move completed, false if not.
7151 */
7152 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7153 synchronized(this) {
7154 final long origId = Binder.clearCallingIdentity();
7155 int taskId = getTaskForActivityLocked(token, !nonRoot);
7156 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007157 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007158 }
7159 Binder.restoreCallingIdentity(origId);
7160 }
7161 return false;
7162 }
7163
7164 /**
7165 * Worker method for rearranging history stack. Implements the function of moving all
7166 * activities for a specific task (gathering them if disjoint) into a single group at the
7167 * bottom of the stack.
7168 *
7169 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7170 * to premeptively cancel the move.
7171 *
7172 * @param task The taskId to collect and move to the bottom.
7173 * @return Returns true if the move completed, false if not.
7174 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007175 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007176 Log.i(TAG, "moveTaskToBack: " + task);
7177
7178 // If we have a watcher, preflight the move before committing to it. First check
7179 // for *other* available tasks, but if none are available, then try again allowing the
7180 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007181 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007182 HistoryRecord next = topRunningActivityLocked(null, task);
7183 if (next == null) {
7184 next = topRunningActivityLocked(null, 0);
7185 }
7186 if (next != null) {
7187 // ask watcher if this is allowed
7188 boolean moveOK = true;
7189 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007190 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007191 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007192 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007193 }
7194 if (!moveOK) {
7195 return false;
7196 }
7197 }
7198 }
7199
7200 ArrayList moved = new ArrayList();
7201
7202 if (DEBUG_TRANSITION) Log.v(TAG,
7203 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007204
7205 final int N = mHistory.size();
7206 int bottom = 0;
7207 int pos = 0;
7208
7209 // Shift all activities with this task down to the bottom
7210 // of the stack, keeping them in the same internal order.
7211 while (pos < N) {
7212 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7213 if (localLOGV) Log.v(
7214 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7215 if (r.task.taskId == task) {
7216 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7217 mHistory.remove(pos);
7218 mHistory.add(bottom, r);
7219 moved.add(r);
7220 bottom++;
7221 }
7222 pos++;
7223 }
7224
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007225 if (reason != null &&
7226 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7227 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7228 HistoryRecord r = topRunningActivityLocked(null);
7229 if (r != null) {
7230 mNoAnimActivities.add(r);
7231 }
7232 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007233 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007235 mWindowManager.moveAppTokensToBottom(moved);
7236 if (VALIDATE_TOKENS) {
7237 mWindowManager.validateAppTokens(mHistory);
7238 }
7239
7240 finishTaskMove(task);
7241 return true;
7242 }
7243
7244 public void moveTaskBackwards(int task) {
7245 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7246 "moveTaskBackwards()");
7247
7248 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007249 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7250 Binder.getCallingUid(), "Task backwards")) {
7251 return;
7252 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007253 final long origId = Binder.clearCallingIdentity();
7254 moveTaskBackwardsLocked(task);
7255 Binder.restoreCallingIdentity(origId);
7256 }
7257 }
7258
7259 private final void moveTaskBackwardsLocked(int task) {
7260 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7261 }
7262
7263 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7264 synchronized(this) {
7265 return getTaskForActivityLocked(token, onlyRoot);
7266 }
7267 }
7268
7269 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7270 final int N = mHistory.size();
7271 TaskRecord lastTask = null;
7272 for (int i=0; i<N; i++) {
7273 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7274 if (r == token) {
7275 if (!onlyRoot || lastTask != r.task) {
7276 return r.task.taskId;
7277 }
7278 return -1;
7279 }
7280 lastTask = r.task;
7281 }
7282
7283 return -1;
7284 }
7285
7286 /**
7287 * Returns the top activity in any existing task matching the given
7288 * Intent. Returns null if no such task is found.
7289 */
7290 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7291 ComponentName cls = intent.getComponent();
7292 if (info.targetActivity != null) {
7293 cls = new ComponentName(info.packageName, info.targetActivity);
7294 }
7295
7296 TaskRecord cp = null;
7297
7298 final int N = mHistory.size();
7299 for (int i=(N-1); i>=0; i--) {
7300 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7301 if (!r.finishing && r.task != cp
7302 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7303 cp = r.task;
7304 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7305 // + "/aff=" + r.task.affinity + " to new cls="
7306 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7307 if (r.task.affinity != null) {
7308 if (r.task.affinity.equals(info.taskAffinity)) {
7309 //Log.i(TAG, "Found matching affinity!");
7310 return r;
7311 }
7312 } else if (r.task.intent != null
7313 && r.task.intent.getComponent().equals(cls)) {
7314 //Log.i(TAG, "Found matching class!");
7315 //dump();
7316 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7317 return r;
7318 } else if (r.task.affinityIntent != null
7319 && r.task.affinityIntent.getComponent().equals(cls)) {
7320 //Log.i(TAG, "Found matching class!");
7321 //dump();
7322 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7323 return r;
7324 }
7325 }
7326 }
7327
7328 return null;
7329 }
7330
7331 /**
7332 * Returns the first activity (starting from the top of the stack) that
7333 * is the same as the given activity. Returns null if no such activity
7334 * is found.
7335 */
7336 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7337 ComponentName cls = intent.getComponent();
7338 if (info.targetActivity != null) {
7339 cls = new ComponentName(info.packageName, info.targetActivity);
7340 }
7341
7342 final int N = mHistory.size();
7343 for (int i=(N-1); i>=0; i--) {
7344 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7345 if (!r.finishing) {
7346 if (r.intent.getComponent().equals(cls)) {
7347 //Log.i(TAG, "Found matching class!");
7348 //dump();
7349 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7350 return r;
7351 }
7352 }
7353 }
7354
7355 return null;
7356 }
7357
7358 public void finishOtherInstances(IBinder token, ComponentName className) {
7359 synchronized(this) {
7360 final long origId = Binder.clearCallingIdentity();
7361
7362 int N = mHistory.size();
7363 TaskRecord lastTask = null;
7364 for (int i=0; i<N; i++) {
7365 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7366 if (r.realActivity.equals(className)
7367 && r != token && lastTask != r.task) {
7368 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7369 null, "others")) {
7370 i--;
7371 N--;
7372 }
7373 }
7374 lastTask = r.task;
7375 }
7376
7377 Binder.restoreCallingIdentity(origId);
7378 }
7379 }
7380
7381 // =========================================================
7382 // THUMBNAILS
7383 // =========================================================
7384
7385 public void reportThumbnail(IBinder token,
7386 Bitmap thumbnail, CharSequence description) {
7387 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7388 final long origId = Binder.clearCallingIdentity();
7389 sendPendingThumbnail(null, token, thumbnail, description, true);
7390 Binder.restoreCallingIdentity(origId);
7391 }
7392
7393 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7394 Bitmap thumbnail, CharSequence description, boolean always) {
7395 TaskRecord task = null;
7396 ArrayList receivers = null;
7397
7398 //System.out.println("Send pending thumbnail: " + r);
7399
7400 synchronized(this) {
7401 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007402 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007403 if (index < 0) {
7404 return;
7405 }
7406 r = (HistoryRecord)mHistory.get(index);
7407 }
7408 if (thumbnail == null) {
7409 thumbnail = r.thumbnail;
7410 description = r.description;
7411 }
7412 if (thumbnail == null && !always) {
7413 // If there is no thumbnail, and this entry is not actually
7414 // going away, then abort for now and pick up the next
7415 // thumbnail we get.
7416 return;
7417 }
7418 task = r.task;
7419
7420 int N = mPendingThumbnails.size();
7421 int i=0;
7422 while (i<N) {
7423 PendingThumbnailsRecord pr =
7424 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7425 //System.out.println("Looking in " + pr.pendingRecords);
7426 if (pr.pendingRecords.remove(r)) {
7427 if (receivers == null) {
7428 receivers = new ArrayList();
7429 }
7430 receivers.add(pr);
7431 if (pr.pendingRecords.size() == 0) {
7432 pr.finished = true;
7433 mPendingThumbnails.remove(i);
7434 N--;
7435 continue;
7436 }
7437 }
7438 i++;
7439 }
7440 }
7441
7442 if (receivers != null) {
7443 final int N = receivers.size();
7444 for (int i=0; i<N; i++) {
7445 try {
7446 PendingThumbnailsRecord pr =
7447 (PendingThumbnailsRecord)receivers.get(i);
7448 pr.receiver.newThumbnail(
7449 task != null ? task.taskId : -1, thumbnail, description);
7450 if (pr.finished) {
7451 pr.receiver.finished();
7452 }
7453 } catch (Exception e) {
7454 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7455 }
7456 }
7457 }
7458 }
7459
7460 // =========================================================
7461 // CONTENT PROVIDERS
7462 // =========================================================
7463
7464 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7465 List providers = null;
7466 try {
7467 providers = ActivityThread.getPackageManager().
7468 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007469 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007470 } catch (RemoteException ex) {
7471 }
7472 if (providers != null) {
7473 final int N = providers.size();
7474 for (int i=0; i<N; i++) {
7475 ProviderInfo cpi =
7476 (ProviderInfo)providers.get(i);
7477 ContentProviderRecord cpr =
7478 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7479 if (cpr == null) {
7480 cpr = new ContentProviderRecord(cpi, app.info);
7481 mProvidersByClass.put(cpi.name, cpr);
7482 }
7483 app.pubProviders.put(cpi.name, cpr);
7484 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007485 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007486 }
7487 }
7488 return providers;
7489 }
7490
7491 private final String checkContentProviderPermissionLocked(
7492 ProviderInfo cpi, ProcessRecord r, int mode) {
7493 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7494 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7495 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7496 cpi.exported ? -1 : cpi.applicationInfo.uid)
7497 == PackageManager.PERMISSION_GRANTED
7498 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7499 return null;
7500 }
7501 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7502 cpi.exported ? -1 : cpi.applicationInfo.uid)
7503 == PackageManager.PERMISSION_GRANTED) {
7504 return null;
7505 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007506
7507 PathPermission[] pps = cpi.pathPermissions;
7508 if (pps != null) {
7509 int i = pps.length;
7510 while (i > 0) {
7511 i--;
7512 PathPermission pp = pps[i];
7513 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7514 cpi.exported ? -1 : cpi.applicationInfo.uid)
7515 == PackageManager.PERMISSION_GRANTED
7516 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7517 return null;
7518 }
7519 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7520 cpi.exported ? -1 : cpi.applicationInfo.uid)
7521 == PackageManager.PERMISSION_GRANTED) {
7522 return null;
7523 }
7524 }
7525 }
7526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007527 String msg = "Permission Denial: opening provider " + cpi.name
7528 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7529 + ", uid=" + callingUid + ") requires "
7530 + cpi.readPermission + " or " + cpi.writePermission;
7531 Log.w(TAG, msg);
7532 return msg;
7533 }
7534
7535 private final ContentProviderHolder getContentProviderImpl(
7536 IApplicationThread caller, String name) {
7537 ContentProviderRecord cpr;
7538 ProviderInfo cpi = null;
7539
7540 synchronized(this) {
7541 ProcessRecord r = null;
7542 if (caller != null) {
7543 r = getRecordForAppLocked(caller);
7544 if (r == null) {
7545 throw new SecurityException(
7546 "Unable to find app for caller " + caller
7547 + " (pid=" + Binder.getCallingPid()
7548 + ") when getting content provider " + name);
7549 }
7550 }
7551
7552 // First check if this content provider has been published...
7553 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7554 if (cpr != null) {
7555 cpi = cpr.info;
7556 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7557 return new ContentProviderHolder(cpi,
7558 cpi.readPermission != null
7559 ? cpi.readPermission : cpi.writePermission);
7560 }
7561
7562 if (r != null && cpr.canRunHere(r)) {
7563 // This provider has been published or is in the process
7564 // of being published... but it is also allowed to run
7565 // in the caller's process, so don't make a connection
7566 // and just let the caller instantiate its own instance.
7567 if (cpr.provider != null) {
7568 // don't give caller the provider object, it needs
7569 // to make its own.
7570 cpr = new ContentProviderRecord(cpr);
7571 }
7572 return cpr;
7573 }
7574
7575 final long origId = Binder.clearCallingIdentity();
7576
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007577 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007578 // return it right away.
7579 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007580 if (DEBUG_PROVIDER) Log.v(TAG,
7581 "Adding provider requested by "
7582 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007583 + cpr.info.processName);
7584 Integer cnt = r.conProviders.get(cpr);
7585 if (cnt == null) {
7586 r.conProviders.put(cpr, new Integer(1));
7587 } else {
7588 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7589 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007590 cpr.clients.add(r);
7591 } else {
7592 cpr.externals++;
7593 }
7594
7595 if (cpr.app != null) {
7596 updateOomAdjLocked(cpr.app);
7597 }
7598
7599 Binder.restoreCallingIdentity(origId);
7600
7601 } else {
7602 try {
7603 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007604 resolveContentProvider(name,
7605 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007606 } catch (RemoteException ex) {
7607 }
7608 if (cpi == null) {
7609 return null;
7610 }
7611
7612 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7613 return new ContentProviderHolder(cpi,
7614 cpi.readPermission != null
7615 ? cpi.readPermission : cpi.writePermission);
7616 }
7617
Dianne Hackbornc3b91fd2010-02-23 17:25:30 -08007618 if (!mSystemReady && !mDidUpdate && !mWaitingUpdate
7619 && !cpi.processName.equals("system")) {
7620 // If this content provider does not run in the system
7621 // process, and the system is not yet ready to run other
7622 // processes, then fail fast instead of hanging.
7623 throw new IllegalArgumentException(
7624 "Attempt to launch content provider before system ready");
7625 }
7626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007627 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7628 final boolean firstClass = cpr == null;
7629 if (firstClass) {
7630 try {
7631 ApplicationInfo ai =
7632 ActivityThread.getPackageManager().
7633 getApplicationInfo(
7634 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007635 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007636 if (ai == null) {
7637 Log.w(TAG, "No package info for content provider "
7638 + cpi.name);
7639 return null;
7640 }
7641 cpr = new ContentProviderRecord(cpi, ai);
7642 } catch (RemoteException ex) {
7643 // pm is in same process, this will never happen.
7644 }
7645 }
7646
7647 if (r != null && cpr.canRunHere(r)) {
7648 // If this is a multiprocess provider, then just return its
7649 // info and allow the caller to instantiate it. Only do
7650 // this if the provider is the same user as the caller's
7651 // process, or can run as root (so can be in any process).
7652 return cpr;
7653 }
7654
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007655 if (DEBUG_PROVIDER) {
7656 RuntimeException e = new RuntimeException("here");
7657 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7658 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007659 }
7660
7661 // This is single process, and our app is now connecting to it.
7662 // See if we are already in the process of launching this
7663 // provider.
7664 final int N = mLaunchingProviders.size();
7665 int i;
7666 for (i=0; i<N; i++) {
7667 if (mLaunchingProviders.get(i) == cpr) {
7668 break;
7669 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007670 }
7671
7672 // If the provider is not already being launched, then get it
7673 // started.
7674 if (i >= N) {
7675 final long origId = Binder.clearCallingIdentity();
7676 ProcessRecord proc = startProcessLocked(cpi.processName,
7677 cpr.appInfo, false, 0, "content provider",
7678 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007679 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007680 if (proc == null) {
7681 Log.w(TAG, "Unable to launch app "
7682 + cpi.applicationInfo.packageName + "/"
7683 + cpi.applicationInfo.uid + " for provider "
7684 + name + ": process is bad");
7685 return null;
7686 }
7687 cpr.launchingApp = proc;
7688 mLaunchingProviders.add(cpr);
7689 Binder.restoreCallingIdentity(origId);
7690 }
7691
7692 // Make sure the provider is published (the same provider class
7693 // may be published under multiple names).
7694 if (firstClass) {
7695 mProvidersByClass.put(cpi.name, cpr);
7696 }
7697 mProvidersByName.put(name, cpr);
7698
7699 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007700 if (DEBUG_PROVIDER) Log.v(TAG,
7701 "Adding provider requested by "
7702 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007703 + cpr.info.processName);
7704 Integer cnt = r.conProviders.get(cpr);
7705 if (cnt == null) {
7706 r.conProviders.put(cpr, new Integer(1));
7707 } else {
7708 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7709 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007710 cpr.clients.add(r);
7711 } else {
7712 cpr.externals++;
7713 }
7714 }
7715 }
7716
7717 // Wait for the provider to be published...
7718 synchronized (cpr) {
7719 while (cpr.provider == null) {
7720 if (cpr.launchingApp == null) {
7721 Log.w(TAG, "Unable to launch app "
7722 + cpi.applicationInfo.packageName + "/"
7723 + cpi.applicationInfo.uid + " for provider "
7724 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007725 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007726 cpi.applicationInfo.packageName,
7727 cpi.applicationInfo.uid, name);
7728 return null;
7729 }
7730 try {
7731 cpr.wait();
7732 } catch (InterruptedException ex) {
7733 }
7734 }
7735 }
7736 return cpr;
7737 }
7738
7739 public final ContentProviderHolder getContentProvider(
7740 IApplicationThread caller, String name) {
7741 if (caller == null) {
7742 String msg = "null IApplicationThread when getting content provider "
7743 + name;
7744 Log.w(TAG, msg);
7745 throw new SecurityException(msg);
7746 }
7747
7748 return getContentProviderImpl(caller, name);
7749 }
7750
7751 private ContentProviderHolder getContentProviderExternal(String name) {
7752 return getContentProviderImpl(null, name);
7753 }
7754
7755 /**
7756 * Drop a content provider from a ProcessRecord's bookkeeping
7757 * @param cpr
7758 */
7759 public void removeContentProvider(IApplicationThread caller, String name) {
7760 synchronized (this) {
7761 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7762 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007763 // remove from mProvidersByClass
7764 if (DEBUG_PROVIDER) Log.v(TAG, name +
7765 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007766 return;
7767 }
7768 final ProcessRecord r = getRecordForAppLocked(caller);
7769 if (r == null) {
7770 throw new SecurityException(
7771 "Unable to find app for caller " + caller +
7772 " when removing content provider " + name);
7773 }
7774 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007775 ContentProviderRecord localCpr = (ContentProviderRecord)
7776 mProvidersByClass.get(cpr.info.name);
7777 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7778 + r.info.processName + " from process "
7779 + localCpr.appInfo.processName);
7780 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007781 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007782 Log.w(TAG, "removeContentProvider called on local provider: "
7783 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007784 return;
7785 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007786 Integer cnt = r.conProviders.get(localCpr);
7787 if (cnt == null || cnt.intValue() <= 1) {
7788 localCpr.clients.remove(r);
7789 r.conProviders.remove(localCpr);
7790 } else {
7791 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007793 }
7794 updateOomAdjLocked();
7795 }
7796 }
7797
7798 private void removeContentProviderExternal(String name) {
7799 synchronized (this) {
7800 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7801 if(cpr == null) {
7802 //remove from mProvidersByClass
7803 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7804 return;
7805 }
7806
7807 //update content provider record entry info
7808 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7809 localCpr.externals--;
7810 if (localCpr.externals < 0) {
7811 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7812 }
7813 updateOomAdjLocked();
7814 }
7815 }
7816
7817 public final void publishContentProviders(IApplicationThread caller,
7818 List<ContentProviderHolder> providers) {
7819 if (providers == null) {
7820 return;
7821 }
7822
7823 synchronized(this) {
7824 final ProcessRecord r = getRecordForAppLocked(caller);
7825 if (r == null) {
7826 throw new SecurityException(
7827 "Unable to find app for caller " + caller
7828 + " (pid=" + Binder.getCallingPid()
7829 + ") when publishing content providers");
7830 }
7831
7832 final long origId = Binder.clearCallingIdentity();
7833
7834 final int N = providers.size();
7835 for (int i=0; i<N; i++) {
7836 ContentProviderHolder src = providers.get(i);
7837 if (src == null || src.info == null || src.provider == null) {
7838 continue;
7839 }
7840 ContentProviderRecord dst =
7841 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7842 if (dst != null) {
7843 mProvidersByClass.put(dst.info.name, dst);
7844 String names[] = dst.info.authority.split(";");
7845 for (int j = 0; j < names.length; j++) {
7846 mProvidersByName.put(names[j], dst);
7847 }
7848
7849 int NL = mLaunchingProviders.size();
7850 int j;
7851 for (j=0; j<NL; j++) {
7852 if (mLaunchingProviders.get(j) == dst) {
7853 mLaunchingProviders.remove(j);
7854 j--;
7855 NL--;
7856 }
7857 }
7858 synchronized (dst) {
7859 dst.provider = src.provider;
7860 dst.app = r;
7861 dst.notifyAll();
7862 }
7863 updateOomAdjLocked(r);
7864 }
7865 }
7866
7867 Binder.restoreCallingIdentity(origId);
7868 }
7869 }
7870
7871 public static final void installSystemProviders() {
7872 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7873 List providers = mSelf.generateApplicationProvidersLocked(app);
Dianne Hackbornc3b91fd2010-02-23 17:25:30 -08007874 if (providers != null) {
7875 for (int i=providers.size()-1; i>=0; i--) {
7876 ProviderInfo pi = (ProviderInfo)providers.get(i);
7877 if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
7878 Log.w(TAG, "Not installing system proc provider " + pi.name
7879 + ": not system .apk");
7880 providers.remove(i);
7881 }
7882 }
7883 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007884 mSystemThread.installSystemProviders(providers);
7885 }
7886
7887 // =========================================================
7888 // GLOBAL MANAGEMENT
7889 // =========================================================
7890
7891 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7892 ApplicationInfo info, String customProcess) {
7893 String proc = customProcess != null ? customProcess : info.processName;
7894 BatteryStatsImpl.Uid.Proc ps = null;
7895 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7896 synchronized (stats) {
7897 ps = stats.getProcessStatsLocked(info.uid, proc);
7898 }
7899 return new ProcessRecord(ps, thread, info, proc);
7900 }
7901
7902 final ProcessRecord addAppLocked(ApplicationInfo info) {
7903 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7904
7905 if (app == null) {
7906 app = newProcessRecordLocked(null, info, null);
7907 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007908 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007909 }
7910
7911 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7912 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7913 app.persistent = true;
7914 app.maxAdj = CORE_SERVER_ADJ;
7915 }
7916 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7917 mPersistentStartingProcesses.add(app);
7918 startProcessLocked(app, "added application", app.processName);
7919 }
7920
7921 return app;
7922 }
7923
7924 public void unhandledBack() {
7925 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7926 "unhandledBack()");
7927
7928 synchronized(this) {
7929 int count = mHistory.size();
Dianne Hackborn03abb812010-01-04 18:43:19 -08007930 if (DEBUG_SWITCH) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007931 TAG, "Performing unhandledBack(): stack size = " + count);
7932 if (count > 1) {
7933 final long origId = Binder.clearCallingIdentity();
7934 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7935 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7936 Binder.restoreCallingIdentity(origId);
7937 }
7938 }
7939 }
7940
7941 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7942 String name = uri.getAuthority();
7943 ContentProviderHolder cph = getContentProviderExternal(name);
7944 ParcelFileDescriptor pfd = null;
7945 if (cph != null) {
7946 // We record the binder invoker's uid in thread-local storage before
7947 // going to the content provider to open the file. Later, in the code
7948 // that handles all permissions checks, we look for this uid and use
7949 // that rather than the Activity Manager's own uid. The effect is that
7950 // we do the check against the caller's permissions even though it looks
7951 // to the content provider like the Activity Manager itself is making
7952 // the request.
7953 sCallerIdentity.set(new Identity(
7954 Binder.getCallingPid(), Binder.getCallingUid()));
7955 try {
7956 pfd = cph.provider.openFile(uri, "r");
7957 } catch (FileNotFoundException e) {
7958 // do nothing; pfd will be returned null
7959 } finally {
7960 // Ensure that whatever happens, we clean up the identity state
7961 sCallerIdentity.remove();
7962 }
7963
7964 // We've got the fd now, so we're done with the provider.
7965 removeContentProviderExternal(name);
7966 } else {
7967 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7968 }
7969 return pfd;
7970 }
7971
7972 public void goingToSleep() {
7973 synchronized(this) {
7974 mSleeping = true;
7975 mWindowManager.setEventDispatching(false);
7976
7977 if (mResumedActivity != null) {
7978 pauseIfSleepingLocked();
7979 } else {
7980 Log.w(TAG, "goingToSleep with no resumed activity!");
7981 }
7982 }
7983 }
7984
Dianne Hackborn55280a92009-05-07 15:53:46 -07007985 public boolean shutdown(int timeout) {
7986 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7987 != PackageManager.PERMISSION_GRANTED) {
7988 throw new SecurityException("Requires permission "
7989 + android.Manifest.permission.SHUTDOWN);
7990 }
7991
7992 boolean timedout = false;
7993
7994 synchronized(this) {
7995 mShuttingDown = true;
7996 mWindowManager.setEventDispatching(false);
7997
7998 if (mResumedActivity != null) {
7999 pauseIfSleepingLocked();
8000 final long endTime = System.currentTimeMillis() + timeout;
8001 while (mResumedActivity != null || mPausingActivity != null) {
8002 long delay = endTime - System.currentTimeMillis();
8003 if (delay <= 0) {
8004 Log.w(TAG, "Activity manager shutdown timed out");
8005 timedout = true;
8006 break;
8007 }
8008 try {
8009 this.wait();
8010 } catch (InterruptedException e) {
8011 }
8012 }
8013 }
8014 }
8015
8016 mUsageStatsService.shutdown();
8017 mBatteryStatsService.shutdown();
8018
8019 return timedout;
8020 }
8021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008022 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07008023 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008024 if (!mGoingToSleep.isHeld()) {
8025 mGoingToSleep.acquire();
8026 if (mLaunchingActivity.isHeld()) {
8027 mLaunchingActivity.release();
8028 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
8029 }
8030 }
8031
8032 // If we are not currently pausing an activity, get the current
8033 // one to pause. If we are pausing one, we will just let that stuff
8034 // run and release the wake lock when all done.
8035 if (mPausingActivity == null) {
8036 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8037 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8038 startPausingLocked(false, true);
8039 }
8040 }
8041 }
8042
8043 public void wakingUp() {
8044 synchronized(this) {
8045 if (mGoingToSleep.isHeld()) {
8046 mGoingToSleep.release();
8047 }
8048 mWindowManager.setEventDispatching(true);
8049 mSleeping = false;
8050 resumeTopActivityLocked(null);
8051 }
8052 }
8053
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008054 public void stopAppSwitches() {
8055 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8056 != PackageManager.PERMISSION_GRANTED) {
8057 throw new SecurityException("Requires permission "
8058 + android.Manifest.permission.STOP_APP_SWITCHES);
8059 }
8060
8061 synchronized(this) {
8062 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8063 + APP_SWITCH_DELAY_TIME;
8064 mDidAppSwitch = false;
8065 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8066 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8067 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8068 }
8069 }
8070
8071 public void resumeAppSwitches() {
8072 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8073 != PackageManager.PERMISSION_GRANTED) {
8074 throw new SecurityException("Requires permission "
8075 + android.Manifest.permission.STOP_APP_SWITCHES);
8076 }
8077
8078 synchronized(this) {
8079 // Note that we don't execute any pending app switches... we will
8080 // let those wait until either the timeout, or the next start
8081 // activity request.
8082 mAppSwitchesAllowedTime = 0;
8083 }
8084 }
8085
8086 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8087 String name) {
8088 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8089 return true;
8090 }
8091
8092 final int perm = checkComponentPermission(
8093 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8094 callingUid, -1);
8095 if (perm == PackageManager.PERMISSION_GRANTED) {
8096 return true;
8097 }
8098
8099 Log.w(TAG, name + " request from " + callingUid + " stopped");
8100 return false;
8101 }
8102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008103 public void setDebugApp(String packageName, boolean waitForDebugger,
8104 boolean persistent) {
8105 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8106 "setDebugApp()");
8107
8108 // Note that this is not really thread safe if there are multiple
8109 // callers into it at the same time, but that's not a situation we
8110 // care about.
8111 if (persistent) {
8112 final ContentResolver resolver = mContext.getContentResolver();
8113 Settings.System.putString(
8114 resolver, Settings.System.DEBUG_APP,
8115 packageName);
8116 Settings.System.putInt(
8117 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8118 waitForDebugger ? 1 : 0);
8119 }
8120
8121 synchronized (this) {
8122 if (!persistent) {
8123 mOrigDebugApp = mDebugApp;
8124 mOrigWaitForDebugger = mWaitForDebugger;
8125 }
8126 mDebugApp = packageName;
8127 mWaitForDebugger = waitForDebugger;
8128 mDebugTransient = !persistent;
8129 if (packageName != null) {
8130 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08008131 forceStopPackageLocked(packageName, -1, false, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008132 Binder.restoreCallingIdentity(origId);
8133 }
8134 }
8135 }
8136
8137 public void setAlwaysFinish(boolean enabled) {
8138 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8139 "setAlwaysFinish()");
8140
8141 Settings.System.putInt(
8142 mContext.getContentResolver(),
8143 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8144
8145 synchronized (this) {
8146 mAlwaysFinishActivities = enabled;
8147 }
8148 }
8149
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008150 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008151 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008152 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008153 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008154 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008155 }
8156 }
8157
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08008158 public boolean isUserAMonkey() {
8159 // For now the fact that there is a controller implies
8160 // we have a monkey.
8161 synchronized (this) {
8162 return mController != null;
8163 }
8164 }
8165
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008166 public void registerActivityWatcher(IActivityWatcher watcher) {
8167 mWatchers.register(watcher);
8168 }
8169
8170 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8171 mWatchers.unregister(watcher);
8172 }
8173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008174 public final void enterSafeMode() {
8175 synchronized(this) {
8176 // It only makes sense to do this before the system is ready
8177 // and started launching other packages.
8178 if (!mSystemReady) {
8179 try {
8180 ActivityThread.getPackageManager().enterSafeMode();
8181 } catch (RemoteException e) {
8182 }
8183
8184 View v = LayoutInflater.from(mContext).inflate(
8185 com.android.internal.R.layout.safe_mode, null);
8186 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8187 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8188 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8189 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8190 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8191 lp.format = v.getBackground().getOpacity();
8192 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8193 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8194 ((WindowManager)mContext.getSystemService(
8195 Context.WINDOW_SERVICE)).addView(v, lp);
8196 }
8197 }
8198 }
8199
8200 public void noteWakeupAlarm(IIntentSender sender) {
8201 if (!(sender instanceof PendingIntentRecord)) {
8202 return;
8203 }
8204 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8205 synchronized (stats) {
8206 if (mBatteryStatsService.isOnBattery()) {
8207 mBatteryStatsService.enforceCallingPermission();
8208 PendingIntentRecord rec = (PendingIntentRecord)sender;
8209 int MY_UID = Binder.getCallingUid();
8210 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8211 BatteryStatsImpl.Uid.Pkg pkg =
8212 stats.getPackageStatsLocked(uid, rec.key.packageName);
8213 pkg.incWakeupsLocked();
8214 }
8215 }
8216 }
8217
8218 public boolean killPidsForMemory(int[] pids) {
8219 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8220 throw new SecurityException("killPidsForMemory only available to the system");
8221 }
8222
8223 // XXX Note: don't acquire main activity lock here, because the window
8224 // manager calls in with its locks held.
8225
8226 boolean killed = false;
8227 synchronized (mPidsSelfLocked) {
8228 int[] types = new int[pids.length];
8229 int worstType = 0;
8230 for (int i=0; i<pids.length; i++) {
8231 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8232 if (proc != null) {
8233 int type = proc.setAdj;
8234 types[i] = type;
8235 if (type > worstType) {
8236 worstType = type;
8237 }
8238 }
8239 }
8240
8241 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8242 // then constrain it so we will kill all hidden procs.
8243 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8244 worstType = HIDDEN_APP_MIN_ADJ;
8245 }
8246 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8247 for (int i=0; i<pids.length; i++) {
8248 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8249 if (proc == null) {
8250 continue;
8251 }
8252 int adj = proc.setAdj;
8253 if (adj >= worstType) {
8254 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8255 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008256 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008257 proc.processName, adj);
8258 killed = true;
8259 Process.killProcess(pids[i]);
8260 }
8261 }
8262 }
8263 return killed;
8264 }
8265
8266 public void reportPss(IApplicationThread caller, int pss) {
8267 Watchdog.PssRequestor req;
8268 String name;
8269 ProcessRecord callerApp;
8270 synchronized (this) {
8271 if (caller == null) {
8272 return;
8273 }
8274 callerApp = getRecordForAppLocked(caller);
8275 if (callerApp == null) {
8276 return;
8277 }
8278 callerApp.lastPss = pss;
8279 req = callerApp;
8280 name = callerApp.processName;
8281 }
8282 Watchdog.getInstance().reportPss(req, name, pss);
8283 if (!callerApp.persistent) {
8284 removeRequestedPss(callerApp);
8285 }
8286 }
8287
8288 public void requestPss(Runnable completeCallback) {
8289 ArrayList<ProcessRecord> procs;
8290 synchronized (this) {
8291 mRequestPssCallback = completeCallback;
8292 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008293 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8294 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008295 if (!proc.persistent) {
8296 mRequestPssList.add(proc);
8297 }
8298 }
8299 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8300 }
8301
8302 int oldPri = Process.getThreadPriority(Process.myTid());
8303 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8304 for (int i=procs.size()-1; i>=0; i--) {
8305 ProcessRecord proc = procs.get(i);
8306 proc.lastPss = 0;
8307 proc.requestPss();
8308 }
8309 Process.setThreadPriority(oldPri);
8310 }
8311
8312 void removeRequestedPss(ProcessRecord proc) {
8313 Runnable callback = null;
8314 synchronized (this) {
8315 if (mRequestPssList.remove(proc)) {
8316 if (mRequestPssList.size() == 0) {
8317 callback = mRequestPssCallback;
8318 mRequestPssCallback = null;
8319 }
8320 }
8321 }
8322
8323 if (callback != null) {
8324 callback.run();
8325 }
8326 }
8327
8328 public void collectPss(Watchdog.PssStats stats) {
8329 stats.mEmptyPss = 0;
8330 stats.mEmptyCount = 0;
8331 stats.mBackgroundPss = 0;
8332 stats.mBackgroundCount = 0;
8333 stats.mServicePss = 0;
8334 stats.mServiceCount = 0;
8335 stats.mVisiblePss = 0;
8336 stats.mVisibleCount = 0;
8337 stats.mForegroundPss = 0;
8338 stats.mForegroundCount = 0;
8339 stats.mNoPssCount = 0;
8340 synchronized (this) {
8341 int i;
8342 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8343 ? mProcDeaths.length : stats.mProcDeaths.length;
8344 int aggr = 0;
8345 for (i=0; i<NPD; i++) {
8346 aggr += mProcDeaths[i];
8347 stats.mProcDeaths[i] = aggr;
8348 }
8349 while (i<stats.mProcDeaths.length) {
8350 stats.mProcDeaths[i] = 0;
8351 i++;
8352 }
8353
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008354 for (i=mLruProcesses.size()-1; i>=0; i--) {
8355 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008356 if (proc.persistent) {
8357 continue;
8358 }
8359 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8360 if (proc.lastPss == 0) {
8361 stats.mNoPssCount++;
8362 continue;
8363 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008364 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8365 if (proc.empty) {
8366 stats.mEmptyPss += proc.lastPss;
8367 stats.mEmptyCount++;
8368 } else {
8369 stats.mBackgroundPss += proc.lastPss;
8370 stats.mBackgroundCount++;
8371 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008372 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8373 stats.mVisiblePss += proc.lastPss;
8374 stats.mVisibleCount++;
8375 } else {
8376 stats.mForegroundPss += proc.lastPss;
8377 stats.mForegroundCount++;
8378 }
8379 }
8380 }
8381 }
8382
8383 public final void startRunning(String pkg, String cls, String action,
8384 String data) {
8385 synchronized(this) {
8386 if (mStartRunning) {
8387 return;
8388 }
8389 mStartRunning = true;
8390 mTopComponent = pkg != null && cls != null
8391 ? new ComponentName(pkg, cls) : null;
8392 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8393 mTopData = data;
8394 if (!mSystemReady) {
8395 return;
8396 }
8397 }
8398
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008399 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008400 }
8401
8402 private void retrieveSettings() {
8403 final ContentResolver resolver = mContext.getContentResolver();
8404 String debugApp = Settings.System.getString(
8405 resolver, Settings.System.DEBUG_APP);
8406 boolean waitForDebugger = Settings.System.getInt(
8407 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8408 boolean alwaysFinishActivities = Settings.System.getInt(
8409 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8410
8411 Configuration configuration = new Configuration();
8412 Settings.System.getConfiguration(resolver, configuration);
8413
8414 synchronized (this) {
8415 mDebugApp = mOrigDebugApp = debugApp;
8416 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8417 mAlwaysFinishActivities = alwaysFinishActivities;
8418 // This happens before any activities are started, so we can
8419 // change mConfiguration in-place.
8420 mConfiguration.updateFrom(configuration);
Dianne Hackborne36d6e22010-02-17 19:46:25 -08008421 mConfigurationSeq = mConfiguration.seq = 1;
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008422 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008423 }
8424 }
8425
8426 public boolean testIsSystemReady() {
8427 // no need to synchronize(this) just to read & return the value
8428 return mSystemReady;
8429 }
8430
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008431 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008432 // In the simulator, startRunning will never have been called, which
8433 // normally sets a few crucial variables. Do it here instead.
8434 if (!Process.supportsProcesses()) {
8435 mStartRunning = true;
8436 mTopAction = Intent.ACTION_MAIN;
8437 }
8438
8439 synchronized(this) {
8440 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008441 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008442 return;
8443 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008444
8445 // Check to see if there are any update receivers to run.
8446 if (!mDidUpdate) {
8447 if (mWaitingUpdate) {
8448 return;
8449 }
8450 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8451 List<ResolveInfo> ris = null;
8452 try {
8453 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8454 intent, null, 0);
8455 } catch (RemoteException e) {
8456 }
8457 if (ris != null) {
8458 for (int i=ris.size()-1; i>=0; i--) {
8459 if ((ris.get(i).activityInfo.applicationInfo.flags
8460 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8461 ris.remove(i);
8462 }
8463 }
8464 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8465 for (int i=0; i<ris.size(); i++) {
8466 ActivityInfo ai = ris.get(i).activityInfo;
8467 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8468 IIntentReceiver finisher = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -08008469 if (i == ris.size()-1) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008470 finisher = new IIntentReceiver.Stub() {
8471 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008472 String data, Bundle extras, boolean ordered,
8473 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008474 throws RemoteException {
8475 synchronized (ActivityManagerService.this) {
8476 mDidUpdate = true;
8477 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008478 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008479 }
8480 };
8481 }
8482 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8483 broadcastIntentLocked(null, null, intent, null, finisher,
8484 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornd6847842010-01-12 18:14:19 -08008485 if (finisher != null) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008486 mWaitingUpdate = true;
8487 }
8488 }
8489 }
8490 if (mWaitingUpdate) {
8491 return;
8492 }
8493 mDidUpdate = true;
8494 }
8495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008496 mSystemReady = true;
8497 if (!mStartRunning) {
8498 return;
8499 }
8500 }
8501
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008502 ArrayList<ProcessRecord> procsToKill = null;
8503 synchronized(mPidsSelfLocked) {
8504 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8505 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8506 if (!isAllowedWhileBooting(proc.info)){
8507 if (procsToKill == null) {
8508 procsToKill = new ArrayList<ProcessRecord>();
8509 }
8510 procsToKill.add(proc);
8511 }
8512 }
8513 }
8514
8515 if (procsToKill != null) {
8516 synchronized(this) {
8517 for (int i=procsToKill.size()-1; i>=0; i--) {
8518 ProcessRecord proc = procsToKill.get(i);
8519 Log.i(TAG, "Removing system update proc: " + proc);
8520 removeProcessLocked(proc, true);
8521 }
8522 }
8523 }
8524
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008525 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008526 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008527 SystemClock.uptimeMillis());
8528
8529 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008530 // Make sure we have no pre-ready processes sitting around.
8531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008532 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8533 ResolveInfo ri = mContext.getPackageManager()
8534 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008535 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008536 CharSequence errorMsg = null;
8537 if (ri != null) {
8538 ActivityInfo ai = ri.activityInfo;
8539 ApplicationInfo app = ai.applicationInfo;
8540 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8541 mTopAction = Intent.ACTION_FACTORY_TEST;
8542 mTopData = null;
8543 mTopComponent = new ComponentName(app.packageName,
8544 ai.name);
8545 } else {
8546 errorMsg = mContext.getResources().getText(
8547 com.android.internal.R.string.factorytest_not_system);
8548 }
8549 } else {
8550 errorMsg = mContext.getResources().getText(
8551 com.android.internal.R.string.factorytest_no_action);
8552 }
8553 if (errorMsg != null) {
8554 mTopAction = null;
8555 mTopData = null;
8556 mTopComponent = null;
8557 Message msg = Message.obtain();
8558 msg.what = SHOW_FACTORY_ERROR_MSG;
8559 msg.getData().putCharSequence("msg", errorMsg);
8560 mHandler.sendMessage(msg);
8561 }
8562 }
8563 }
8564
8565 retrieveSettings();
8566
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008567 if (goingCallback != null) goingCallback.run();
8568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008569 synchronized (this) {
8570 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8571 try {
8572 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008573 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008574 if (apps != null) {
8575 int N = apps.size();
8576 int i;
8577 for (i=0; i<N; i++) {
8578 ApplicationInfo info
8579 = (ApplicationInfo)apps.get(i);
8580 if (info != null &&
8581 !info.packageName.equals("android")) {
8582 addAppLocked(info);
8583 }
8584 }
8585 }
8586 } catch (RemoteException ex) {
8587 // pm is in same process, this will never happen.
8588 }
8589 }
8590
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008591 // Start up initial activity.
8592 mBooting = true;
8593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008594 try {
8595 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8596 Message msg = Message.obtain();
8597 msg.what = SHOW_UID_ERROR_MSG;
8598 mHandler.sendMessage(msg);
8599 }
8600 } catch (RemoteException e) {
8601 }
8602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008603 resumeTopActivityLocked(null);
8604 }
8605 }
8606
Dan Egnorb7f03672009-12-09 16:22:32 -08008607 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008608 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008609 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008610 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008611 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008612 startAppProblemLocked(app);
8613 app.stopFreezingAllLocked();
8614 return handleAppCrashLocked(app);
8615 }
8616
Dan Egnorb7f03672009-12-09 16:22:32 -08008617 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008618 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008619 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008620 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008621 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8622 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008623 startAppProblemLocked(app);
8624 app.stopFreezingAllLocked();
8625 }
8626
8627 /**
8628 * Generate a process error record, suitable for attachment to a ProcessRecord.
8629 *
8630 * @param app The ProcessRecord in which the error occurred.
8631 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8632 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008633 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008634 * @param shortMsg Short message describing the crash.
8635 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008636 * @param stackTrace Full crash stack trace, may be null.
8637 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008638 * @return Returns a fully-formed AppErrorStateInfo record.
8639 */
8640 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008641 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008642 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008644 report.condition = condition;
8645 report.processName = app.processName;
8646 report.pid = app.pid;
8647 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008648 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008649 report.shortMsg = shortMsg;
8650 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008651 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008652
8653 return report;
8654 }
8655
Dan Egnor42471dd2010-01-07 17:25:22 -08008656 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008657 synchronized (this) {
8658 app.crashing = false;
8659 app.crashingReport = null;
8660 app.notResponding = false;
8661 app.notRespondingReport = null;
8662 if (app.anrDialog == fromDialog) {
8663 app.anrDialog = null;
8664 }
8665 if (app.waitDialog == fromDialog) {
8666 app.waitDialog = null;
8667 }
8668 if (app.pid > 0 && app.pid != MY_PID) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008669 handleAppCrashLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008670 Log.i(ActivityManagerService.TAG, "Killing process "
8671 + app.processName
8672 + " (pid=" + app.pid + ") at user's request");
8673 Process.killProcess(app.pid);
8674 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008675 }
8676 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008677
Dan Egnorb7f03672009-12-09 16:22:32 -08008678 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008679 long now = SystemClock.uptimeMillis();
8680
8681 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8682 app.info.uid);
8683 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8684 // This process loses!
8685 Log.w(TAG, "Process " + app.info.processName
8686 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008687 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008688 app.info.processName, app.info.uid);
8689 killServicesLocked(app, false);
8690 for (int i=mHistory.size()-1; i>=0; i--) {
8691 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8692 if (r.app == app) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08008693 Log.w(TAG, " Force finishing activity "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008694 + r.intent.getComponent().flattenToShortString());
8695 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8696 }
8697 }
8698 if (!app.persistent) {
8699 // We don't want to start this process again until the user
8700 // explicitly does so... but for persistent process, we really
8701 // need to keep it running. If a persistent process is actually
8702 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008703 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008704 app.info.processName);
8705 mBadProcesses.put(app.info.processName, app.info.uid, now);
8706 app.bad = true;
8707 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8708 app.removed = true;
8709 removeProcessLocked(app, false);
8710 return false;
8711 }
8712 }
8713
8714 // Bump up the crash count of any services currently running in the proc.
8715 if (app.services.size() != 0) {
8716 // Any services running in the application need to be placed
8717 // back in the pending list.
8718 Iterator it = app.services.iterator();
8719 while (it.hasNext()) {
8720 ServiceRecord sr = (ServiceRecord)it.next();
8721 sr.crashCount++;
8722 }
8723 }
8724
8725 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8726 return true;
8727 }
8728
8729 void startAppProblemLocked(ProcessRecord app) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08008730 app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
8731 mContext, app.info.packageName, app.info.flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008732 skipCurrentReceiverLocked(app);
8733 }
8734
8735 void skipCurrentReceiverLocked(ProcessRecord app) {
8736 boolean reschedule = false;
8737 BroadcastRecord r = app.curReceiver;
8738 if (r != null) {
8739 // The current broadcast is waiting for this app's receiver
8740 // to be finished. Looks like that's not going to happen, so
8741 // let the broadcast continue.
8742 logBroadcastReceiverDiscard(r);
8743 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8744 r.resultExtras, r.resultAbort, true);
8745 reschedule = true;
8746 }
8747 r = mPendingBroadcast;
8748 if (r != null && r.curApp == app) {
8749 if (DEBUG_BROADCAST) Log.v(TAG,
8750 "skip & discard pending app " + r);
8751 logBroadcastReceiverDiscard(r);
8752 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8753 r.resultExtras, r.resultAbort, true);
8754 reschedule = true;
8755 }
8756 if (reschedule) {
8757 scheduleBroadcastsLocked();
8758 }
8759 }
8760
Dan Egnor60d87622009-12-16 16:32:58 -08008761 /**
8762 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8763 * The application process will exit immediately after this call returns.
8764 * @param app object of the crashing app, null for the system server
8765 * @param crashInfo describing the exception
8766 */
8767 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8768 ProcessRecord r = findAppProcess(app);
8769
8770 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8771 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008772 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008773 crashInfo.exceptionClassName,
8774 crashInfo.exceptionMessage,
8775 crashInfo.throwFileName,
8776 crashInfo.throwLineNumber);
8777
Dan Egnor42471dd2010-01-07 17:25:22 -08008778 addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008779
8780 crashApplication(r, crashInfo);
8781 }
8782
8783 /**
8784 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8785 * @param app object of the crashing app, null for the system server
8786 * @param tag reported by the caller
8787 * @param crashInfo describing the context of the error
8788 * @return true if the process should exit immediately (WTF is fatal)
8789 */
8790 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008791 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008792 ProcessRecord r = findAppProcess(app);
8793
8794 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8795 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008796 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008797 tag, crashInfo.exceptionMessage);
8798
Dan Egnor42471dd2010-01-07 17:25:22 -08008799 addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008800
Doug Zongker43866e02010-01-07 12:09:54 -08008801 if (Settings.Secure.getInt(mContext.getContentResolver(),
8802 Settings.Secure.WTF_IS_FATAL, 0) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008803 crashApplication(r, crashInfo);
8804 return true;
8805 } else {
8806 return false;
8807 }
8808 }
8809
8810 /**
8811 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8812 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8813 */
8814 private ProcessRecord findAppProcess(IBinder app) {
8815 if (app == null) {
8816 return null;
8817 }
8818
8819 synchronized (this) {
8820 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8821 final int NA = apps.size();
8822 for (int ia=0; ia<NA; ia++) {
8823 ProcessRecord p = apps.valueAt(ia);
8824 if (p.thread != null && p.thread.asBinder() == app) {
8825 return p;
8826 }
8827 }
8828 }
8829
8830 Log.w(TAG, "Can't find mystery application: " + app);
8831 return null;
8832 }
8833 }
8834
8835 /**
Dan Egnor42471dd2010-01-07 17:25:22 -08008836 * Write a description of an error (crash, WTF, ANR) to the drop box.
Dan Egnor60d87622009-12-16 16:32:58 -08008837 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
Dan Egnor42471dd2010-01-07 17:25:22 -08008838 * @param process which caused the error, null means the system server
8839 * @param activity which triggered the error, null if unknown
8840 * @param parent activity related to the error, null if unknown
8841 * @param subject line related to the error, null if absent
8842 * @param report in long form describing the error, null if absent
8843 * @param logFile to include in the report, null if none
8844 * @param crashInfo giving an application stack trace, null if absent
Dan Egnor60d87622009-12-16 16:32:58 -08008845 */
Dan Egnor42471dd2010-01-07 17:25:22 -08008846 private void addErrorToDropBox(String eventType,
8847 ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
8848 String subject, String report, File logFile,
Dan Egnor60d87622009-12-16 16:32:58 -08008849 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008850 String dropboxTag;
8851 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008852 dropboxTag = "system_server_" + eventType;
Dan Egnor42471dd2010-01-07 17:25:22 -08008853 } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008854 dropboxTag = "system_app_" + eventType;
8855 } else {
8856 dropboxTag = "data_app_" + eventType;
8857 }
8858
8859 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8860 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8861 StringBuilder sb = new StringBuilder(1024);
Dan Egnor42471dd2010-01-07 17:25:22 -08008862 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008863 sb.append("Process: system_server\n");
8864 } else {
Dan Egnor42471dd2010-01-07 17:25:22 -08008865 sb.append("Process: ").append(process.processName).append("\n");
Dan Egnor66c40e72010-01-26 16:23:11 -08008866 }
8867 if (process != null) {
8868 int flags = process.info.flags;
8869 IPackageManager pm = ActivityThread.getPackageManager();
8870 sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
8871 for (String pkg : process.pkgList) {
8872 sb.append("Package: ").append(pkg);
8873 try {
8874 PackageInfo pi = pm.getPackageInfo(pkg, 0);
8875 if (pi != null) {
8876 sb.append(" v").append(pi.versionCode);
8877 if (pi.versionName != null) {
8878 sb.append(" (").append(pi.versionName).append(")");
8879 }
8880 }
8881 } catch (RemoteException e) {
8882 Log.e(TAG, "Error getting package info: " + pkg, e);
8883 }
8884 sb.append("\n");
8885 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008886 }
8887 if (activity != null) {
8888 sb.append("Activity: ").append(activity.shortComponentName).append("\n");
8889 }
8890 if (parent != null && parent.app != null && parent.app.pid != process.pid) {
8891 sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
8892 }
8893 if (parent != null && parent != activity) {
8894 sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
8895 }
8896 if (subject != null) {
8897 sb.append("Subject: ").append(subject).append("\n");
8898 }
8899 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8900 sb.append("\n");
8901 if (report != null) {
8902 sb.append(report);
8903 }
8904 if (logFile != null) {
8905 try {
8906 sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
8907 } catch (IOException e) {
8908 Log.e(TAG, "Error reading " + logFile, e);
Dan Egnor60d87622009-12-16 16:32:58 -08008909 }
8910 }
Dan Egnor60d87622009-12-16 16:32:58 -08008911 if (crashInfo != null && crashInfo.stackTrace != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008912 sb.append(crashInfo.stackTrace);
Dan Egnor60d87622009-12-16 16:32:58 -08008913 }
8914 dbox.addText(dropboxTag, sb.toString());
8915 }
8916 }
8917
8918 /**
8919 * Bring up the "unexpected error" dialog box for a crashing app.
8920 * Deal with edge cases (intercepts from instrumented applications,
8921 * ActivityController, error intent receivers, that sort of thing).
8922 * @param r the application crashing
8923 * @param crashInfo describing the failure
8924 */
8925 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008926 long timeMillis = System.currentTimeMillis();
8927 String shortMsg = crashInfo.exceptionClassName;
8928 String longMsg = crashInfo.exceptionMessage;
8929 String stackTrace = crashInfo.stackTrace;
8930 if (shortMsg != null && longMsg != null) {
8931 longMsg = shortMsg + ": " + longMsg;
8932 } else if (shortMsg != null) {
8933 longMsg = shortMsg;
8934 }
8935
Dan Egnor60d87622009-12-16 16:32:58 -08008936 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008937 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008938 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008939 try {
8940 String name = r != null ? r.processName : null;
8941 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008942 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008943 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008944 Log.w(TAG, "Force-killing crashed app " + name
8945 + " at watcher's request");
8946 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008947 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008948 }
8949 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008950 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008951 }
8952 }
8953
8954 final long origId = Binder.clearCallingIdentity();
8955
8956 // If this process is running instrumentation, finish it.
8957 if (r != null && r.instrumentationClass != null) {
8958 Log.w(TAG, "Error in app " + r.processName
8959 + " running instrumentation " + r.instrumentationClass + ":");
8960 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8961 if (longMsg != null) Log.w(TAG, " " + longMsg);
8962 Bundle info = new Bundle();
8963 info.putString("shortMsg", shortMsg);
8964 info.putString("longMsg", longMsg);
8965 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8966 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008967 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008968 }
8969
Dan Egnor60d87622009-12-16 16:32:58 -08008970 // If we can't identify the process or it's already exceeded its crash quota,
8971 // quit right away without showing a crash dialog.
8972 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008973 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008974 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008975 }
8976
8977 Message msg = Message.obtain();
8978 msg.what = SHOW_ERROR_MSG;
8979 HashMap data = new HashMap();
8980 data.put("result", result);
8981 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008982 msg.obj = data;
8983 mHandler.sendMessage(msg);
8984
8985 Binder.restoreCallingIdentity(origId);
8986 }
8987
8988 int res = result.get();
8989
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008990 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008991 synchronized (this) {
8992 if (r != null) {
8993 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8994 SystemClock.uptimeMillis());
8995 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008996 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008997 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008998 }
8999 }
9000
9001 if (appErrorIntent != null) {
9002 try {
9003 mContext.startActivity(appErrorIntent);
9004 } catch (ActivityNotFoundException e) {
9005 Log.w(TAG, "bug report receiver dissappeared", e);
9006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009008 }
Dan Egnorb7f03672009-12-09 16:22:32 -08009009
9010 Intent createAppErrorIntentLocked(ProcessRecord r,
9011 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
9012 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009013 if (report == null) {
9014 return null;
9015 }
9016 Intent result = new Intent(Intent.ACTION_APP_ERROR);
9017 result.setComponent(r.errorReportReceiver);
9018 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
9019 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
9020 return result;
9021 }
9022
Dan Egnorb7f03672009-12-09 16:22:32 -08009023 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
9024 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009025 if (r.errorReportReceiver == null) {
9026 return null;
9027 }
9028
9029 if (!r.crashing && !r.notResponding) {
9030 return null;
9031 }
9032
Dan Egnorb7f03672009-12-09 16:22:32 -08009033 ApplicationErrorReport report = new ApplicationErrorReport();
9034 report.packageName = r.info.packageName;
9035 report.installerPackageName = r.errorReportReceiver.getPackageName();
9036 report.processName = r.processName;
9037 report.time = timeMillis;
Jacek Surazskie0ee6ef2010-01-07 16:23:03 +01009038 report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009039
Dan Egnorb7f03672009-12-09 16:22:32 -08009040 if (r.crashing) {
9041 report.type = ApplicationErrorReport.TYPE_CRASH;
9042 report.crashInfo = crashInfo;
9043 } else if (r.notResponding) {
9044 report.type = ApplicationErrorReport.TYPE_ANR;
9045 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009046
Dan Egnorb7f03672009-12-09 16:22:32 -08009047 report.anrInfo.activity = r.notRespondingReport.tag;
9048 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9049 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009050 }
9051
Dan Egnorb7f03672009-12-09 16:22:32 -08009052 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009053 }
9054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009055 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9056 // assume our apps are happy - lazy create the list
9057 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9058
9059 synchronized (this) {
9060
9061 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009062 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9063 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009064 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9065 // This one's in trouble, so we'll generate a report for it
9066 // crashes are higher priority (in case there's a crash *and* an anr)
9067 ActivityManager.ProcessErrorStateInfo report = null;
9068 if (app.crashing) {
9069 report = app.crashingReport;
9070 } else if (app.notResponding) {
9071 report = app.notRespondingReport;
9072 }
9073
9074 if (report != null) {
9075 if (errList == null) {
9076 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9077 }
9078 errList.add(report);
9079 } else {
9080 Log.w(TAG, "Missing app error report, app = " + app.processName +
9081 " crashing = " + app.crashing +
9082 " notResponding = " + app.notResponding);
9083 }
9084 }
9085 }
9086 }
9087
9088 return errList;
9089 }
9090
9091 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9092 // Lazy instantiation of list
9093 List<ActivityManager.RunningAppProcessInfo> runList = null;
9094 synchronized (this) {
9095 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009096 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9097 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009098 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9099 // Generate process state info for running application
9100 ActivityManager.RunningAppProcessInfo currApp =
9101 new ActivityManager.RunningAppProcessInfo(app.processName,
9102 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009103 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009104 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009105 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009106 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9107 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9108 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009109 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9110 } else if (adj >= HOME_APP_ADJ) {
9111 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9112 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009113 } else if (adj >= SECONDARY_SERVER_ADJ) {
9114 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9115 } else if (adj >= VISIBLE_APP_ADJ) {
9116 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9117 } else {
9118 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9119 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009120 currApp.importanceReasonCode = app.adjTypeCode;
9121 if (app.adjSource instanceof ProcessRecord) {
9122 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9123 } else if (app.adjSource instanceof HistoryRecord) {
9124 HistoryRecord r = (HistoryRecord)app.adjSource;
9125 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9126 }
9127 if (app.adjTarget instanceof ComponentName) {
9128 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9129 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009130 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9131 // + " lru=" + currApp.lru);
9132 if (runList == null) {
9133 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9134 }
9135 runList.add(currApp);
9136 }
9137 }
9138 }
9139 return runList;
9140 }
9141
9142 @Override
9143 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009144 if (checkCallingPermission(android.Manifest.permission.DUMP)
9145 != PackageManager.PERMISSION_GRANTED) {
9146 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9147 + Binder.getCallingPid()
9148 + ", uid=" + Binder.getCallingUid()
9149 + " without permission "
9150 + android.Manifest.permission.DUMP);
9151 return;
9152 }
9153
9154 boolean dumpAll = false;
9155
9156 int opti = 0;
9157 while (opti < args.length) {
9158 String opt = args[opti];
9159 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9160 break;
9161 }
9162 opti++;
9163 if ("-a".equals(opt)) {
9164 dumpAll = true;
9165 } else if ("-h".equals(opt)) {
9166 pw.println("Activity manager dump options:");
9167 pw.println(" [-a] [h- [cmd] ...");
9168 pw.println(" cmd may be one of:");
9169 pw.println(" activities: activity stack state");
9170 pw.println(" broadcasts: broadcast state");
9171 pw.println(" intents: pending intent state");
9172 pw.println(" processes: process state");
9173 pw.println(" providers: content provider state");
9174 pw.println(" services: service state");
9175 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009176 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009177 } else {
9178 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009179 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009180 }
9181
9182 // Is the caller requesting to dump a particular piece of data?
9183 if (opti < args.length) {
9184 String cmd = args[opti];
9185 opti++;
9186 if ("activities".equals(cmd) || "a".equals(cmd)) {
9187 synchronized (this) {
9188 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009189 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009190 return;
9191 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9192 synchronized (this) {
9193 dumpBroadcastsLocked(fd, pw, args, opti, true);
9194 }
9195 return;
9196 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9197 synchronized (this) {
9198 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9199 }
9200 return;
9201 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9202 synchronized (this) {
9203 dumpProcessesLocked(fd, pw, args, opti, true);
9204 }
9205 return;
9206 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9207 synchronized (this) {
9208 dumpProvidersLocked(fd, pw, args, opti, true);
9209 }
9210 return;
9211 } else if ("service".equals(cmd)) {
9212 dumpService(fd, pw, args, opti, true);
9213 return;
9214 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9215 synchronized (this) {
9216 dumpServicesLocked(fd, pw, args, opti, true);
9217 }
9218 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009219 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009220 }
9221
9222 // No piece of data specified, dump everything.
9223 synchronized (this) {
9224 boolean needSep;
9225 if (dumpAll) {
9226 pw.println("Providers in Current Activity Manager State:");
9227 }
9228 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9229 if (needSep) {
9230 pw.println(" ");
9231 }
9232 if (dumpAll) {
9233 pw.println("-------------------------------------------------------------------------------");
9234 pw.println("Broadcasts in Current Activity Manager State:");
9235 }
9236 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9237 if (needSep) {
9238 pw.println(" ");
9239 }
9240 if (dumpAll) {
9241 pw.println("-------------------------------------------------------------------------------");
9242 pw.println("Services in Current Activity Manager State:");
9243 }
9244 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9245 if (needSep) {
9246 pw.println(" ");
9247 }
9248 if (dumpAll) {
9249 pw.println("-------------------------------------------------------------------------------");
9250 pw.println("PendingIntents in Current Activity Manager State:");
9251 }
9252 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9253 if (needSep) {
9254 pw.println(" ");
9255 }
9256 if (dumpAll) {
9257 pw.println("-------------------------------------------------------------------------------");
9258 pw.println("Activities in Current Activity Manager State:");
9259 }
9260 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9261 if (needSep) {
9262 pw.println(" ");
9263 }
9264 if (dumpAll) {
9265 pw.println("-------------------------------------------------------------------------------");
9266 pw.println("Processes in Current Activity Manager State:");
9267 }
9268 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9269 }
9270 }
9271
9272 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9273 int opti, boolean dumpAll, boolean needHeader) {
9274 if (needHeader) {
9275 pw.println(" Activity stack:");
9276 }
9277 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9278 pw.println(" ");
9279 pw.println(" Running activities (most recent first):");
9280 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9281 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009282 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009283 pw.println(" Activities waiting for another to become visible:");
9284 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9285 }
9286 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009287 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009288 pw.println(" Activities waiting to stop:");
9289 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9290 }
9291 if (mFinishingActivities.size() > 0) {
9292 pw.println(" ");
9293 pw.println(" Activities waiting to finish:");
9294 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9295 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009296
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009297 pw.println(" ");
9298 pw.println(" mPausingActivity: " + mPausingActivity);
9299 pw.println(" mResumedActivity: " + mResumedActivity);
9300 pw.println(" mFocusedActivity: " + mFocusedActivity);
9301 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009302
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009303 if (dumpAll && mRecentTasks.size() > 0) {
9304 pw.println(" ");
9305 pw.println("Recent tasks in Current Activity Manager State:");
9306
9307 final int N = mRecentTasks.size();
9308 for (int i=0; i<N; i++) {
9309 TaskRecord tr = mRecentTasks.get(i);
9310 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9311 pw.println(tr);
9312 mRecentTasks.get(i).dump(pw, " ");
9313 }
9314 }
9315
9316 pw.println(" ");
9317 pw.println(" mCurTask: " + mCurTask);
9318
9319 return true;
9320 }
9321
9322 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9323 int opti, boolean dumpAll) {
9324 boolean needSep = false;
9325 int numPers = 0;
9326
9327 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009328 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9329 final int NA = procs.size();
9330 for (int ia=0; ia<NA; ia++) {
9331 if (!needSep) {
9332 pw.println(" All known processes:");
9333 needSep = true;
9334 }
9335 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009336 pw.print(r.persistent ? " *PERS*" : " *APP*");
9337 pw.print(" UID "); pw.print(procs.keyAt(ia));
9338 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009339 r.dump(pw, " ");
9340 if (r.persistent) {
9341 numPers++;
9342 }
9343 }
9344 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009345 }
9346
9347 if (mLruProcesses.size() > 0) {
9348 if (needSep) pw.println(" ");
9349 needSep = true;
9350 pw.println(" Running processes (most recent first):");
9351 dumpProcessList(pw, this, mLruProcesses, " ",
9352 "App ", "PERS", true);
9353 needSep = true;
9354 }
9355
9356 synchronized (mPidsSelfLocked) {
9357 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009358 if (needSep) pw.println(" ");
9359 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009360 pw.println(" PID mappings:");
9361 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9362 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9363 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009364 }
9365 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009366 }
9367
9368 if (mForegroundProcesses.size() > 0) {
9369 if (needSep) pw.println(" ");
9370 needSep = true;
9371 pw.println(" Foreground Processes:");
9372 for (int i=0; i<mForegroundProcesses.size(); i++) {
9373 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9374 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009375 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009376 }
9377
9378 if (mPersistentStartingProcesses.size() > 0) {
9379 if (needSep) pw.println(" ");
9380 needSep = true;
9381 pw.println(" Persisent processes that are starting:");
9382 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9383 "Starting Norm", "Restarting PERS", false);
9384 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009385
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009386 if (mStartingProcesses.size() > 0) {
9387 if (needSep) pw.println(" ");
9388 needSep = true;
9389 pw.println(" Processes that are starting:");
9390 dumpProcessList(pw, this, mStartingProcesses, " ",
9391 "Starting Norm", "Starting PERS", false);
9392 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009393
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009394 if (mRemovedProcesses.size() > 0) {
9395 if (needSep) pw.println(" ");
9396 needSep = true;
9397 pw.println(" Processes that are being removed:");
9398 dumpProcessList(pw, this, mRemovedProcesses, " ",
9399 "Removed Norm", "Removed PERS", false);
9400 }
9401
9402 if (mProcessesOnHold.size() > 0) {
9403 if (needSep) pw.println(" ");
9404 needSep = true;
9405 pw.println(" Processes that are on old until the system is ready:");
9406 dumpProcessList(pw, this, mProcessesOnHold, " ",
9407 "OnHold Norm", "OnHold PERS", false);
9408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009409
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009410 if (mProcessesToGc.size() > 0) {
9411 if (needSep) pw.println(" ");
9412 needSep = true;
9413 pw.println(" Processes that are waiting to GC:");
9414 long now = SystemClock.uptimeMillis();
9415 for (int i=0; i<mProcessesToGc.size(); i++) {
9416 ProcessRecord proc = mProcessesToGc.get(i);
9417 pw.print(" Process "); pw.println(proc);
9418 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9419 pw.print(", last gced=");
9420 pw.print(now-proc.lastRequestedGc);
9421 pw.print(" ms ago, last lowMem=");
9422 pw.print(now-proc.lastLowMemory);
9423 pw.println(" ms ago");
9424
9425 }
9426 }
9427
9428 if (mProcessCrashTimes.getMap().size() > 0) {
9429 if (needSep) pw.println(" ");
9430 needSep = true;
9431 pw.println(" Time since processes crashed:");
9432 long now = SystemClock.uptimeMillis();
9433 for (Map.Entry<String, SparseArray<Long>> procs
9434 : mProcessCrashTimes.getMap().entrySet()) {
9435 SparseArray<Long> uids = procs.getValue();
9436 final int N = uids.size();
9437 for (int i=0; i<N; i++) {
9438 pw.print(" Process "); pw.print(procs.getKey());
9439 pw.print(" uid "); pw.print(uids.keyAt(i));
9440 pw.print(": last crashed ");
9441 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009442 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009443 }
9444 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009445 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009446
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009447 if (mBadProcesses.getMap().size() > 0) {
9448 if (needSep) pw.println(" ");
9449 needSep = true;
9450 pw.println(" Bad processes:");
9451 for (Map.Entry<String, SparseArray<Long>> procs
9452 : mBadProcesses.getMap().entrySet()) {
9453 SparseArray<Long> uids = procs.getValue();
9454 final int N = uids.size();
9455 for (int i=0; i<N; i++) {
9456 pw.print(" Bad process "); pw.print(procs.getKey());
9457 pw.print(" uid "); pw.print(uids.keyAt(i));
9458 pw.print(": crashed at time ");
9459 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009460 }
9461 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009462 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009463
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009464 pw.println(" ");
9465 pw.println(" mHomeProcess: " + mHomeProcess);
9466 pw.println(" mConfiguration: " + mConfiguration);
9467 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9468 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9469 || mOrigWaitForDebugger) {
9470 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9471 + " mDebugTransient=" + mDebugTransient
9472 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9473 }
9474 if (mAlwaysFinishActivities || mController != null) {
9475 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9476 + " mController=" + mController);
9477 }
9478 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009479 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009480 pw.println(" mStartRunning=" + mStartRunning
9481 + " mSystemReady=" + mSystemReady
9482 + " mBooting=" + mBooting
9483 + " mBooted=" + mBooted
9484 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009485 pw.println(" mGoingToSleep=" + mGoingToSleep);
9486 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009487 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009488
9489 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009490 }
9491
9492 /**
9493 * There are three ways to call this:
9494 * - no service specified: dump all the services
9495 * - a flattened component name that matched an existing service was specified as the
9496 * first arg: dump that one service
9497 * - the first arg isn't the flattened component name of an existing service:
9498 * dump all services whose component contains the first arg as a substring
9499 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009500 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9501 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009502 String[] newArgs;
9503 String componentNameString;
9504 ServiceRecord r;
Kenny Root3619b9ab2010-02-13 10:05:42 -08009505 if (opti >= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009506 componentNameString = null;
9507 newArgs = EMPTY_STRING_ARRAY;
9508 r = null;
9509 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009510 componentNameString = args[opti];
9511 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009512 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9513 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009514 newArgs = new String[args.length - opti];
9515 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009516 }
9517
9518 if (r != null) {
9519 dumpService(fd, pw, r, newArgs);
9520 } else {
9521 for (ServiceRecord r1 : mServices.values()) {
9522 if (componentNameString == null
9523 || r1.name.flattenToString().contains(componentNameString)) {
9524 dumpService(fd, pw, r1, newArgs);
9525 }
9526 }
9527 }
9528 }
9529
9530 /**
9531 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9532 * there is a thread associated with the service.
9533 */
9534 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9535 pw.println(" Service " + r.name.flattenToString());
9536 if (r.app != null && r.app.thread != null) {
9537 try {
9538 // flush anything that is already in the PrintWriter since the thread is going
9539 // to write to the file descriptor directly
9540 pw.flush();
9541 r.app.thread.dumpService(fd, r, args);
9542 pw.print("\n");
9543 } catch (RemoteException e) {
9544 pw.println("got a RemoteException while dumping the service");
9545 }
9546 }
9547 }
9548
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009549 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9550 int opti, boolean dumpAll) {
9551 boolean needSep = false;
9552
9553 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009554 if (mRegisteredReceivers.size() > 0) {
9555 pw.println(" ");
9556 pw.println(" Registered Receivers:");
9557 Iterator it = mRegisteredReceivers.values().iterator();
9558 while (it.hasNext()) {
9559 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009560 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009561 r.dump(pw, " ");
9562 }
9563 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009565 pw.println(" ");
9566 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009567 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009568 needSep = true;
9569 }
9570
9571 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9572 || mPendingBroadcast != null) {
9573 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009574 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009575 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009576 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009577 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9578 pw.println(" Broadcast #" + i + ":");
9579 mParallelBroadcasts.get(i).dump(pw, " ");
9580 }
9581 if (mOrderedBroadcasts.size() > 0) {
9582 pw.println(" ");
9583 pw.println(" Active serialized broadcasts:");
9584 }
9585 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9586 pw.println(" Serialized Broadcast #" + i + ":");
9587 mOrderedBroadcasts.get(i).dump(pw, " ");
9588 }
9589 pw.println(" ");
9590 pw.println(" Pending broadcast:");
9591 if (mPendingBroadcast != null) {
9592 mPendingBroadcast.dump(pw, " ");
9593 } else {
9594 pw.println(" (null)");
9595 }
9596 needSep = true;
9597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009598
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009599 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009600 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009601 pw.println(" Historical broadcasts:");
9602 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9603 BroadcastRecord r = mBroadcastHistory[i];
9604 if (r == null) {
9605 break;
9606 }
9607 pw.println(" Historical Broadcast #" + i + ":");
9608 r.dump(pw, " ");
9609 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009610 needSep = true;
9611 }
9612
9613 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009614 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009615 pw.println(" Sticky broadcasts:");
9616 StringBuilder sb = new StringBuilder(128);
9617 for (Map.Entry<String, ArrayList<Intent>> ent
9618 : mStickyBroadcasts.entrySet()) {
9619 pw.print(" * Sticky action "); pw.print(ent.getKey());
9620 pw.println(":");
9621 ArrayList<Intent> intents = ent.getValue();
9622 final int N = intents.size();
9623 for (int i=0; i<N; i++) {
9624 sb.setLength(0);
9625 sb.append(" Intent: ");
9626 intents.get(i).toShortString(sb, true, false);
9627 pw.println(sb.toString());
9628 Bundle bundle = intents.get(i).getExtras();
9629 if (bundle != null) {
9630 pw.print(" ");
9631 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009632 }
9633 }
9634 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009635 needSep = true;
9636 }
9637
9638 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009639 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009640 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009641 pw.println(" mHandler:");
9642 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009643 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009644 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009645
9646 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009647 }
9648
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009649 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9650 int opti, boolean dumpAll) {
9651 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009652
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009653 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009654 if (mServices.size() > 0) {
9655 pw.println(" Active services:");
9656 Iterator<ServiceRecord> it = mServices.values().iterator();
9657 while (it.hasNext()) {
9658 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009659 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009660 r.dump(pw, " ");
9661 }
9662 needSep = true;
9663 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009665
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009666 if (mPendingServices.size() > 0) {
9667 if (needSep) pw.println(" ");
9668 pw.println(" Pending services:");
9669 for (int i=0; i<mPendingServices.size(); i++) {
9670 ServiceRecord r = mPendingServices.get(i);
9671 pw.print(" * Pending "); pw.println(r);
9672 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009673 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009674 needSep = true;
9675 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009676
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009677 if (mRestartingServices.size() > 0) {
9678 if (needSep) pw.println(" ");
9679 pw.println(" Restarting services:");
9680 for (int i=0; i<mRestartingServices.size(); i++) {
9681 ServiceRecord r = mRestartingServices.get(i);
9682 pw.print(" * Restarting "); pw.println(r);
9683 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009684 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009685 needSep = true;
9686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009687
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009688 if (mStoppingServices.size() > 0) {
9689 if (needSep) pw.println(" ");
9690 pw.println(" Stopping services:");
9691 for (int i=0; i<mStoppingServices.size(); i++) {
9692 ServiceRecord r = mStoppingServices.get(i);
9693 pw.print(" * Stopping "); pw.println(r);
9694 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009695 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009696 needSep = true;
9697 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009698
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009699 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009700 if (mServiceConnections.size() > 0) {
9701 if (needSep) pw.println(" ");
9702 pw.println(" Connection bindings to services:");
9703 Iterator<ConnectionRecord> it
9704 = mServiceConnections.values().iterator();
9705 while (it.hasNext()) {
9706 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009707 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009708 r.dump(pw, " ");
9709 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009710 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009711 }
9712 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009713
9714 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009715 }
9716
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009717 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9718 int opti, boolean dumpAll) {
9719 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009720
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009721 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009722 if (mProvidersByClass.size() > 0) {
9723 if (needSep) pw.println(" ");
9724 pw.println(" Published content providers (by class):");
9725 Iterator it = mProvidersByClass.entrySet().iterator();
9726 while (it.hasNext()) {
9727 Map.Entry e = (Map.Entry)it.next();
9728 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009729 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009730 r.dump(pw, " ");
9731 }
9732 needSep = true;
9733 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009734
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009735 if (mProvidersByName.size() > 0) {
9736 pw.println(" ");
9737 pw.println(" Authority to provider mappings:");
9738 Iterator it = mProvidersByName.entrySet().iterator();
9739 while (it.hasNext()) {
9740 Map.Entry e = (Map.Entry)it.next();
9741 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9742 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9743 pw.println(r);
9744 }
9745 needSep = true;
9746 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009747 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009748
9749 if (mLaunchingProviders.size() > 0) {
9750 if (needSep) pw.println(" ");
9751 pw.println(" Launching content providers:");
9752 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9753 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9754 pw.println(mLaunchingProviders.get(i));
9755 }
9756 needSep = true;
9757 }
9758
9759 if (mGrantedUriPermissions.size() > 0) {
9760 pw.println();
9761 pw.println("Granted Uri Permissions:");
9762 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9763 int uid = mGrantedUriPermissions.keyAt(i);
9764 HashMap<Uri, UriPermission> perms
9765 = mGrantedUriPermissions.valueAt(i);
9766 pw.print(" * UID "); pw.print(uid);
9767 pw.println(" holds:");
9768 for (UriPermission perm : perms.values()) {
9769 pw.print(" "); pw.println(perm);
9770 perm.dump(pw, " ");
9771 }
9772 }
9773 needSep = true;
9774 }
9775
9776 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009777 }
9778
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009779 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9780 int opti, boolean dumpAll) {
9781 boolean needSep = false;
9782
9783 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009784 if (this.mIntentSenderRecords.size() > 0) {
9785 Iterator<WeakReference<PendingIntentRecord>> it
9786 = mIntentSenderRecords.values().iterator();
9787 while (it.hasNext()) {
9788 WeakReference<PendingIntentRecord> ref = it.next();
9789 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009790 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009791 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009792 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009793 rec.dump(pw, " ");
9794 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009795 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009796 }
9797 }
9798 }
9799 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009800
9801 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009802 }
9803
9804 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009805 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009806 TaskRecord lastTask = null;
9807 for (int i=list.size()-1; i>=0; i--) {
9808 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009809 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009810 if (lastTask != r.task) {
9811 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009812 pw.print(prefix);
9813 pw.print(full ? "* " : " ");
9814 pw.println(lastTask);
9815 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009816 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009817 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009818 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009819 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9820 pw.print(" #"); pw.print(i); pw.print(": ");
9821 pw.println(r);
9822 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009823 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009824 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009825 }
9826 }
9827
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009828 private static String buildOomTag(String prefix, String space, int val, int base) {
9829 if (val == base) {
9830 if (space == null) return prefix;
9831 return prefix + " ";
9832 }
9833 return prefix + "+" + Integer.toString(val-base);
9834 }
9835
9836 private static final int dumpProcessList(PrintWriter pw,
9837 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009838 String prefix, String normalLabel, String persistentLabel,
9839 boolean inclOomAdj) {
9840 int numPers = 0;
9841 for (int i=list.size()-1; i>=0; i--) {
9842 ProcessRecord r = (ProcessRecord)list.get(i);
9843 if (false) {
9844 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9845 + " #" + i + ":");
9846 r.dump(pw, prefix + " ");
9847 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009848 String oomAdj;
9849 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009850 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009851 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009852 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9853 } else if (r.setAdj >= HOME_APP_ADJ) {
9854 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9855 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9856 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9857 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9858 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9859 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9860 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9861 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9862 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009863 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009864 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009865 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009866 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009867 } else {
9868 oomAdj = Integer.toString(r.setAdj);
9869 }
9870 String schedGroup;
9871 switch (r.setSchedGroup) {
9872 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9873 schedGroup = "B";
9874 break;
9875 case Process.THREAD_GROUP_DEFAULT:
9876 schedGroup = "F";
9877 break;
9878 default:
9879 schedGroup = Integer.toString(r.setSchedGroup);
9880 break;
9881 }
9882 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009883 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009884 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009885 if (r.adjSource != null || r.adjTarget != null) {
9886 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009887 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009888 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009889 } else {
9890 pw.println(String.format("%s%s #%2d: %s",
9891 prefix, (r.persistent ? persistentLabel : normalLabel),
9892 i, r.toString()));
9893 }
9894 if (r.persistent) {
9895 numPers++;
9896 }
9897 }
9898 return numPers;
9899 }
9900
9901 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9902 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009903 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009904 long uptime = SystemClock.uptimeMillis();
9905 long realtime = SystemClock.elapsedRealtime();
9906
9907 if (isCheckinRequest) {
9908 // short checkin version
9909 pw.println(uptime + "," + realtime);
9910 pw.flush();
9911 } else {
9912 pw.println("Applications Memory Usage (kB):");
9913 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9914 }
9915 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9916 ProcessRecord r = (ProcessRecord)list.get(i);
9917 if (r.thread != null) {
9918 if (!isCheckinRequest) {
9919 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9920 pw.flush();
9921 }
9922 try {
9923 r.thread.asBinder().dump(fd, args);
9924 } catch (RemoteException e) {
9925 if (!isCheckinRequest) {
9926 pw.println("Got RemoteException!");
9927 pw.flush();
9928 }
9929 }
9930 }
9931 }
9932 }
9933
9934 /**
9935 * Searches array of arguments for the specified string
9936 * @param args array of argument strings
9937 * @param value value to search for
9938 * @return true if the value is contained in the array
9939 */
9940 private static boolean scanArgs(String[] args, String value) {
9941 if (args != null) {
9942 for (String arg : args) {
9943 if (value.equals(arg)) {
9944 return true;
9945 }
9946 }
9947 }
9948 return false;
9949 }
9950
Dianne Hackborn75b03852009-06-12 15:43:26 -07009951 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009952 int count = mHistory.size();
9953
9954 // convert the token to an entry in the history.
9955 HistoryRecord r = null;
9956 int index = -1;
9957 for (int i=count-1; i>=0; i--) {
9958 Object o = mHistory.get(i);
9959 if (o == token) {
9960 r = (HistoryRecord)o;
9961 index = i;
9962 break;
9963 }
9964 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009965
9966 return index;
9967 }
9968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009969 private final void killServicesLocked(ProcessRecord app,
9970 boolean allowRestart) {
9971 // Report disconnected services.
9972 if (false) {
9973 // XXX we are letting the client link to the service for
9974 // death notifications.
9975 if (app.services.size() > 0) {
9976 Iterator it = app.services.iterator();
9977 while (it.hasNext()) {
9978 ServiceRecord r = (ServiceRecord)it.next();
9979 if (r.connections.size() > 0) {
9980 Iterator<ConnectionRecord> jt
9981 = r.connections.values().iterator();
9982 while (jt.hasNext()) {
9983 ConnectionRecord c = jt.next();
9984 if (c.binding.client != app) {
9985 try {
9986 //c.conn.connected(r.className, null);
9987 } catch (Exception e) {
9988 // todo: this should be asynchronous!
9989 Log.w(TAG, "Exception thrown disconnected servce "
9990 + r.shortName
9991 + " from app " + app.processName, e);
9992 }
9993 }
9994 }
9995 }
9996 }
9997 }
9998 }
9999
10000 // Clean up any connections this application has to other services.
10001 if (app.connections.size() > 0) {
10002 Iterator<ConnectionRecord> it = app.connections.iterator();
10003 while (it.hasNext()) {
10004 ConnectionRecord r = it.next();
10005 removeConnectionLocked(r, app, null);
10006 }
10007 }
10008 app.connections.clear();
10009
10010 if (app.services.size() != 0) {
10011 // Any services running in the application need to be placed
10012 // back in the pending list.
10013 Iterator it = app.services.iterator();
10014 while (it.hasNext()) {
10015 ServiceRecord sr = (ServiceRecord)it.next();
10016 synchronized (sr.stats.getBatteryStats()) {
10017 sr.stats.stopLaunchedLocked();
10018 }
10019 sr.app = null;
10020 sr.executeNesting = 0;
10021 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010022
10023 boolean hasClients = sr.bindings.size() > 0;
10024 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010025 Iterator<IntentBindRecord> bindings
10026 = sr.bindings.values().iterator();
10027 while (bindings.hasNext()) {
10028 IntentBindRecord b = bindings.next();
10029 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
10030 + ": shouldUnbind=" + b.hasBound);
10031 b.binder = null;
10032 b.requested = b.received = b.hasBound = false;
10033 }
10034 }
10035
10036 if (sr.crashCount >= 2) {
10037 Log.w(TAG, "Service crashed " + sr.crashCount
10038 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010039 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010040 sr.crashCount, sr.shortName, app.pid);
10041 bringDownServiceLocked(sr, true);
10042 } else if (!allowRestart) {
10043 bringDownServiceLocked(sr, true);
10044 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010045 boolean canceled = scheduleServiceRestartLocked(sr, true);
10046
10047 // Should the service remain running? Note that in the
10048 // extreme case of so many attempts to deliver a command
10049 // that it failed, that we also will stop it here.
10050 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10051 if (sr.pendingStarts.size() == 0) {
10052 sr.startRequested = false;
10053 if (!hasClients) {
10054 // Whoops, no reason to restart!
10055 bringDownServiceLocked(sr, true);
10056 }
10057 }
10058 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010059 }
10060 }
10061
10062 if (!allowRestart) {
10063 app.services.clear();
10064 }
10065 }
10066
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010067 // Make sure we have no more records on the stopping list.
10068 int i = mStoppingServices.size();
10069 while (i > 0) {
10070 i--;
10071 ServiceRecord sr = mStoppingServices.get(i);
10072 if (sr.app == app) {
10073 mStoppingServices.remove(i);
10074 }
10075 }
10076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010077 app.executingServices.clear();
10078 }
10079
10080 private final void removeDyingProviderLocked(ProcessRecord proc,
10081 ContentProviderRecord cpr) {
10082 synchronized (cpr) {
10083 cpr.launchingApp = null;
10084 cpr.notifyAll();
10085 }
10086
10087 mProvidersByClass.remove(cpr.info.name);
10088 String names[] = cpr.info.authority.split(";");
10089 for (int j = 0; j < names.length; j++) {
10090 mProvidersByName.remove(names[j]);
10091 }
10092
10093 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10094 while (cit.hasNext()) {
10095 ProcessRecord capp = cit.next();
10096 if (!capp.persistent && capp.thread != null
10097 && capp.pid != 0
10098 && capp.pid != MY_PID) {
10099 Log.i(TAG, "Killing app " + capp.processName
10100 + " (pid " + capp.pid
10101 + ") because provider " + cpr.info.name
10102 + " is in dying process " + proc.processName);
10103 Process.killProcess(capp.pid);
10104 }
10105 }
10106
10107 mLaunchingProviders.remove(cpr);
10108 }
10109
10110 /**
10111 * Main code for cleaning up a process when it has gone away. This is
10112 * called both as a result of the process dying, or directly when stopping
10113 * a process when running in single process mode.
10114 */
10115 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10116 boolean restarting, int index) {
10117 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010118 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010119 }
10120
Dianne Hackborn36124872009-10-08 16:22:03 -070010121 mProcessesToGc.remove(app);
10122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010123 // Dismiss any open dialogs.
10124 if (app.crashDialog != null) {
10125 app.crashDialog.dismiss();
10126 app.crashDialog = null;
10127 }
10128 if (app.anrDialog != null) {
10129 app.anrDialog.dismiss();
10130 app.anrDialog = null;
10131 }
10132 if (app.waitDialog != null) {
10133 app.waitDialog.dismiss();
10134 app.waitDialog = null;
10135 }
10136
10137 app.crashing = false;
10138 app.notResponding = false;
10139
10140 app.resetPackageList();
10141 app.thread = null;
10142 app.forcingToForeground = null;
10143 app.foregroundServices = false;
10144
10145 killServicesLocked(app, true);
10146
10147 boolean restart = false;
10148
10149 int NL = mLaunchingProviders.size();
10150
10151 // Remove published content providers.
10152 if (!app.pubProviders.isEmpty()) {
10153 Iterator it = app.pubProviders.values().iterator();
10154 while (it.hasNext()) {
10155 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10156 cpr.provider = null;
10157 cpr.app = null;
10158
10159 // See if someone is waiting for this provider... in which
10160 // case we don't remove it, but just let it restart.
10161 int i = 0;
10162 if (!app.bad) {
10163 for (; i<NL; i++) {
10164 if (mLaunchingProviders.get(i) == cpr) {
10165 restart = true;
10166 break;
10167 }
10168 }
10169 } else {
10170 i = NL;
10171 }
10172
10173 if (i >= NL) {
10174 removeDyingProviderLocked(app, cpr);
10175 NL = mLaunchingProviders.size();
10176 }
10177 }
10178 app.pubProviders.clear();
10179 }
10180
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010181 // Take care of any launching providers waiting for this process.
10182 if (checkAppInLaunchingProvidersLocked(app, false)) {
10183 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010184 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010186 // Unregister from connected content providers.
10187 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010188 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010189 while (it.hasNext()) {
10190 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10191 cpr.clients.remove(app);
10192 }
10193 app.conProviders.clear();
10194 }
10195
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010196 // At this point there may be remaining entries in mLaunchingProviders
10197 // where we were the only one waiting, so they are no longer of use.
10198 // Look for these and clean up if found.
10199 // XXX Commented out for now. Trying to figure out a way to reproduce
10200 // the actual situation to identify what is actually going on.
10201 if (false) {
10202 for (int i=0; i<NL; i++) {
10203 ContentProviderRecord cpr = (ContentProviderRecord)
10204 mLaunchingProviders.get(i);
10205 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10206 synchronized (cpr) {
10207 cpr.launchingApp = null;
10208 cpr.notifyAll();
10209 }
10210 }
10211 }
10212 }
10213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010214 skipCurrentReceiverLocked(app);
10215
10216 // Unregister any receivers.
10217 if (app.receivers.size() > 0) {
10218 Iterator<ReceiverList> it = app.receivers.iterator();
10219 while (it.hasNext()) {
10220 removeReceiverLocked(it.next());
10221 }
10222 app.receivers.clear();
10223 }
10224
Christopher Tate181fafa2009-05-14 11:12:14 -070010225 // If the app is undergoing backup, tell the backup manager about it
10226 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10227 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10228 try {
10229 IBackupManager bm = IBackupManager.Stub.asInterface(
10230 ServiceManager.getService(Context.BACKUP_SERVICE));
10231 bm.agentDisconnected(app.info.packageName);
10232 } catch (RemoteException e) {
10233 // can't happen; backup manager is local
10234 }
10235 }
10236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010237 // If the caller is restarting this app, then leave it in its
10238 // current lists and let the caller take care of it.
10239 if (restarting) {
10240 return;
10241 }
10242
10243 if (!app.persistent) {
10244 if (DEBUG_PROCESSES) Log.v(TAG,
10245 "Removing non-persistent process during cleanup: " + app);
10246 mProcessNames.remove(app.processName, app.info.uid);
10247 } else if (!app.removed) {
10248 // This app is persistent, so we need to keep its record around.
10249 // If it is not already on the pending app list, add it there
10250 // and start a new process for it.
10251 app.thread = null;
10252 app.forcingToForeground = null;
10253 app.foregroundServices = false;
10254 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10255 mPersistentStartingProcesses.add(app);
10256 restart = true;
10257 }
10258 }
10259 mProcessesOnHold.remove(app);
10260
The Android Open Source Project4df24232009-03-05 14:34:35 -080010261 if (app == mHomeProcess) {
10262 mHomeProcess = null;
10263 }
10264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010265 if (restart) {
10266 // We have components that still need to be running in the
10267 // process, so re-launch it.
10268 mProcessNames.put(app.processName, app.info.uid, app);
10269 startProcessLocked(app, "restart", app.processName);
10270 } else if (app.pid > 0 && app.pid != MY_PID) {
10271 // Goodbye!
10272 synchronized (mPidsSelfLocked) {
10273 mPidsSelfLocked.remove(app.pid);
10274 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10275 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010276 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010277 }
10278 }
10279
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010280 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10281 // Look through the content providers we are waiting to have launched,
10282 // and if any run in this process then either schedule a restart of
10283 // the process or kill the client waiting for it if this process has
10284 // gone bad.
10285 int NL = mLaunchingProviders.size();
10286 boolean restart = false;
10287 for (int i=0; i<NL; i++) {
10288 ContentProviderRecord cpr = (ContentProviderRecord)
10289 mLaunchingProviders.get(i);
10290 if (cpr.launchingApp == app) {
10291 if (!alwaysBad && !app.bad) {
10292 restart = true;
10293 } else {
10294 removeDyingProviderLocked(app, cpr);
10295 NL = mLaunchingProviders.size();
10296 }
10297 }
10298 }
10299 return restart;
10300 }
10301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010302 // =========================================================
10303 // SERVICES
10304 // =========================================================
10305
10306 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10307 ActivityManager.RunningServiceInfo info =
10308 new ActivityManager.RunningServiceInfo();
10309 info.service = r.name;
10310 if (r.app != null) {
10311 info.pid = r.app.pid;
10312 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010313 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010314 info.process = r.processName;
10315 info.foreground = r.isForeground;
10316 info.activeSince = r.createTime;
10317 info.started = r.startRequested;
10318 info.clientCount = r.connections.size();
10319 info.crashCount = r.crashCount;
10320 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010321 if (r.isForeground) {
10322 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10323 }
10324 if (r.startRequested) {
10325 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10326 }
Dan Egnor42471dd2010-01-07 17:25:22 -080010327 if (r.app != null && r.app.pid == MY_PID) {
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010328 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10329 }
10330 if (r.app != null && r.app.persistent) {
10331 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10332 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010333 for (ConnectionRecord conn : r.connections.values()) {
10334 if (conn.clientLabel != 0) {
10335 info.clientPackage = conn.binding.client.info.packageName;
10336 info.clientLabel = conn.clientLabel;
10337 break;
10338 }
10339 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010340 return info;
10341 }
10342
10343 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10344 int flags) {
10345 synchronized (this) {
10346 ArrayList<ActivityManager.RunningServiceInfo> res
10347 = new ArrayList<ActivityManager.RunningServiceInfo>();
10348
10349 if (mServices.size() > 0) {
10350 Iterator<ServiceRecord> it = mServices.values().iterator();
10351 while (it.hasNext() && res.size() < maxNum) {
10352 res.add(makeRunningServiceInfoLocked(it.next()));
10353 }
10354 }
10355
10356 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10357 ServiceRecord r = mRestartingServices.get(i);
10358 ActivityManager.RunningServiceInfo info =
10359 makeRunningServiceInfoLocked(r);
10360 info.restarting = r.nextRestartTime;
10361 res.add(info);
10362 }
10363
10364 return res;
10365 }
10366 }
10367
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010368 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10369 synchronized (this) {
10370 ServiceRecord r = mServices.get(name);
10371 if (r != null) {
10372 for (ConnectionRecord conn : r.connections.values()) {
10373 if (conn.clientIntent != null) {
10374 return conn.clientIntent;
10375 }
10376 }
10377 }
10378 }
10379 return null;
10380 }
10381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010382 private final ServiceRecord findServiceLocked(ComponentName name,
10383 IBinder token) {
10384 ServiceRecord r = mServices.get(name);
10385 return r == token ? r : null;
10386 }
10387
10388 private final class ServiceLookupResult {
10389 final ServiceRecord record;
10390 final String permission;
10391
10392 ServiceLookupResult(ServiceRecord _record, String _permission) {
10393 record = _record;
10394 permission = _permission;
10395 }
10396 };
10397
10398 private ServiceLookupResult findServiceLocked(Intent service,
10399 String resolvedType) {
10400 ServiceRecord r = null;
10401 if (service.getComponent() != null) {
10402 r = mServices.get(service.getComponent());
10403 }
10404 if (r == null) {
10405 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10406 r = mServicesByIntent.get(filter);
10407 }
10408
10409 if (r == null) {
10410 try {
10411 ResolveInfo rInfo =
10412 ActivityThread.getPackageManager().resolveService(
10413 service, resolvedType, 0);
10414 ServiceInfo sInfo =
10415 rInfo != null ? rInfo.serviceInfo : null;
10416 if (sInfo == null) {
10417 return null;
10418 }
10419
10420 ComponentName name = new ComponentName(
10421 sInfo.applicationInfo.packageName, sInfo.name);
10422 r = mServices.get(name);
10423 } catch (RemoteException ex) {
10424 // pm is in same process, this will never happen.
10425 }
10426 }
10427 if (r != null) {
10428 int callingPid = Binder.getCallingPid();
10429 int callingUid = Binder.getCallingUid();
10430 if (checkComponentPermission(r.permission,
10431 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10432 != PackageManager.PERMISSION_GRANTED) {
10433 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10434 + " from pid=" + callingPid
10435 + ", uid=" + callingUid
10436 + " requires " + r.permission);
10437 return new ServiceLookupResult(null, r.permission);
10438 }
10439 return new ServiceLookupResult(r, null);
10440 }
10441 return null;
10442 }
10443
10444 private class ServiceRestarter implements Runnable {
10445 private ServiceRecord mService;
10446
10447 void setService(ServiceRecord service) {
10448 mService = service;
10449 }
10450
10451 public void run() {
10452 synchronized(ActivityManagerService.this) {
10453 performServiceRestartLocked(mService);
10454 }
10455 }
10456 }
10457
10458 private ServiceLookupResult retrieveServiceLocked(Intent service,
10459 String resolvedType, int callingPid, int callingUid) {
10460 ServiceRecord r = null;
10461 if (service.getComponent() != null) {
10462 r = mServices.get(service.getComponent());
10463 }
10464 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10465 r = mServicesByIntent.get(filter);
10466 if (r == null) {
10467 try {
10468 ResolveInfo rInfo =
10469 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010470 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010471 ServiceInfo sInfo =
10472 rInfo != null ? rInfo.serviceInfo : null;
10473 if (sInfo == null) {
10474 Log.w(TAG, "Unable to start service " + service +
10475 ": not found");
10476 return null;
10477 }
10478
10479 ComponentName name = new ComponentName(
10480 sInfo.applicationInfo.packageName, sInfo.name);
10481 r = mServices.get(name);
10482 if (r == null) {
10483 filter = new Intent.FilterComparison(service.cloneFilter());
10484 ServiceRestarter res = new ServiceRestarter();
10485 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10486 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10487 synchronized (stats) {
10488 ss = stats.getServiceStatsLocked(
10489 sInfo.applicationInfo.uid, sInfo.packageName,
10490 sInfo.name);
10491 }
Dianne Hackbornb1c4a2a2010-01-19 15:36:42 -080010492 r = new ServiceRecord(this, ss, name, filter, sInfo, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010493 res.setService(r);
10494 mServices.put(name, r);
10495 mServicesByIntent.put(filter, r);
10496
10497 // Make sure this component isn't in the pending list.
10498 int N = mPendingServices.size();
10499 for (int i=0; i<N; i++) {
10500 ServiceRecord pr = mPendingServices.get(i);
10501 if (pr.name.equals(name)) {
10502 mPendingServices.remove(i);
10503 i--;
10504 N--;
10505 }
10506 }
10507 }
10508 } catch (RemoteException ex) {
10509 // pm is in same process, this will never happen.
10510 }
10511 }
10512 if (r != null) {
10513 if (checkComponentPermission(r.permission,
10514 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10515 != PackageManager.PERMISSION_GRANTED) {
10516 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10517 + " from pid=" + Binder.getCallingPid()
10518 + ", uid=" + Binder.getCallingUid()
10519 + " requires " + r.permission);
10520 return new ServiceLookupResult(null, r.permission);
10521 }
10522 return new ServiceLookupResult(r, null);
10523 }
10524 return null;
10525 }
10526
10527 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10528 long now = SystemClock.uptimeMillis();
10529 if (r.executeNesting == 0 && r.app != null) {
10530 if (r.app.executingServices.size() == 0) {
10531 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10532 msg.obj = r.app;
10533 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10534 }
10535 r.app.executingServices.add(r);
10536 }
10537 r.executeNesting++;
10538 r.executingStart = now;
10539 }
10540
10541 private final void sendServiceArgsLocked(ServiceRecord r,
10542 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010543 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010544 if (N == 0) {
10545 return;
10546 }
10547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010548 int i = 0;
10549 while (i < N) {
10550 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010551 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010552 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010553 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010554 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010555 // If somehow we got a dummy start at the front, then
10556 // just drop it here.
10557 i++;
10558 continue;
10559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010560 bumpServiceExecutingLocked(r);
10561 if (!oomAdjusted) {
10562 oomAdjusted = true;
10563 updateOomAdjLocked(r.app);
10564 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010565 int flags = 0;
10566 if (si.deliveryCount > 0) {
10567 flags |= Service.START_FLAG_RETRY;
10568 }
10569 if (si.doneExecutingCount > 0) {
10570 flags |= Service.START_FLAG_REDELIVERY;
10571 }
10572 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10573 si.deliveredTime = SystemClock.uptimeMillis();
10574 r.deliveredStarts.add(si);
10575 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010576 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010577 } catch (RemoteException e) {
10578 // Remote process gone... we'll let the normal cleanup take
10579 // care of this.
10580 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010581 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010582 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010583 break;
10584 }
10585 }
10586 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010587 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010588 } else {
10589 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010590 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010591 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010592 }
10593 }
10594 }
10595
10596 private final boolean requestServiceBindingLocked(ServiceRecord r,
10597 IntentBindRecord i, boolean rebind) {
10598 if (r.app == null || r.app.thread == null) {
10599 // If service is not currently running, can't yet bind.
10600 return false;
10601 }
10602 if ((!i.requested || rebind) && i.apps.size() > 0) {
10603 try {
10604 bumpServiceExecutingLocked(r);
10605 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10606 + ": shouldUnbind=" + i.hasBound);
10607 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10608 if (!rebind) {
10609 i.requested = true;
10610 }
10611 i.hasBound = true;
10612 i.doRebind = false;
10613 } catch (RemoteException e) {
10614 return false;
10615 }
10616 }
10617 return true;
10618 }
10619
10620 private final void requestServiceBindingsLocked(ServiceRecord r) {
10621 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10622 while (bindings.hasNext()) {
10623 IntentBindRecord i = bindings.next();
10624 if (!requestServiceBindingLocked(r, i, false)) {
10625 break;
10626 }
10627 }
10628 }
10629
10630 private final void realStartServiceLocked(ServiceRecord r,
10631 ProcessRecord app) throws RemoteException {
10632 if (app.thread == null) {
10633 throw new RemoteException();
10634 }
10635
10636 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010637 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010638
10639 app.services.add(r);
10640 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010641 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010642
10643 boolean created = false;
10644 try {
10645 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10646 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010647 mStringBuilder.setLength(0);
10648 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010649 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010650 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010651 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010652 synchronized (r.stats.getBatteryStats()) {
10653 r.stats.startLaunchedLocked();
10654 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010655 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010656 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010657 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010658 created = true;
10659 } finally {
10660 if (!created) {
10661 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010662 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010663 }
10664 }
10665
10666 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010667
10668 // If the service is in the started state, and there are no
10669 // pending arguments, then fake up one so its onStartCommand() will
10670 // be called.
10671 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10672 r.lastStartId++;
10673 if (r.lastStartId < 1) {
10674 r.lastStartId = 1;
10675 }
10676 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10677 }
10678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010679 sendServiceArgsLocked(r, true);
10680 }
10681
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010682 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10683 boolean allowCancel) {
10684 boolean canceled = false;
10685
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010686 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010687 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010688 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010689
10690 // Any delivered but not yet finished starts should be put back
10691 // on the pending list.
10692 final int N = r.deliveredStarts.size();
10693 if (N > 0) {
10694 for (int i=N-1; i>=0; i--) {
10695 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10696 if (si.intent == null) {
10697 // We'll generate this again if needed.
10698 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10699 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10700 r.pendingStarts.add(0, si);
10701 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10702 dur *= 2;
10703 if (minDuration < dur) minDuration = dur;
10704 if (resetTime < dur) resetTime = dur;
10705 } else {
10706 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10707 + r.name);
10708 canceled = true;
10709 }
10710 }
10711 r.deliveredStarts.clear();
10712 }
10713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010714 r.totalRestartCount++;
10715 if (r.restartDelay == 0) {
10716 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010717 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010718 } else {
10719 // If it has been a "reasonably long time" since the service
10720 // was started, then reset our restart duration back to
10721 // the beginning, so we don't infinitely increase the duration
10722 // on a service that just occasionally gets killed (which is
10723 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010724 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010725 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010726 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010727 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010728 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010729 if (r.restartDelay < minDuration) {
10730 r.restartDelay = minDuration;
10731 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010732 }
10733 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010734
10735 r.nextRestartTime = now + r.restartDelay;
10736
10737 // Make sure that we don't end up restarting a bunch of services
10738 // all at the same time.
10739 boolean repeat;
10740 do {
10741 repeat = false;
10742 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10743 ServiceRecord r2 = mRestartingServices.get(i);
10744 if (r2 != r && r.nextRestartTime
10745 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10746 && r.nextRestartTime
10747 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10748 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10749 r.restartDelay = r.nextRestartTime - now;
10750 repeat = true;
10751 break;
10752 }
10753 }
10754 } while (repeat);
10755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010756 if (!mRestartingServices.contains(r)) {
10757 mRestartingServices.add(r);
10758 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010759
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010760 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010761
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010762 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010763 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010764 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10765 Log.w(TAG, "Scheduling restart of crashed service "
10766 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010767 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010768 r.shortName, r.restartDelay);
10769
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010770 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010771 }
10772
10773 final void performServiceRestartLocked(ServiceRecord r) {
10774 if (!mRestartingServices.contains(r)) {
10775 return;
10776 }
10777 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10778 }
10779
10780 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10781 if (r.restartDelay == 0) {
10782 return false;
10783 }
10784 r.resetRestartCounter();
10785 mRestartingServices.remove(r);
10786 mHandler.removeCallbacks(r.restarter);
10787 return true;
10788 }
10789
10790 private final boolean bringUpServiceLocked(ServiceRecord r,
10791 int intentFlags, boolean whileRestarting) {
10792 //Log.i(TAG, "Bring up service:");
10793 //r.dump(" ");
10794
Dianne Hackborn36124872009-10-08 16:22:03 -070010795 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010796 sendServiceArgsLocked(r, false);
10797 return true;
10798 }
10799
10800 if (!whileRestarting && r.restartDelay > 0) {
10801 // If waiting for a restart, then do nothing.
10802 return true;
10803 }
10804
10805 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10806 + " " + r.intent);
10807
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010808 // We are now bringing the service up, so no longer in the
10809 // restarting state.
10810 mRestartingServices.remove(r);
10811
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010812 final String appName = r.processName;
10813 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10814 if (app != null && app.thread != null) {
10815 try {
10816 realStartServiceLocked(r, app);
10817 return true;
10818 } catch (RemoteException e) {
10819 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10820 }
10821
10822 // If a dead object exception was thrown -- fall through to
10823 // restart the application.
10824 }
10825
Dianne Hackborn36124872009-10-08 16:22:03 -070010826 // Not running -- get it started, and enqueue this service record
10827 // to be executed when the app comes up.
10828 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10829 "service", r.name, false) == null) {
10830 Log.w(TAG, "Unable to launch app "
10831 + r.appInfo.packageName + "/"
10832 + r.appInfo.uid + " for service "
10833 + r.intent.getIntent() + ": process is bad");
10834 bringDownServiceLocked(r, true);
10835 return false;
10836 }
10837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010838 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010839 mPendingServices.add(r);
10840 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010842 return true;
10843 }
10844
10845 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10846 //Log.i(TAG, "Bring down service:");
10847 //r.dump(" ");
10848
10849 // Does it still need to run?
10850 if (!force && r.startRequested) {
10851 return;
10852 }
10853 if (r.connections.size() > 0) {
10854 if (!force) {
10855 // XXX should probably keep a count of the number of auto-create
10856 // connections directly in the service.
10857 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10858 while (it.hasNext()) {
10859 ConnectionRecord cr = it.next();
10860 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10861 return;
10862 }
10863 }
10864 }
10865
10866 // Report to all of the connections that the service is no longer
10867 // available.
10868 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10869 while (it.hasNext()) {
10870 ConnectionRecord c = it.next();
10871 try {
10872 // todo: shouldn't be a synchronous call!
10873 c.conn.connected(r.name, null);
10874 } catch (Exception e) {
10875 Log.w(TAG, "Failure disconnecting service " + r.name +
10876 " to connection " + c.conn.asBinder() +
10877 " (in " + c.binding.client.processName + ")", e);
10878 }
10879 }
10880 }
10881
10882 // Tell the service that it has been unbound.
10883 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10884 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10885 while (it.hasNext()) {
10886 IntentBindRecord ibr = it.next();
10887 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10888 + ": hasBound=" + ibr.hasBound);
10889 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10890 try {
10891 bumpServiceExecutingLocked(r);
10892 updateOomAdjLocked(r.app);
10893 ibr.hasBound = false;
10894 r.app.thread.scheduleUnbindService(r,
10895 ibr.intent.getIntent());
10896 } catch (Exception e) {
10897 Log.w(TAG, "Exception when unbinding service "
10898 + r.shortName, e);
10899 serviceDoneExecutingLocked(r, true);
10900 }
10901 }
10902 }
10903 }
10904
10905 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10906 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010907 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010908 System.identityHashCode(r), r.shortName,
10909 (r.app != null) ? r.app.pid : -1);
10910
10911 mServices.remove(r.name);
10912 mServicesByIntent.remove(r.intent);
10913 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10914 r.totalRestartCount = 0;
10915 unscheduleServiceRestartLocked(r);
10916
10917 // Also make sure it is not on the pending list.
10918 int N = mPendingServices.size();
10919 for (int i=0; i<N; i++) {
10920 if (mPendingServices.get(i) == r) {
10921 mPendingServices.remove(i);
10922 if (DEBUG_SERVICE) Log.v(
10923 TAG, "Removed pending service: " + r.shortName);
10924 i--;
10925 N--;
10926 }
10927 }
10928
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010929 r.cancelNotification();
10930 r.isForeground = false;
10931 r.foregroundId = 0;
10932 r.foregroundNoti = null;
10933
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010934 // Clear start entries.
10935 r.deliveredStarts.clear();
10936 r.pendingStarts.clear();
10937
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010938 if (r.app != null) {
10939 synchronized (r.stats.getBatteryStats()) {
10940 r.stats.stopLaunchedLocked();
10941 }
10942 r.app.services.remove(r);
10943 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010944 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010945 if (DEBUG_SERVICE) Log.v(TAG,
10946 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010947 bumpServiceExecutingLocked(r);
10948 mStoppingServices.add(r);
10949 updateOomAdjLocked(r.app);
10950 r.app.thread.scheduleStopService(r);
10951 } catch (Exception e) {
10952 Log.w(TAG, "Exception when stopping service "
10953 + r.shortName, e);
10954 serviceDoneExecutingLocked(r, true);
10955 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010956 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010957 } else {
10958 if (DEBUG_SERVICE) Log.v(
10959 TAG, "Removed service that has no process: " + r.shortName);
10960 }
10961 } else {
10962 if (DEBUG_SERVICE) Log.v(
10963 TAG, "Removed service that is not running: " + r.shortName);
10964 }
10965 }
10966
10967 ComponentName startServiceLocked(IApplicationThread caller,
10968 Intent service, String resolvedType,
10969 int callingPid, int callingUid) {
10970 synchronized(this) {
10971 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10972 + " type=" + resolvedType + " args=" + service.getExtras());
10973
10974 if (caller != null) {
10975 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10976 if (callerApp == null) {
10977 throw new SecurityException(
10978 "Unable to find app for caller " + caller
10979 + " (pid=" + Binder.getCallingPid()
10980 + ") when starting service " + service);
10981 }
10982 }
10983
10984 ServiceLookupResult res =
10985 retrieveServiceLocked(service, resolvedType,
10986 callingPid, callingUid);
10987 if (res == null) {
10988 return null;
10989 }
10990 if (res.record == null) {
10991 return new ComponentName("!", res.permission != null
10992 ? res.permission : "private to package");
10993 }
10994 ServiceRecord r = res.record;
10995 if (unscheduleServiceRestartLocked(r)) {
10996 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10997 + r.shortName);
10998 }
10999 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011000 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011001 r.lastStartId++;
11002 if (r.lastStartId < 1) {
11003 r.lastStartId = 1;
11004 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011005 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011006 r.lastActivity = SystemClock.uptimeMillis();
11007 synchronized (r.stats.getBatteryStats()) {
11008 r.stats.startRunningLocked();
11009 }
11010 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
11011 return new ComponentName("!", "Service process is bad");
11012 }
11013 return r.name;
11014 }
11015 }
11016
11017 public ComponentName startService(IApplicationThread caller, Intent service,
11018 String resolvedType) {
11019 // Refuse possible leaked file descriptors
11020 if (service != null && service.hasFileDescriptors() == true) {
11021 throw new IllegalArgumentException("File descriptors passed in Intent");
11022 }
11023
11024 synchronized(this) {
11025 final int callingPid = Binder.getCallingPid();
11026 final int callingUid = Binder.getCallingUid();
11027 final long origId = Binder.clearCallingIdentity();
11028 ComponentName res = startServiceLocked(caller, service,
11029 resolvedType, callingPid, callingUid);
11030 Binder.restoreCallingIdentity(origId);
11031 return res;
11032 }
11033 }
11034
11035 ComponentName startServiceInPackage(int uid,
11036 Intent service, String resolvedType) {
11037 synchronized(this) {
11038 final long origId = Binder.clearCallingIdentity();
11039 ComponentName res = startServiceLocked(null, service,
11040 resolvedType, -1, uid);
11041 Binder.restoreCallingIdentity(origId);
11042 return res;
11043 }
11044 }
11045
11046 public int stopService(IApplicationThread caller, Intent service,
11047 String resolvedType) {
11048 // Refuse possible leaked file descriptors
11049 if (service != null && service.hasFileDescriptors() == true) {
11050 throw new IllegalArgumentException("File descriptors passed in Intent");
11051 }
11052
11053 synchronized(this) {
11054 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11055 + " type=" + resolvedType);
11056
11057 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11058 if (caller != null && callerApp == null) {
11059 throw new SecurityException(
11060 "Unable to find app for caller " + caller
11061 + " (pid=" + Binder.getCallingPid()
11062 + ") when stopping service " + service);
11063 }
11064
11065 // If this service is active, make sure it is stopped.
11066 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11067 if (r != null) {
11068 if (r.record != null) {
11069 synchronized (r.record.stats.getBatteryStats()) {
11070 r.record.stats.stopRunningLocked();
11071 }
11072 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011073 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011074 final long origId = Binder.clearCallingIdentity();
11075 bringDownServiceLocked(r.record, false);
11076 Binder.restoreCallingIdentity(origId);
11077 return 1;
11078 }
11079 return -1;
11080 }
11081 }
11082
11083 return 0;
11084 }
11085
11086 public IBinder peekService(Intent service, String resolvedType) {
11087 // Refuse possible leaked file descriptors
11088 if (service != null && service.hasFileDescriptors() == true) {
11089 throw new IllegalArgumentException("File descriptors passed in Intent");
11090 }
11091
11092 IBinder ret = null;
11093
11094 synchronized(this) {
11095 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11096
11097 if (r != null) {
11098 // r.record is null if findServiceLocked() failed the caller permission check
11099 if (r.record == null) {
11100 throw new SecurityException(
11101 "Permission Denial: Accessing service " + r.record.name
11102 + " from pid=" + Binder.getCallingPid()
11103 + ", uid=" + Binder.getCallingUid()
11104 + " requires " + r.permission);
11105 }
11106 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11107 if (ib != null) {
11108 ret = ib.binder;
11109 }
11110 }
11111 }
11112
11113 return ret;
11114 }
11115
11116 public boolean stopServiceToken(ComponentName className, IBinder token,
11117 int startId) {
11118 synchronized(this) {
11119 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11120 + " " + token + " startId=" + startId);
11121 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011122 if (r != null) {
11123 if (startId >= 0) {
11124 // Asked to only stop if done with all work. Note that
11125 // to avoid leaks, we will take this as dropping all
11126 // start items up to and including this one.
11127 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11128 if (si != null) {
11129 while (r.deliveredStarts.size() > 0) {
11130 if (r.deliveredStarts.remove(0) == si) {
11131 break;
11132 }
11133 }
11134 }
11135
11136 if (r.lastStartId != startId) {
11137 return false;
11138 }
11139
11140 if (r.deliveredStarts.size() > 0) {
11141 Log.w(TAG, "stopServiceToken startId " + startId
11142 + " is last, but have " + r.deliveredStarts.size()
11143 + " remaining args");
11144 }
11145 }
11146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011147 synchronized (r.stats.getBatteryStats()) {
11148 r.stats.stopRunningLocked();
11149 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011150 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011151 }
11152 final long origId = Binder.clearCallingIdentity();
11153 bringDownServiceLocked(r, false);
11154 Binder.restoreCallingIdentity(origId);
11155 return true;
11156 }
11157 }
11158 return false;
11159 }
11160
11161 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011162 int id, Notification notification, boolean removeNotification) {
11163 final long origId = Binder.clearCallingIdentity();
11164 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011165 synchronized(this) {
11166 ServiceRecord r = findServiceLocked(className, token);
11167 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011168 if (id != 0) {
11169 if (notification == null) {
11170 throw new IllegalArgumentException("null notification");
11171 }
11172 if (r.foregroundId != id) {
11173 r.cancelNotification();
11174 r.foregroundId = id;
11175 }
11176 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11177 r.foregroundNoti = notification;
11178 r.isForeground = true;
11179 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011180 if (r.app != null) {
11181 updateServiceForegroundLocked(r.app, true);
11182 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011183 } else {
11184 if (r.isForeground) {
11185 r.isForeground = false;
11186 if (r.app != null) {
11187 updateServiceForegroundLocked(r.app, true);
11188 }
11189 }
11190 if (removeNotification) {
11191 r.cancelNotification();
11192 r.foregroundId = 0;
11193 r.foregroundNoti = null;
11194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011195 }
11196 }
11197 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011198 } finally {
11199 Binder.restoreCallingIdentity(origId);
11200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011201 }
11202
11203 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11204 boolean anyForeground = false;
11205 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11206 if (sr.isForeground) {
11207 anyForeground = true;
11208 break;
11209 }
11210 }
11211 if (anyForeground != proc.foregroundServices) {
11212 proc.foregroundServices = anyForeground;
11213 if (oomAdj) {
11214 updateOomAdjLocked();
11215 }
11216 }
11217 }
11218
11219 public int bindService(IApplicationThread caller, IBinder token,
11220 Intent service, String resolvedType,
11221 IServiceConnection connection, int flags) {
11222 // Refuse possible leaked file descriptors
11223 if (service != null && service.hasFileDescriptors() == true) {
11224 throw new IllegalArgumentException("File descriptors passed in Intent");
11225 }
11226
11227 synchronized(this) {
11228 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11229 + " type=" + resolvedType + " conn=" + connection.asBinder()
11230 + " flags=0x" + Integer.toHexString(flags));
11231 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11232 if (callerApp == null) {
11233 throw new SecurityException(
11234 "Unable to find app for caller " + caller
11235 + " (pid=" + Binder.getCallingPid()
11236 + ") when binding service " + service);
11237 }
11238
11239 HistoryRecord activity = null;
11240 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011241 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011242 if (aindex < 0) {
11243 Log.w(TAG, "Binding with unknown activity: " + token);
11244 return 0;
11245 }
11246 activity = (HistoryRecord)mHistory.get(aindex);
11247 }
11248
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011249 int clientLabel = 0;
11250 PendingIntent clientIntent = null;
11251
11252 if (callerApp.info.uid == Process.SYSTEM_UID) {
11253 // Hacky kind of thing -- allow system stuff to tell us
11254 // what they are, so we can report this elsewhere for
11255 // others to know why certain services are running.
11256 try {
11257 clientIntent = (PendingIntent)service.getParcelableExtra(
11258 Intent.EXTRA_CLIENT_INTENT);
11259 } catch (RuntimeException e) {
11260 }
11261 if (clientIntent != null) {
11262 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11263 if (clientLabel != 0) {
11264 // There are no useful extras in the intent, trash them.
11265 // System code calling with this stuff just needs to know
11266 // this will happen.
11267 service = service.cloneFilter();
11268 }
11269 }
11270 }
11271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011272 ServiceLookupResult res =
11273 retrieveServiceLocked(service, resolvedType,
11274 Binder.getCallingPid(), Binder.getCallingUid());
11275 if (res == null) {
11276 return 0;
11277 }
11278 if (res.record == null) {
11279 return -1;
11280 }
11281 ServiceRecord s = res.record;
11282
11283 final long origId = Binder.clearCallingIdentity();
11284
11285 if (unscheduleServiceRestartLocked(s)) {
11286 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11287 + s.shortName);
11288 }
11289
11290 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11291 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011292 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011293
11294 IBinder binder = connection.asBinder();
11295 s.connections.put(binder, c);
11296 b.connections.add(c);
11297 if (activity != null) {
11298 if (activity.connections == null) {
11299 activity.connections = new HashSet<ConnectionRecord>();
11300 }
11301 activity.connections.add(c);
11302 }
11303 b.client.connections.add(c);
11304 mServiceConnections.put(binder, c);
11305
11306 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11307 s.lastActivity = SystemClock.uptimeMillis();
11308 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11309 return 0;
11310 }
11311 }
11312
11313 if (s.app != null) {
11314 // This could have made the service more important.
11315 updateOomAdjLocked(s.app);
11316 }
11317
11318 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11319 + ": received=" + b.intent.received
11320 + " apps=" + b.intent.apps.size()
11321 + " doRebind=" + b.intent.doRebind);
11322
11323 if (s.app != null && b.intent.received) {
11324 // Service is already running, so we can immediately
11325 // publish the connection.
11326 try {
11327 c.conn.connected(s.name, b.intent.binder);
11328 } catch (Exception e) {
11329 Log.w(TAG, "Failure sending service " + s.shortName
11330 + " to connection " + c.conn.asBinder()
11331 + " (in " + c.binding.client.processName + ")", e);
11332 }
11333
11334 // If this is the first app connected back to this binding,
11335 // and the service had previously asked to be told when
11336 // rebound, then do so.
11337 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11338 requestServiceBindingLocked(s, b.intent, true);
11339 }
11340 } else if (!b.intent.requested) {
11341 requestServiceBindingLocked(s, b.intent, false);
11342 }
11343
11344 Binder.restoreCallingIdentity(origId);
11345 }
11346
11347 return 1;
11348 }
11349
11350 private void removeConnectionLocked(
11351 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11352 IBinder binder = c.conn.asBinder();
11353 AppBindRecord b = c.binding;
11354 ServiceRecord s = b.service;
11355 s.connections.remove(binder);
11356 b.connections.remove(c);
11357 if (c.activity != null && c.activity != skipAct) {
11358 if (c.activity.connections != null) {
11359 c.activity.connections.remove(c);
11360 }
11361 }
11362 if (b.client != skipApp) {
11363 b.client.connections.remove(c);
11364 }
11365 mServiceConnections.remove(binder);
11366
11367 if (b.connections.size() == 0) {
11368 b.intent.apps.remove(b.client);
11369 }
11370
11371 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11372 + ": shouldUnbind=" + b.intent.hasBound);
11373 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11374 && b.intent.hasBound) {
11375 try {
11376 bumpServiceExecutingLocked(s);
11377 updateOomAdjLocked(s.app);
11378 b.intent.hasBound = false;
11379 // Assume the client doesn't want to know about a rebind;
11380 // we will deal with that later if it asks for one.
11381 b.intent.doRebind = false;
11382 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11383 } catch (Exception e) {
11384 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11385 serviceDoneExecutingLocked(s, true);
11386 }
11387 }
11388
11389 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11390 bringDownServiceLocked(s, false);
11391 }
11392 }
11393
11394 public boolean unbindService(IServiceConnection connection) {
11395 synchronized (this) {
11396 IBinder binder = connection.asBinder();
11397 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11398 ConnectionRecord r = mServiceConnections.get(binder);
11399 if (r == null) {
11400 Log.w(TAG, "Unbind failed: could not find connection for "
11401 + connection.asBinder());
11402 return false;
11403 }
11404
11405 final long origId = Binder.clearCallingIdentity();
11406
11407 removeConnectionLocked(r, null, null);
11408
11409 if (r.binding.service.app != null) {
11410 // This could have made the service less important.
11411 updateOomAdjLocked(r.binding.service.app);
11412 }
11413
11414 Binder.restoreCallingIdentity(origId);
11415 }
11416
11417 return true;
11418 }
11419
11420 public void publishService(IBinder token, Intent intent, IBinder service) {
11421 // Refuse possible leaked file descriptors
11422 if (intent != null && intent.hasFileDescriptors() == true) {
11423 throw new IllegalArgumentException("File descriptors passed in Intent");
11424 }
11425
11426 synchronized(this) {
11427 if (!(token instanceof ServiceRecord)) {
11428 throw new IllegalArgumentException("Invalid service token");
11429 }
11430 ServiceRecord r = (ServiceRecord)token;
11431
11432 final long origId = Binder.clearCallingIdentity();
11433
11434 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11435 + " " + intent + ": " + service);
11436 if (r != null) {
11437 Intent.FilterComparison filter
11438 = new Intent.FilterComparison(intent);
11439 IntentBindRecord b = r.bindings.get(filter);
11440 if (b != null && !b.received) {
11441 b.binder = service;
11442 b.requested = true;
11443 b.received = true;
11444 if (r.connections.size() > 0) {
11445 Iterator<ConnectionRecord> it
11446 = r.connections.values().iterator();
11447 while (it.hasNext()) {
11448 ConnectionRecord c = it.next();
11449 if (!filter.equals(c.binding.intent.intent)) {
11450 if (DEBUG_SERVICE) Log.v(
11451 TAG, "Not publishing to: " + c);
11452 if (DEBUG_SERVICE) Log.v(
11453 TAG, "Bound intent: " + c.binding.intent.intent);
11454 if (DEBUG_SERVICE) Log.v(
11455 TAG, "Published intent: " + intent);
11456 continue;
11457 }
11458 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11459 try {
11460 c.conn.connected(r.name, service);
11461 } catch (Exception e) {
11462 Log.w(TAG, "Failure sending service " + r.name +
11463 " to connection " + c.conn.asBinder() +
11464 " (in " + c.binding.client.processName + ")", e);
11465 }
11466 }
11467 }
11468 }
11469
11470 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11471
11472 Binder.restoreCallingIdentity(origId);
11473 }
11474 }
11475 }
11476
11477 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11478 // Refuse possible leaked file descriptors
11479 if (intent != null && intent.hasFileDescriptors() == true) {
11480 throw new IllegalArgumentException("File descriptors passed in Intent");
11481 }
11482
11483 synchronized(this) {
11484 if (!(token instanceof ServiceRecord)) {
11485 throw new IllegalArgumentException("Invalid service token");
11486 }
11487 ServiceRecord r = (ServiceRecord)token;
11488
11489 final long origId = Binder.clearCallingIdentity();
11490
11491 if (r != null) {
11492 Intent.FilterComparison filter
11493 = new Intent.FilterComparison(intent);
11494 IntentBindRecord b = r.bindings.get(filter);
11495 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11496 + " at " + b + ": apps="
11497 + (b != null ? b.apps.size() : 0));
11498 if (b != null) {
11499 if (b.apps.size() > 0) {
11500 // Applications have already bound since the last
11501 // unbind, so just rebind right here.
11502 requestServiceBindingLocked(r, b, true);
11503 } else {
11504 // Note to tell the service the next time there is
11505 // a new client.
11506 b.doRebind = true;
11507 }
11508 }
11509
11510 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11511
11512 Binder.restoreCallingIdentity(origId);
11513 }
11514 }
11515 }
11516
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011517 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011518 synchronized(this) {
11519 if (!(token instanceof ServiceRecord)) {
11520 throw new IllegalArgumentException("Invalid service token");
11521 }
11522 ServiceRecord r = (ServiceRecord)token;
11523 boolean inStopping = mStoppingServices.contains(token);
11524 if (r != null) {
11525 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11526 + ": nesting=" + r.executeNesting
11527 + ", inStopping=" + inStopping);
11528 if (r != token) {
11529 Log.w(TAG, "Done executing service " + r.name
11530 + " with incorrect token: given " + token
11531 + ", expected " + r);
11532 return;
11533 }
11534
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011535 if (type == 1) {
11536 // This is a call from a service start... take care of
11537 // book-keeping.
11538 r.callStart = true;
11539 switch (res) {
11540 case Service.START_STICKY_COMPATIBILITY:
11541 case Service.START_STICKY: {
11542 // We are done with the associated start arguments.
11543 r.findDeliveredStart(startId, true);
11544 // Don't stop if killed.
11545 r.stopIfKilled = false;
11546 break;
11547 }
11548 case Service.START_NOT_STICKY: {
11549 // We are done with the associated start arguments.
11550 r.findDeliveredStart(startId, true);
11551 if (r.lastStartId == startId) {
11552 // There is no more work, and this service
11553 // doesn't want to hang around if killed.
11554 r.stopIfKilled = true;
11555 }
11556 break;
11557 }
11558 case Service.START_REDELIVER_INTENT: {
11559 // We'll keep this item until they explicitly
11560 // call stop for it, but keep track of the fact
11561 // that it was delivered.
11562 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11563 if (si != null) {
11564 si.deliveryCount = 0;
11565 si.doneExecutingCount++;
11566 // Don't stop if killed.
11567 r.stopIfKilled = true;
11568 }
11569 break;
11570 }
11571 default:
11572 throw new IllegalArgumentException(
11573 "Unknown service start result: " + res);
11574 }
11575 if (res == Service.START_STICKY_COMPATIBILITY) {
11576 r.callStart = false;
11577 }
11578 }
11579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011580 final long origId = Binder.clearCallingIdentity();
11581 serviceDoneExecutingLocked(r, inStopping);
11582 Binder.restoreCallingIdentity(origId);
11583 } else {
11584 Log.w(TAG, "Done executing unknown service " + r.name
11585 + " with token " + token);
11586 }
11587 }
11588 }
11589
11590 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11591 r.executeNesting--;
11592 if (r.executeNesting <= 0 && r.app != null) {
11593 r.app.executingServices.remove(r);
11594 if (r.app.executingServices.size() == 0) {
11595 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11596 }
11597 if (inStopping) {
11598 mStoppingServices.remove(r);
11599 }
11600 updateOomAdjLocked(r.app);
11601 }
11602 }
11603
11604 void serviceTimeout(ProcessRecord proc) {
11605 synchronized(this) {
11606 if (proc.executingServices.size() == 0 || proc.thread == null) {
11607 return;
11608 }
11609 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11610 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11611 ServiceRecord timeout = null;
11612 long nextTime = 0;
11613 while (it.hasNext()) {
11614 ServiceRecord sr = it.next();
11615 if (sr.executingStart < maxTime) {
11616 timeout = sr;
11617 break;
11618 }
11619 if (sr.executingStart > nextTime) {
11620 nextTime = sr.executingStart;
11621 }
11622 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011623 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011624 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnor42471dd2010-01-07 17:25:22 -080011625 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011626 } else {
11627 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11628 msg.obj = proc;
11629 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11630 }
11631 }
11632 }
11633
11634 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011635 // BACKUP AND RESTORE
11636 // =========================================================
11637
11638 // Cause the target app to be launched if necessary and its backup agent
11639 // instantiated. The backup agent will invoke backupAgentCreated() on the
11640 // activity manager to announce its creation.
11641 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11642 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11643 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11644
11645 synchronized(this) {
11646 // !!! TODO: currently no check here that we're already bound
11647 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11648 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11649 synchronized (stats) {
11650 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11651 }
11652
11653 BackupRecord r = new BackupRecord(ss, app, backupMode);
11654 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11655 // startProcessLocked() returns existing proc's record if it's already running
11656 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011657 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011658 if (proc == null) {
11659 Log.e(TAG, "Unable to start backup agent process " + r);
11660 return false;
11661 }
11662
11663 r.app = proc;
11664 mBackupTarget = r;
11665 mBackupAppName = app.packageName;
11666
Christopher Tate6fa95972009-06-05 18:43:55 -070011667 // Try not to kill the process during backup
11668 updateOomAdjLocked(proc);
11669
Christopher Tate181fafa2009-05-14 11:12:14 -070011670 // If the process is already attached, schedule the creation of the backup agent now.
11671 // If it is not yet live, this will be done when it attaches to the framework.
11672 if (proc.thread != null) {
11673 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11674 try {
11675 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11676 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011677 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011678 }
11679 } else {
11680 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11681 }
11682 // Invariants: at this point, the target app process exists and the application
11683 // is either already running or in the process of coming up. mBackupTarget and
11684 // mBackupAppName describe the app, so that when it binds back to the AM we
11685 // know that it's scheduled for a backup-agent operation.
11686 }
11687
11688 return true;
11689 }
11690
11691 // A backup agent has just come up
11692 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11693 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11694 + " = " + agent);
11695
11696 synchronized(this) {
11697 if (!agentPackageName.equals(mBackupAppName)) {
11698 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11699 return;
11700 }
11701
Christopher Tate043dadc2009-06-02 16:11:00 -070011702 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011703 try {
11704 IBackupManager bm = IBackupManager.Stub.asInterface(
11705 ServiceManager.getService(Context.BACKUP_SERVICE));
11706 bm.agentConnected(agentPackageName, agent);
11707 } catch (RemoteException e) {
11708 // can't happen; the backup manager service is local
11709 } catch (Exception e) {
11710 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11711 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011712 } finally {
11713 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011714 }
11715 }
11716 }
11717
11718 // done with this agent
11719 public void unbindBackupAgent(ApplicationInfo appInfo) {
11720 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011721 if (appInfo == null) {
11722 Log.w(TAG, "unbind backup agent for null app");
11723 return;
11724 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011725
11726 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011727 if (mBackupAppName == null) {
11728 Log.w(TAG, "Unbinding backup agent with no active backup");
11729 return;
11730 }
11731
Christopher Tate181fafa2009-05-14 11:12:14 -070011732 if (!mBackupAppName.equals(appInfo.packageName)) {
11733 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11734 return;
11735 }
11736
Christopher Tate6fa95972009-06-05 18:43:55 -070011737 ProcessRecord proc = mBackupTarget.app;
11738 mBackupTarget = null;
11739 mBackupAppName = null;
11740
11741 // Not backing this app up any more; reset its OOM adjustment
11742 updateOomAdjLocked(proc);
11743
Christopher Tatec7b31e32009-06-10 15:49:30 -070011744 // If the app crashed during backup, 'thread' will be null here
11745 if (proc.thread != null) {
11746 try {
11747 proc.thread.scheduleDestroyBackupAgent(appInfo);
11748 } catch (Exception e) {
11749 Log.e(TAG, "Exception when unbinding backup agent:");
11750 e.printStackTrace();
11751 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011752 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011753 }
11754 }
11755 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011756 // BROADCASTS
11757 // =========================================================
11758
11759 private final List getStickies(String action, IntentFilter filter,
11760 List cur) {
11761 final ContentResolver resolver = mContext.getContentResolver();
11762 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11763 if (list == null) {
11764 return cur;
11765 }
11766 int N = list.size();
11767 for (int i=0; i<N; i++) {
11768 Intent intent = list.get(i);
11769 if (filter.match(resolver, intent, true, TAG) >= 0) {
11770 if (cur == null) {
11771 cur = new ArrayList<Intent>();
11772 }
11773 cur.add(intent);
11774 }
11775 }
11776 return cur;
11777 }
11778
11779 private final void scheduleBroadcastsLocked() {
11780 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11781 + mBroadcastsScheduled);
11782
11783 if (mBroadcastsScheduled) {
11784 return;
11785 }
11786 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11787 mBroadcastsScheduled = true;
11788 }
11789
11790 public Intent registerReceiver(IApplicationThread caller,
11791 IIntentReceiver receiver, IntentFilter filter, String permission) {
11792 synchronized(this) {
11793 ProcessRecord callerApp = null;
11794 if (caller != null) {
11795 callerApp = getRecordForAppLocked(caller);
11796 if (callerApp == null) {
11797 throw new SecurityException(
11798 "Unable to find app for caller " + caller
11799 + " (pid=" + Binder.getCallingPid()
11800 + ") when registering receiver " + receiver);
11801 }
11802 }
11803
11804 List allSticky = null;
11805
11806 // Look for any matching sticky broadcasts...
11807 Iterator actions = filter.actionsIterator();
11808 if (actions != null) {
11809 while (actions.hasNext()) {
11810 String action = (String)actions.next();
11811 allSticky = getStickies(action, filter, allSticky);
11812 }
11813 } else {
11814 allSticky = getStickies(null, filter, allSticky);
11815 }
11816
11817 // The first sticky in the list is returned directly back to
11818 // the client.
11819 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11820
11821 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11822 + ": " + sticky);
11823
11824 if (receiver == null) {
11825 return sticky;
11826 }
11827
11828 ReceiverList rl
11829 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11830 if (rl == null) {
11831 rl = new ReceiverList(this, callerApp,
11832 Binder.getCallingPid(),
11833 Binder.getCallingUid(), receiver);
11834 if (rl.app != null) {
11835 rl.app.receivers.add(rl);
11836 } else {
11837 try {
11838 receiver.asBinder().linkToDeath(rl, 0);
11839 } catch (RemoteException e) {
11840 return sticky;
11841 }
11842 rl.linkedToDeath = true;
11843 }
11844 mRegisteredReceivers.put(receiver.asBinder(), rl);
11845 }
11846 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11847 rl.add(bf);
11848 if (!bf.debugCheck()) {
11849 Log.w(TAG, "==> For Dynamic broadast");
11850 }
11851 mReceiverResolver.addFilter(bf);
11852
11853 // Enqueue broadcasts for all existing stickies that match
11854 // this filter.
11855 if (allSticky != null) {
11856 ArrayList receivers = new ArrayList();
11857 receivers.add(bf);
11858
11859 int N = allSticky.size();
11860 for (int i=0; i<N; i++) {
11861 Intent intent = (Intent)allSticky.get(i);
11862 BroadcastRecord r = new BroadcastRecord(intent, null,
11863 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011864 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011865 if (mParallelBroadcasts.size() == 0) {
11866 scheduleBroadcastsLocked();
11867 }
11868 mParallelBroadcasts.add(r);
11869 }
11870 }
11871
11872 return sticky;
11873 }
11874 }
11875
11876 public void unregisterReceiver(IIntentReceiver receiver) {
11877 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11878
11879 boolean doNext = false;
11880
11881 synchronized(this) {
11882 ReceiverList rl
11883 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11884 if (rl != null) {
11885 if (rl.curBroadcast != null) {
11886 BroadcastRecord r = rl.curBroadcast;
11887 doNext = finishReceiverLocked(
11888 receiver.asBinder(), r.resultCode, r.resultData,
11889 r.resultExtras, r.resultAbort, true);
11890 }
11891
11892 if (rl.app != null) {
11893 rl.app.receivers.remove(rl);
11894 }
11895 removeReceiverLocked(rl);
11896 if (rl.linkedToDeath) {
11897 rl.linkedToDeath = false;
11898 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11899 }
11900 }
11901 }
11902
11903 if (!doNext) {
11904 return;
11905 }
11906
11907 final long origId = Binder.clearCallingIdentity();
11908 processNextBroadcast(false);
11909 trimApplications();
11910 Binder.restoreCallingIdentity(origId);
11911 }
11912
11913 void removeReceiverLocked(ReceiverList rl) {
11914 mRegisteredReceivers.remove(rl.receiver.asBinder());
11915 int N = rl.size();
11916 for (int i=0; i<N; i++) {
11917 mReceiverResolver.removeFilter(rl.get(i));
11918 }
11919 }
11920
11921 private final int broadcastIntentLocked(ProcessRecord callerApp,
11922 String callerPackage, Intent intent, String resolvedType,
11923 IIntentReceiver resultTo, int resultCode, String resultData,
11924 Bundle map, String requiredPermission,
11925 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11926 intent = new Intent(intent);
11927
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011928 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011929 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11930 + " ordered=" + ordered);
11931 if ((resultTo != null) && !ordered) {
11932 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11933 }
11934
11935 // Handle special intents: if this broadcast is from the package
11936 // manager about a package being removed, we need to remove all of
11937 // its activities from the history stack.
11938 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11939 intent.getAction());
11940 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11941 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080011942 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011943 || uidRemoved) {
11944 if (checkComponentPermission(
11945 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11946 callingPid, callingUid, -1)
11947 == PackageManager.PERMISSION_GRANTED) {
11948 if (uidRemoved) {
11949 final Bundle intentExtras = intent.getExtras();
11950 final int uid = intentExtras != null
11951 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11952 if (uid >= 0) {
11953 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11954 synchronized (bs) {
11955 bs.removeUidStatsLocked(uid);
11956 }
11957 }
11958 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011959 // If resources are unvailble just force stop all
11960 // those packages and flush the attribute cache as well.
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080011961 if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011962 String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
11963 if (list != null && (list.length > 0)) {
11964 for (String pkg : list) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080011965 forceStopPackageLocked(pkg, -1, false, true, true);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011966 }
11967 }
11968 } else {
11969 Uri data = intent.getData();
11970 String ssp;
11971 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11972 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11973 forceStopPackageLocked(ssp,
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080011974 intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011975 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011976 }
11977 }
11978 }
11979 } else {
11980 String msg = "Permission Denial: " + intent.getAction()
11981 + " broadcast from " + callerPackage + " (pid=" + callingPid
11982 + ", uid=" + callingUid + ")"
11983 + " requires "
11984 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11985 Log.w(TAG, msg);
11986 throw new SecurityException(msg);
11987 }
11988 }
11989
11990 /*
11991 * If this is the time zone changed action, queue up a message that will reset the timezone
11992 * of all currently running processes. This message will get queued up before the broadcast
11993 * happens.
11994 */
11995 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11996 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11997 }
11998
Dianne Hackborn854060af2009-07-09 18:14:31 -070011999 /*
12000 * Prevent non-system code (defined here to be non-persistent
12001 * processes) from sending protected broadcasts.
12002 */
12003 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
12004 || callingUid == Process.SHELL_UID || callingUid == 0) {
12005 // Always okay.
12006 } else if (callerApp == null || !callerApp.persistent) {
12007 try {
12008 if (ActivityThread.getPackageManager().isProtectedBroadcast(
12009 intent.getAction())) {
12010 String msg = "Permission Denial: not allowed to send broadcast "
12011 + intent.getAction() + " from pid="
12012 + callingPid + ", uid=" + callingUid;
12013 Log.w(TAG, msg);
12014 throw new SecurityException(msg);
12015 }
12016 } catch (RemoteException e) {
12017 Log.w(TAG, "Remote exception", e);
12018 return BROADCAST_SUCCESS;
12019 }
12020 }
12021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012022 // Add to the sticky list if requested.
12023 if (sticky) {
12024 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
12025 callingPid, callingUid)
12026 != PackageManager.PERMISSION_GRANTED) {
12027 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
12028 + callingPid + ", uid=" + callingUid
12029 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12030 Log.w(TAG, msg);
12031 throw new SecurityException(msg);
12032 }
12033 if (requiredPermission != null) {
12034 Log.w(TAG, "Can't broadcast sticky intent " + intent
12035 + " and enforce permission " + requiredPermission);
12036 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
12037 }
12038 if (intent.getComponent() != null) {
12039 throw new SecurityException(
12040 "Sticky broadcasts can't target a specific component");
12041 }
12042 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12043 if (list == null) {
12044 list = new ArrayList<Intent>();
12045 mStickyBroadcasts.put(intent.getAction(), list);
12046 }
12047 int N = list.size();
12048 int i;
12049 for (i=0; i<N; i++) {
12050 if (intent.filterEquals(list.get(i))) {
12051 // This sticky already exists, replace it.
12052 list.set(i, new Intent(intent));
12053 break;
12054 }
12055 }
12056 if (i >= N) {
12057 list.add(new Intent(intent));
12058 }
12059 }
12060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012061 // Figure out who all will receive this broadcast.
12062 List receivers = null;
12063 List<BroadcastFilter> registeredReceivers = null;
12064 try {
12065 if (intent.getComponent() != null) {
12066 // Broadcast is going to one specific receiver class...
12067 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012068 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012069 if (ai != null) {
12070 receivers = new ArrayList();
12071 ResolveInfo ri = new ResolveInfo();
12072 ri.activityInfo = ai;
12073 receivers.add(ri);
12074 }
12075 } else {
12076 // Need to resolve the intent to interested receivers...
12077 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12078 == 0) {
12079 receivers =
12080 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012081 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012082 }
Mihai Preda074edef2009-05-18 17:13:31 +020012083 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012084 }
12085 } catch (RemoteException ex) {
12086 // pm is in same process, this will never happen.
12087 }
12088
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012089 final boolean replacePending =
12090 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12091
12092 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12093 + " replacePending=" + replacePending);
12094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012095 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12096 if (!ordered && NR > 0) {
12097 // If we are not serializing this broadcast, then send the
12098 // registered receivers separately so they don't wait for the
12099 // components to be launched.
12100 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12101 callerPackage, callingPid, callingUid, requiredPermission,
12102 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012103 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012104 if (DEBUG_BROADCAST) Log.v(
12105 TAG, "Enqueueing parallel broadcast " + r
12106 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012107 boolean replaced = false;
12108 if (replacePending) {
12109 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12110 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12111 if (DEBUG_BROADCAST) Log.v(TAG,
12112 "***** DROPPING PARALLEL: " + intent);
12113 mParallelBroadcasts.set(i, r);
12114 replaced = true;
12115 break;
12116 }
12117 }
12118 }
12119 if (!replaced) {
12120 mParallelBroadcasts.add(r);
12121 scheduleBroadcastsLocked();
12122 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012123 registeredReceivers = null;
12124 NR = 0;
12125 }
12126
12127 // Merge into one list.
12128 int ir = 0;
12129 if (receivers != null) {
12130 // A special case for PACKAGE_ADDED: do not allow the package
12131 // being added to see this broadcast. This prevents them from
12132 // using this as a back door to get run as soon as they are
12133 // installed. Maybe in the future we want to have a special install
12134 // broadcast or such for apps, but we'd like to deliberately make
12135 // this decision.
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012136 String skipPackages[] = null;
12137 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
12138 || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
12139 || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12140 Uri data = intent.getData();
12141 if (data != null) {
12142 String pkgName = data.getSchemeSpecificPart();
12143 if (pkgName != null) {
12144 skipPackages = new String[] { pkgName };
12145 }
12146 }
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080012147 } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012148 skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
The Android Open Source Project10592532009-03-18 17:39:46 -070012149 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012150 if (skipPackages != null && (skipPackages.length > 0)) {
12151 for (String skipPackage : skipPackages) {
12152 if (skipPackage != null) {
12153 int NT = receivers.size();
12154 for (int it=0; it<NT; it++) {
12155 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12156 if (curt.activityInfo.packageName.equals(skipPackage)) {
12157 receivers.remove(it);
12158 it--;
12159 NT--;
12160 }
12161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012162 }
12163 }
12164 }
12165
12166 int NT = receivers != null ? receivers.size() : 0;
12167 int it = 0;
12168 ResolveInfo curt = null;
12169 BroadcastFilter curr = null;
12170 while (it < NT && ir < NR) {
12171 if (curt == null) {
12172 curt = (ResolveInfo)receivers.get(it);
12173 }
12174 if (curr == null) {
12175 curr = registeredReceivers.get(ir);
12176 }
12177 if (curr.getPriority() >= curt.priority) {
12178 // Insert this broadcast record into the final list.
12179 receivers.add(it, curr);
12180 ir++;
12181 curr = null;
12182 it++;
12183 NT++;
12184 } else {
12185 // Skip to the next ResolveInfo in the final list.
12186 it++;
12187 curt = null;
12188 }
12189 }
12190 }
12191 while (ir < NR) {
12192 if (receivers == null) {
12193 receivers = new ArrayList();
12194 }
12195 receivers.add(registeredReceivers.get(ir));
12196 ir++;
12197 }
12198
12199 if ((receivers != null && receivers.size() > 0)
12200 || resultTo != null) {
12201 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12202 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012203 receivers, resultTo, resultCode, resultData, map, ordered,
12204 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012205 if (DEBUG_BROADCAST) Log.v(
12206 TAG, "Enqueueing ordered broadcast " + r
12207 + ": prev had " + mOrderedBroadcasts.size());
12208 if (DEBUG_BROADCAST) {
12209 int seq = r.intent.getIntExtra("seq", -1);
12210 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12211 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012212 boolean replaced = false;
12213 if (replacePending) {
12214 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12215 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12216 if (DEBUG_BROADCAST) Log.v(TAG,
12217 "***** DROPPING ORDERED: " + intent);
12218 mOrderedBroadcasts.set(i, r);
12219 replaced = true;
12220 break;
12221 }
12222 }
12223 }
12224 if (!replaced) {
12225 mOrderedBroadcasts.add(r);
12226 scheduleBroadcastsLocked();
12227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012228 }
12229
12230 return BROADCAST_SUCCESS;
12231 }
12232
12233 public final int broadcastIntent(IApplicationThread caller,
12234 Intent intent, String resolvedType, IIntentReceiver resultTo,
12235 int resultCode, String resultData, Bundle map,
12236 String requiredPermission, boolean serialized, boolean sticky) {
12237 // Refuse possible leaked file descriptors
12238 if (intent != null && intent.hasFileDescriptors() == true) {
12239 throw new IllegalArgumentException("File descriptors passed in Intent");
12240 }
12241
12242 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012243 int flags = intent.getFlags();
12244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012245 if (!mSystemReady) {
12246 // if the caller really truly claims to know what they're doing, go
12247 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012248 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12249 intent = new Intent(intent);
12250 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12251 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12252 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12253 + " before boot completion");
12254 throw new IllegalStateException("Cannot broadcast before boot completed");
12255 }
12256 }
12257
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012258 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12259 throw new IllegalArgumentException(
12260 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12261 }
12262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012263 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12264 final int callingPid = Binder.getCallingPid();
12265 final int callingUid = Binder.getCallingUid();
12266 final long origId = Binder.clearCallingIdentity();
12267 int res = broadcastIntentLocked(callerApp,
12268 callerApp != null ? callerApp.info.packageName : null,
12269 intent, resolvedType, resultTo,
12270 resultCode, resultData, map, requiredPermission, serialized,
12271 sticky, callingPid, callingUid);
12272 Binder.restoreCallingIdentity(origId);
12273 return res;
12274 }
12275 }
12276
12277 int broadcastIntentInPackage(String packageName, int uid,
12278 Intent intent, String resolvedType, IIntentReceiver resultTo,
12279 int resultCode, String resultData, Bundle map,
12280 String requiredPermission, boolean serialized, boolean sticky) {
12281 synchronized(this) {
12282 final long origId = Binder.clearCallingIdentity();
12283 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12284 resultTo, resultCode, resultData, map, requiredPermission,
12285 serialized, sticky, -1, uid);
12286 Binder.restoreCallingIdentity(origId);
12287 return res;
12288 }
12289 }
12290
12291 public final void unbroadcastIntent(IApplicationThread caller,
12292 Intent intent) {
12293 // Refuse possible leaked file descriptors
12294 if (intent != null && intent.hasFileDescriptors() == true) {
12295 throw new IllegalArgumentException("File descriptors passed in Intent");
12296 }
12297
12298 synchronized(this) {
12299 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12300 != PackageManager.PERMISSION_GRANTED) {
12301 String msg = "Permission Denial: unbroadcastIntent() from pid="
12302 + Binder.getCallingPid()
12303 + ", uid=" + Binder.getCallingUid()
12304 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12305 Log.w(TAG, msg);
12306 throw new SecurityException(msg);
12307 }
12308 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12309 if (list != null) {
12310 int N = list.size();
12311 int i;
12312 for (i=0; i<N; i++) {
12313 if (intent.filterEquals(list.get(i))) {
12314 list.remove(i);
12315 break;
12316 }
12317 }
12318 }
12319 }
12320 }
12321
12322 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12323 String resultData, Bundle resultExtras, boolean resultAbort,
12324 boolean explicit) {
12325 if (mOrderedBroadcasts.size() == 0) {
12326 if (explicit) {
12327 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12328 }
12329 return false;
12330 }
12331 BroadcastRecord r = mOrderedBroadcasts.get(0);
12332 if (r.receiver == null) {
12333 if (explicit) {
12334 Log.w(TAG, "finishReceiver called but none active");
12335 }
12336 return false;
12337 }
12338 if (r.receiver != receiver) {
12339 Log.w(TAG, "finishReceiver called but active receiver is different");
12340 return false;
12341 }
12342 int state = r.state;
12343 r.state = r.IDLE;
12344 if (state == r.IDLE) {
12345 if (explicit) {
12346 Log.w(TAG, "finishReceiver called but state is IDLE");
12347 }
12348 }
12349 r.receiver = null;
12350 r.intent.setComponent(null);
12351 if (r.curApp != null) {
12352 r.curApp.curReceiver = null;
12353 }
12354 if (r.curFilter != null) {
12355 r.curFilter.receiverList.curBroadcast = null;
12356 }
12357 r.curFilter = null;
12358 r.curApp = null;
12359 r.curComponent = null;
12360 r.curReceiver = null;
12361 mPendingBroadcast = null;
12362
12363 r.resultCode = resultCode;
12364 r.resultData = resultData;
12365 r.resultExtras = resultExtras;
12366 r.resultAbort = resultAbort;
12367
12368 // We will process the next receiver right now if this is finishing
12369 // an app receiver (which is always asynchronous) or after we have
12370 // come back from calling a receiver.
12371 return state == BroadcastRecord.APP_RECEIVE
12372 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12373 }
12374
12375 public void finishReceiver(IBinder who, int resultCode, String resultData,
12376 Bundle resultExtras, boolean resultAbort) {
12377 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12378
12379 // Refuse possible leaked file descriptors
12380 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12381 throw new IllegalArgumentException("File descriptors passed in Bundle");
12382 }
12383
12384 boolean doNext;
12385
12386 final long origId = Binder.clearCallingIdentity();
12387
12388 synchronized(this) {
12389 doNext = finishReceiverLocked(
12390 who, resultCode, resultData, resultExtras, resultAbort, true);
12391 }
12392
12393 if (doNext) {
12394 processNextBroadcast(false);
12395 }
12396 trimApplications();
12397
12398 Binder.restoreCallingIdentity(origId);
12399 }
12400
12401 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12402 if (r.nextReceiver > 0) {
12403 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12404 if (curReceiver instanceof BroadcastFilter) {
12405 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012406 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012407 System.identityHashCode(r),
12408 r.intent.getAction(),
12409 r.nextReceiver - 1,
12410 System.identityHashCode(bf));
12411 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012412 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012413 System.identityHashCode(r),
12414 r.intent.getAction(),
12415 r.nextReceiver - 1,
12416 ((ResolveInfo)curReceiver).toString());
12417 }
12418 } else {
12419 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12420 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012421 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012422 System.identityHashCode(r),
12423 r.intent.getAction(),
12424 r.nextReceiver,
12425 "NONE");
12426 }
12427 }
12428
12429 private final void broadcastTimeout() {
12430 synchronized (this) {
12431 if (mOrderedBroadcasts.size() == 0) {
12432 return;
12433 }
12434 long now = SystemClock.uptimeMillis();
12435 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012436 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012437 if (DEBUG_BROADCAST) Log.v(TAG,
12438 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012439 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012440 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012441 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012442 return;
12443 }
12444
12445 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012446 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012447 r.anrCount++;
12448
12449 // Current receiver has passed its expiration date.
12450 if (r.nextReceiver <= 0) {
12451 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12452 return;
12453 }
12454
12455 ProcessRecord app = null;
12456
12457 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12458 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12459 logBroadcastReceiverDiscard(r);
12460 if (curReceiver instanceof BroadcastFilter) {
12461 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12462 if (bf.receiverList.pid != 0
12463 && bf.receiverList.pid != MY_PID) {
12464 synchronized (this.mPidsSelfLocked) {
12465 app = this.mPidsSelfLocked.get(
12466 bf.receiverList.pid);
12467 }
12468 }
12469 } else {
12470 app = r.curApp;
12471 }
12472
12473 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012474 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012475 }
12476
12477 if (mPendingBroadcast == r) {
12478 mPendingBroadcast = null;
12479 }
12480
12481 // Move on to the next receiver.
12482 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12483 r.resultExtras, r.resultAbort, true);
12484 scheduleBroadcastsLocked();
12485 }
12486 }
12487
12488 private final void processCurBroadcastLocked(BroadcastRecord r,
12489 ProcessRecord app) throws RemoteException {
12490 if (app.thread == null) {
12491 throw new RemoteException();
12492 }
12493 r.receiver = app.thread.asBinder();
12494 r.curApp = app;
12495 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012496 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012497
12498 // Tell the application to launch this receiver.
12499 r.intent.setComponent(r.curComponent);
12500
12501 boolean started = false;
12502 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012503 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012504 "Delivering to component " + r.curComponent
12505 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012506 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012507 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12508 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12509 started = true;
12510 } finally {
12511 if (!started) {
12512 r.receiver = null;
12513 r.curApp = null;
12514 app.curReceiver = null;
12515 }
12516 }
12517
12518 }
12519
12520 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012521 Intent intent, int resultCode, String data, Bundle extras,
12522 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012523 if (app != null && app.thread != null) {
12524 // If we have an app thread, do the call through that so it is
12525 // correctly ordered with other one-way calls.
12526 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012527 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012528 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012529 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012530 }
12531 }
12532
12533 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12534 BroadcastFilter filter, boolean ordered) {
12535 boolean skip = false;
12536 if (filter.requiredPermission != null) {
12537 int perm = checkComponentPermission(filter.requiredPermission,
12538 r.callingPid, r.callingUid, -1);
12539 if (perm != PackageManager.PERMISSION_GRANTED) {
12540 Log.w(TAG, "Permission Denial: broadcasting "
12541 + r.intent.toString()
12542 + " from " + r.callerPackage + " (pid="
12543 + r.callingPid + ", uid=" + r.callingUid + ")"
12544 + " requires " + filter.requiredPermission
12545 + " due to registered receiver " + filter);
12546 skip = true;
12547 }
12548 }
12549 if (r.requiredPermission != null) {
12550 int perm = checkComponentPermission(r.requiredPermission,
12551 filter.receiverList.pid, filter.receiverList.uid, -1);
12552 if (perm != PackageManager.PERMISSION_GRANTED) {
12553 Log.w(TAG, "Permission Denial: receiving "
12554 + r.intent.toString()
12555 + " to " + filter.receiverList.app
12556 + " (pid=" + filter.receiverList.pid
12557 + ", uid=" + filter.receiverList.uid + ")"
12558 + " requires " + r.requiredPermission
12559 + " due to sender " + r.callerPackage
12560 + " (uid " + r.callingUid + ")");
12561 skip = true;
12562 }
12563 }
12564
12565 if (!skip) {
12566 // If this is not being sent as an ordered broadcast, then we
12567 // don't want to touch the fields that keep track of the current
12568 // state of ordered broadcasts.
12569 if (ordered) {
12570 r.receiver = filter.receiverList.receiver.asBinder();
12571 r.curFilter = filter;
12572 filter.receiverList.curBroadcast = r;
12573 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012574 if (filter.receiverList.app != null) {
12575 // Bump hosting application to no longer be in background
12576 // scheduling class. Note that we can't do that if there
12577 // isn't an app... but we can only be in that case for
12578 // things that directly call the IActivityManager API, which
12579 // are already core system stuff so don't matter for this.
12580 r.curApp = filter.receiverList.app;
12581 filter.receiverList.app.curReceiver = r;
12582 updateOomAdjLocked();
12583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012584 }
12585 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012586 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012587 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012588 Log.i(TAG, "Delivering to " + filter.receiverList.app
12589 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012590 }
12591 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12592 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012593 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012594 if (ordered) {
12595 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12596 }
12597 } catch (RemoteException e) {
12598 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12599 if (ordered) {
12600 r.receiver = null;
12601 r.curFilter = null;
12602 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012603 if (filter.receiverList.app != null) {
12604 filter.receiverList.app.curReceiver = null;
12605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012606 }
12607 }
12608 }
12609 }
12610
Dianne Hackborn12527f92009-11-11 17:39:50 -080012611 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12612 if (r.callingUid < 0) {
12613 // This was from a registerReceiver() call; ignore it.
12614 return;
12615 }
12616 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12617 MAX_BROADCAST_HISTORY-1);
12618 r.finishTime = SystemClock.uptimeMillis();
12619 mBroadcastHistory[0] = r;
12620 }
12621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012622 private final void processNextBroadcast(boolean fromMsg) {
12623 synchronized(this) {
12624 BroadcastRecord r;
12625
12626 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12627 + mParallelBroadcasts.size() + " broadcasts, "
12628 + mOrderedBroadcasts.size() + " serialized broadcasts");
12629
12630 updateCpuStats();
12631
12632 if (fromMsg) {
12633 mBroadcastsScheduled = false;
12634 }
12635
12636 // First, deliver any non-serialized broadcasts right away.
12637 while (mParallelBroadcasts.size() > 0) {
12638 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012639 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012640 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012641 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12642 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012643 for (int i=0; i<N; i++) {
12644 Object target = r.receivers.get(i);
12645 if (DEBUG_BROADCAST) Log.v(TAG,
12646 "Delivering non-serialized to registered "
12647 + target + ": " + r);
12648 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12649 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012650 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012651 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12652 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012653 }
12654
12655 // Now take care of the next serialized one...
12656
12657 // If we are waiting for a process to come up to handle the next
12658 // broadcast, then do nothing at this point. Just in case, we
12659 // check that the process we're waiting for still exists.
12660 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012661 if (DEBUG_BROADCAST_LIGHT) {
12662 Log.v(TAG, "processNextBroadcast: waiting for "
12663 + mPendingBroadcast.curApp);
12664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012665
12666 boolean isDead;
12667 synchronized (mPidsSelfLocked) {
12668 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12669 }
12670 if (!isDead) {
12671 // It's still alive, so keep waiting
12672 return;
12673 } else {
12674 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12675 + " died before responding to broadcast");
12676 mPendingBroadcast = null;
12677 }
12678 }
12679
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012680 boolean looped = false;
12681
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012682 do {
12683 if (mOrderedBroadcasts.size() == 0) {
12684 // No more broadcasts pending, so all done!
12685 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012686 if (looped) {
12687 // If we had finished the last ordered broadcast, then
12688 // make sure all processes have correct oom and sched
12689 // adjustments.
12690 updateOomAdjLocked();
12691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012692 return;
12693 }
12694 r = mOrderedBroadcasts.get(0);
12695 boolean forceReceive = false;
12696
12697 // Ensure that even if something goes awry with the timeout
12698 // detection, we catch "hung" broadcasts here, discard them,
12699 // and continue to make progress.
12700 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12701 long now = SystemClock.uptimeMillis();
12702 if (r.dispatchTime > 0) {
12703 if ((numReceivers > 0) &&
12704 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12705 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12706 + " now=" + now
12707 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012708 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012709 + " intent=" + r.intent
12710 + " numReceivers=" + numReceivers
12711 + " nextReceiver=" + r.nextReceiver
12712 + " state=" + r.state);
12713 broadcastTimeout(); // forcibly finish this broadcast
12714 forceReceive = true;
12715 r.state = BroadcastRecord.IDLE;
12716 }
12717 }
12718
12719 if (r.state != BroadcastRecord.IDLE) {
12720 if (DEBUG_BROADCAST) Log.d(TAG,
12721 "processNextBroadcast() called when not idle (state="
12722 + r.state + ")");
12723 return;
12724 }
12725
12726 if (r.receivers == null || r.nextReceiver >= numReceivers
12727 || r.resultAbort || forceReceive) {
12728 // No more receivers for this broadcast! Send the final
12729 // result if requested...
12730 if (r.resultTo != null) {
12731 try {
12732 if (DEBUG_BROADCAST) {
12733 int seq = r.intent.getIntExtra("seq", -1);
12734 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12735 + " seq=" + seq + " app=" + r.callerApp);
12736 }
12737 performReceive(r.callerApp, r.resultTo,
12738 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012739 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012740 } catch (RemoteException e) {
12741 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12742 }
12743 }
12744
12745 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12746 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12747
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012748 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12749 + r);
12750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012751 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012752 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012753 mOrderedBroadcasts.remove(0);
12754 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012755 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012756 continue;
12757 }
12758 } while (r == null);
12759
12760 // Get the next receiver...
12761 int recIdx = r.nextReceiver++;
12762
12763 // Keep track of when this receiver started, and make sure there
12764 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012765 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012766 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012767 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012768
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012769 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12770 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012771 if (DEBUG_BROADCAST) Log.v(TAG,
12772 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012773 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012774 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012775 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012776 }
12777
12778 Object nextReceiver = r.receivers.get(recIdx);
12779 if (nextReceiver instanceof BroadcastFilter) {
12780 // Simple case: this is a registered receiver who gets
12781 // a direct call.
12782 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12783 if (DEBUG_BROADCAST) Log.v(TAG,
12784 "Delivering serialized to registered "
12785 + filter + ": " + r);
12786 deliverToRegisteredReceiver(r, filter, r.ordered);
12787 if (r.receiver == null || !r.ordered) {
12788 // The receiver has already finished, so schedule to
12789 // process the next one.
12790 r.state = BroadcastRecord.IDLE;
12791 scheduleBroadcastsLocked();
12792 }
12793 return;
12794 }
12795
12796 // Hard case: need to instantiate the receiver, possibly
12797 // starting its application process to host it.
12798
12799 ResolveInfo info =
12800 (ResolveInfo)nextReceiver;
12801
12802 boolean skip = false;
12803 int perm = checkComponentPermission(info.activityInfo.permission,
12804 r.callingPid, r.callingUid,
12805 info.activityInfo.exported
12806 ? -1 : info.activityInfo.applicationInfo.uid);
12807 if (perm != PackageManager.PERMISSION_GRANTED) {
12808 Log.w(TAG, "Permission Denial: broadcasting "
12809 + r.intent.toString()
12810 + " from " + r.callerPackage + " (pid=" + r.callingPid
12811 + ", uid=" + r.callingUid + ")"
12812 + " requires " + info.activityInfo.permission
12813 + " due to receiver " + info.activityInfo.packageName
12814 + "/" + info.activityInfo.name);
12815 skip = true;
12816 }
12817 if (r.callingUid != Process.SYSTEM_UID &&
12818 r.requiredPermission != null) {
12819 try {
12820 perm = ActivityThread.getPackageManager().
12821 checkPermission(r.requiredPermission,
12822 info.activityInfo.applicationInfo.packageName);
12823 } catch (RemoteException e) {
12824 perm = PackageManager.PERMISSION_DENIED;
12825 }
12826 if (perm != PackageManager.PERMISSION_GRANTED) {
12827 Log.w(TAG, "Permission Denial: receiving "
12828 + r.intent + " to "
12829 + info.activityInfo.applicationInfo.packageName
12830 + " requires " + r.requiredPermission
12831 + " due to sender " + r.callerPackage
12832 + " (uid " + r.callingUid + ")");
12833 skip = true;
12834 }
12835 }
12836 if (r.curApp != null && r.curApp.crashing) {
12837 // If the target process is crashing, just skip it.
12838 skip = true;
12839 }
12840
12841 if (skip) {
12842 r.receiver = null;
12843 r.curFilter = null;
12844 r.state = BroadcastRecord.IDLE;
12845 scheduleBroadcastsLocked();
12846 return;
12847 }
12848
12849 r.state = BroadcastRecord.APP_RECEIVE;
12850 String targetProcess = info.activityInfo.processName;
12851 r.curComponent = new ComponentName(
12852 info.activityInfo.applicationInfo.packageName,
12853 info.activityInfo.name);
12854 r.curReceiver = info.activityInfo;
12855
12856 // Is this receiver's application already running?
12857 ProcessRecord app = getProcessRecordLocked(targetProcess,
12858 info.activityInfo.applicationInfo.uid);
12859 if (app != null && app.thread != null) {
12860 try {
12861 processCurBroadcastLocked(r, app);
12862 return;
12863 } catch (RemoteException e) {
12864 Log.w(TAG, "Exception when sending broadcast to "
12865 + r.curComponent, e);
12866 }
12867
12868 // If a dead object exception was thrown -- fall through to
12869 // restart the application.
12870 }
12871
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012872 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012873 if ((r.curApp=startProcessLocked(targetProcess,
12874 info.activityInfo.applicationInfo, true,
12875 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012876 "broadcast", r.curComponent,
12877 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12878 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012879 // Ah, this recipient is unavailable. Finish it if necessary,
12880 // and mark the broadcast record as ready for the next.
12881 Log.w(TAG, "Unable to launch app "
12882 + info.activityInfo.applicationInfo.packageName + "/"
12883 + info.activityInfo.applicationInfo.uid + " for broadcast "
12884 + r.intent + ": process is bad");
12885 logBroadcastReceiverDiscard(r);
12886 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12887 r.resultExtras, r.resultAbort, true);
12888 scheduleBroadcastsLocked();
12889 r.state = BroadcastRecord.IDLE;
12890 return;
12891 }
12892
12893 mPendingBroadcast = r;
12894 }
12895 }
12896
12897 // =========================================================
12898 // INSTRUMENTATION
12899 // =========================================================
12900
12901 public boolean startInstrumentation(ComponentName className,
12902 String profileFile, int flags, Bundle arguments,
12903 IInstrumentationWatcher watcher) {
12904 // Refuse possible leaked file descriptors
12905 if (arguments != null && arguments.hasFileDescriptors()) {
12906 throw new IllegalArgumentException("File descriptors passed in Bundle");
12907 }
12908
12909 synchronized(this) {
12910 InstrumentationInfo ii = null;
12911 ApplicationInfo ai = null;
12912 try {
12913 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012914 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012915 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012916 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012917 } catch (PackageManager.NameNotFoundException e) {
12918 }
12919 if (ii == null) {
12920 reportStartInstrumentationFailure(watcher, className,
12921 "Unable to find instrumentation info for: " + className);
12922 return false;
12923 }
12924 if (ai == null) {
12925 reportStartInstrumentationFailure(watcher, className,
12926 "Unable to find instrumentation target package: " + ii.targetPackage);
12927 return false;
12928 }
12929
12930 int match = mContext.getPackageManager().checkSignatures(
12931 ii.targetPackage, ii.packageName);
12932 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12933 String msg = "Permission Denial: starting instrumentation "
12934 + className + " from pid="
12935 + Binder.getCallingPid()
12936 + ", uid=" + Binder.getCallingPid()
12937 + " not allowed because package " + ii.packageName
12938 + " does not have a signature matching the target "
12939 + ii.targetPackage;
12940 reportStartInstrumentationFailure(watcher, className, msg);
12941 throw new SecurityException(msg);
12942 }
12943
12944 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080012945 forceStopPackageLocked(ii.targetPackage, -1, true, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012946 ProcessRecord app = addAppLocked(ai);
12947 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012948 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012949 app.instrumentationProfileFile = profileFile;
12950 app.instrumentationArguments = arguments;
12951 app.instrumentationWatcher = watcher;
12952 app.instrumentationResultClass = className;
12953 Binder.restoreCallingIdentity(origId);
12954 }
12955
12956 return true;
12957 }
12958
12959 /**
12960 * Report errors that occur while attempting to start Instrumentation. Always writes the
12961 * error to the logs, but if somebody is watching, send the report there too. This enables
12962 * the "am" command to report errors with more information.
12963 *
12964 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12965 * @param cn The component name of the instrumentation.
12966 * @param report The error report.
12967 */
12968 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12969 ComponentName cn, String report) {
12970 Log.w(TAG, report);
12971 try {
12972 if (watcher != null) {
12973 Bundle results = new Bundle();
12974 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12975 results.putString("Error", report);
12976 watcher.instrumentationStatus(cn, -1, results);
12977 }
12978 } catch (RemoteException e) {
12979 Log.w(TAG, e);
12980 }
12981 }
12982
12983 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12984 if (app.instrumentationWatcher != null) {
12985 try {
12986 // NOTE: IInstrumentationWatcher *must* be oneway here
12987 app.instrumentationWatcher.instrumentationFinished(
12988 app.instrumentationClass,
12989 resultCode,
12990 results);
12991 } catch (RemoteException e) {
12992 }
12993 }
12994 app.instrumentationWatcher = null;
12995 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012996 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012997 app.instrumentationProfileFile = null;
12998 app.instrumentationArguments = null;
12999
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080013000 forceStopPackageLocked(app.processName, -1, false, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013001 }
13002
13003 public void finishInstrumentation(IApplicationThread target,
13004 int resultCode, Bundle results) {
13005 // Refuse possible leaked file descriptors
13006 if (results != null && results.hasFileDescriptors()) {
13007 throw new IllegalArgumentException("File descriptors passed in Intent");
13008 }
13009
13010 synchronized(this) {
13011 ProcessRecord app = getRecordForAppLocked(target);
13012 if (app == null) {
13013 Log.w(TAG, "finishInstrumentation: no app for " + target);
13014 return;
13015 }
13016 final long origId = Binder.clearCallingIdentity();
13017 finishInstrumentationLocked(app, resultCode, results);
13018 Binder.restoreCallingIdentity(origId);
13019 }
13020 }
13021
13022 // =========================================================
13023 // CONFIGURATION
13024 // =========================================================
13025
13026 public ConfigurationInfo getDeviceConfigurationInfo() {
13027 ConfigurationInfo config = new ConfigurationInfo();
13028 synchronized (this) {
13029 config.reqTouchScreen = mConfiguration.touchscreen;
13030 config.reqKeyboardType = mConfiguration.keyboard;
13031 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013032 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
13033 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013034 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
13035 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013036 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
13037 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013038 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
13039 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070013040 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013041 }
13042 return config;
13043 }
13044
13045 public Configuration getConfiguration() {
13046 Configuration ci;
13047 synchronized(this) {
13048 ci = new Configuration(mConfiguration);
13049 }
13050 return ci;
13051 }
13052
13053 public void updateConfiguration(Configuration values) {
13054 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13055 "updateConfiguration()");
13056
13057 synchronized(this) {
13058 if (values == null && mWindowManager != null) {
13059 // sentinel: fetch the current configuration from the window manager
13060 values = mWindowManager.computeNewConfiguration();
13061 }
13062
13063 final long origId = Binder.clearCallingIdentity();
13064 updateConfigurationLocked(values, null);
13065 Binder.restoreCallingIdentity(origId);
13066 }
13067 }
13068
13069 /**
13070 * Do either or both things: (1) change the current configuration, and (2)
13071 * make sure the given activity is running with the (now) current
13072 * configuration. Returns true if the activity has been left running, or
13073 * false if <var>starting</var> is being destroyed to match the new
13074 * configuration.
13075 */
13076 public boolean updateConfigurationLocked(Configuration values,
13077 HistoryRecord starting) {
13078 int changes = 0;
13079
13080 boolean kept = true;
13081
13082 if (values != null) {
13083 Configuration newConfig = new Configuration(mConfiguration);
13084 changes = newConfig.updateFrom(values);
13085 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013086 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013087 Log.i(TAG, "Updating configuration to: " + values);
13088 }
13089
Doug Zongker2bec3d42009-12-04 12:52:44 -080013090 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013091
13092 if (values.locale != null) {
13093 saveLocaleLocked(values.locale,
13094 !values.locale.equals(mConfiguration.locale),
13095 values.userSetLocale);
13096 }
13097
Dianne Hackborne36d6e22010-02-17 19:46:25 -080013098 mConfigurationSeq++;
13099 if (mConfigurationSeq <= 0) {
13100 mConfigurationSeq = 1;
13101 }
13102 newConfig.seq = mConfigurationSeq;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013103 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013104 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013105
13106 AttributeCache ac = AttributeCache.instance();
13107 if (ac != null) {
13108 ac.updateConfiguration(mConfiguration);
13109 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013110
13111 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13112 msg.obj = new Configuration(mConfiguration);
13113 mHandler.sendMessage(msg);
13114
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013115 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13116 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013117 try {
13118 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013119 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13120 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013121 app.thread.scheduleConfigurationChanged(mConfiguration);
13122 }
13123 } catch (Exception e) {
13124 }
13125 }
13126 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013127 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13128 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013129 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13130 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013131 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13132 broadcastIntentLocked(null, null,
13133 new Intent(Intent.ACTION_LOCALE_CHANGED),
13134 null, null, 0, null, null,
13135 null, false, false, MY_PID, Process.SYSTEM_UID);
13136 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013137 }
13138 }
13139
13140 if (changes != 0 && starting == null) {
13141 // If the configuration changed, and the caller is not already
13142 // in the process of starting an activity, then find the top
13143 // activity to check if its configuration needs to change.
13144 starting = topRunningActivityLocked(null);
13145 }
13146
13147 if (starting != null) {
13148 kept = ensureActivityConfigurationLocked(starting, changes);
13149 if (kept) {
13150 // If this didn't result in the starting activity being
13151 // destroyed, then we need to make sure at this point that all
13152 // other activities are made visible.
13153 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13154 + ", ensuring others are correct.");
13155 ensureActivitiesVisibleLocked(starting, changes);
13156 }
13157 }
13158
Dianne Hackborne36d6e22010-02-17 19:46:25 -080013159 if (values != null && mWindowManager != null) {
13160 mWindowManager.setNewConfiguration(mConfiguration);
13161 }
13162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013163 return kept;
13164 }
13165
13166 private final boolean relaunchActivityLocked(HistoryRecord r,
13167 int changes, boolean andResume) {
13168 List<ResultInfo> results = null;
13169 List<Intent> newIntents = null;
13170 if (andResume) {
13171 results = r.results;
13172 newIntents = r.newIntents;
13173 }
13174 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13175 + " with results=" + results + " newIntents=" + newIntents
13176 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013177 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13178 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013179 r.task.taskId, r.shortComponentName);
13180
13181 r.startFreezingScreenLocked(r.app, 0);
13182
13183 try {
13184 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13185 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013186 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013187 // Note: don't need to call pauseIfSleepingLocked() here, because
13188 // the caller will only pass in 'andResume' if this activity is
13189 // currently resumed, which implies we aren't sleeping.
13190 } catch (RemoteException e) {
13191 return false;
13192 }
13193
13194 if (andResume) {
13195 r.results = null;
13196 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013197 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013198 }
13199
13200 return true;
13201 }
13202
13203 /**
13204 * Make sure the given activity matches the current configuration. Returns
13205 * false if the activity had to be destroyed. Returns true if the
13206 * configuration is the same, or the activity will remain running as-is
13207 * for whatever reason. Ensures the HistoryRecord is updated with the
13208 * correct configuration and all other bookkeeping is handled.
13209 */
13210 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13211 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013212 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13213 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013214
13215 // Short circuit: if the two configurations are the exact same
13216 // object (the common case), then there is nothing to do.
13217 Configuration newConfig = mConfiguration;
13218 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013219 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13220 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013221 return true;
13222 }
13223
13224 // We don't worry about activities that are finishing.
13225 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013226 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013227 "Configuration doesn't matter in finishing " + r);
13228 r.stopFreezingScreenLocked(false);
13229 return true;
13230 }
13231
13232 // Okay we now are going to make this activity have the new config.
13233 // But then we need to figure out how it needs to deal with that.
13234 Configuration oldConfig = r.configuration;
13235 r.configuration = newConfig;
13236
13237 // If the activity isn't currently running, just leave the new
13238 // configuration and it will pick that up next time it starts.
13239 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013240 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013241 "Configuration doesn't matter not running " + r);
13242 r.stopFreezingScreenLocked(false);
13243 return true;
13244 }
13245
13246 // If the activity isn't persistent, there is a chance we will
13247 // need to restart it.
13248 if (!r.persistent) {
13249
13250 // Figure out what has changed between the two configurations.
13251 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013252 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13253 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013254 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013255 + Integer.toHexString(r.info.configChanges)
13256 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013257 }
13258 if ((changes&(~r.info.configChanges)) != 0) {
13259 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13260 r.configChangeFlags |= changes;
13261 r.startFreezingScreenLocked(r.app, globalChanges);
13262 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013263 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13264 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013265 destroyActivityLocked(r, true);
13266 } else if (r.state == ActivityState.PAUSING) {
13267 // A little annoying: we are waiting for this activity to
13268 // finish pausing. Let's not do anything now, but just
13269 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013270 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13271 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013272 r.configDestroy = true;
13273 return true;
13274 } else if (r.state == ActivityState.RESUMED) {
13275 // Try to optimize this case: the configuration is changing
13276 // and we need to restart the top, resumed activity.
13277 // Instead of doing the normal handshaking, just say
13278 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013279 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13280 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013281 relaunchActivityLocked(r, r.configChangeFlags, true);
13282 r.configChangeFlags = 0;
13283 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013284 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13285 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013286 relaunchActivityLocked(r, r.configChangeFlags, false);
13287 r.configChangeFlags = 0;
13288 }
13289
13290 // All done... tell the caller we weren't able to keep this
13291 // activity around.
13292 return false;
13293 }
13294 }
13295
13296 // Default case: the activity can handle this new configuration, so
13297 // hand it over. Note that we don't need to give it the new
13298 // configuration, since we always send configuration changes to all
13299 // process when they happen so it can just use whatever configuration
13300 // it last got.
13301 if (r.app != null && r.app.thread != null) {
13302 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013303 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013304 r.app.thread.scheduleActivityConfigurationChanged(r);
13305 } catch (RemoteException e) {
13306 // If process died, whatever.
13307 }
13308 }
13309 r.stopFreezingScreenLocked(false);
13310
13311 return true;
13312 }
13313
13314 /**
13315 * Save the locale. You must be inside a synchronized (this) block.
13316 */
13317 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13318 if(isDiff) {
13319 SystemProperties.set("user.language", l.getLanguage());
13320 SystemProperties.set("user.region", l.getCountry());
13321 }
13322
13323 if(isPersist) {
13324 SystemProperties.set("persist.sys.language", l.getLanguage());
13325 SystemProperties.set("persist.sys.country", l.getCountry());
13326 SystemProperties.set("persist.sys.localevar", l.getVariant());
13327 }
13328 }
13329
13330 // =========================================================
13331 // LIFETIME MANAGEMENT
13332 // =========================================================
13333
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013334 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13335 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013336 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013337 // This adjustment has already been computed. If we are calling
13338 // from the top, we may have already computed our adjustment with
13339 // an earlier hidden adjustment that isn't really for us... if
13340 // so, use the new hidden adjustment.
13341 if (!recursed && app.hidden) {
13342 app.curAdj = hiddenAdj;
13343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013344 return app.curAdj;
13345 }
13346
13347 if (app.thread == null) {
13348 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013349 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013350 return (app.curAdj=EMPTY_APP_ADJ);
13351 }
13352
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013353 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13354 // The max adjustment doesn't allow this app to be anything
13355 // below foreground, so it is not worth doing work for it.
13356 app.adjType = "fixed";
13357 app.adjSeq = mAdjSeq;
13358 app.curRawAdj = app.maxAdj;
13359 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13360 return (app.curAdj=app.maxAdj);
13361 }
13362
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013363 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013364 app.adjSource = null;
13365 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013366 app.empty = false;
13367 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013368
The Android Open Source Project4df24232009-03-05 14:34:35 -080013369 // Determine the importance of the process, starting with most
13370 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013371 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013372 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013373 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013374 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013375 // The last app on the list is the foreground app.
13376 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013377 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013378 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013379 } else if (app.instrumentationClass != null) {
13380 // Don't want to kill running instrumentation.
13381 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013382 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013383 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013384 } else if (app.persistentActivities > 0) {
13385 // Special persistent activities... shouldn't be used these days.
13386 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013387 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013388 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013389 } else if (app.curReceiver != null ||
13390 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13391 // An app that is currently receiving a broadcast also
13392 // counts as being in the foreground.
13393 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013394 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013395 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013396 } else if (app.executingServices.size() > 0) {
13397 // An app that is currently executing a service callback also
13398 // counts as being in the foreground.
13399 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013400 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013401 app.adjType = "exec-service";
13402 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013403 // The user is aware of this app, so make it visible.
13404 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013405 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013406 app.adjType = "foreground-service";
13407 } else if (app.forcingToForeground != null) {
13408 // The user is aware of this app, so make it visible.
13409 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013410 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013411 app.adjType = "force-foreground";
13412 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013413 } else if (app == mHomeProcess) {
13414 // This process is hosting what we currently consider to be the
13415 // home app, so we don't want to let it go into the background.
13416 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013417 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013418 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013419 } else if ((N=app.activities.size()) != 0) {
13420 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013421 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013422 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013423 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013424 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013425 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013426 for (int j=0; j<N; j++) {
13427 if (((HistoryRecord)app.activities.get(j)).visible) {
13428 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013429 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013430 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013431 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013432 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013433 break;
13434 }
13435 }
13436 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013437 // A very not-needed process. If this is lower in the lru list,
13438 // we will push it in to the empty bucket.
13439 app.hidden = true;
13440 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013441 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013442 adj = hiddenAdj;
13443 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013444 }
13445
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013446 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13447
The Android Open Source Project4df24232009-03-05 14:34:35 -080013448 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013449 // there are applications dependent on our services or providers, but
13450 // this gives us a baseline and makes sure we don't get into an
13451 // infinite recursion.
13452 app.adjSeq = mAdjSeq;
13453 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013454
Christopher Tate6fa95972009-06-05 18:43:55 -070013455 if (mBackupTarget != null && app == mBackupTarget.app) {
13456 // If possible we want to avoid killing apps while they're being backed up
13457 if (adj > BACKUP_APP_ADJ) {
13458 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13459 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013460 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013461 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013462 }
13463 }
13464
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013465 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13466 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013467 final long now = SystemClock.uptimeMillis();
13468 // This process is more important if the top activity is
13469 // bound to the service.
13470 Iterator jt = app.services.iterator();
13471 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13472 ServiceRecord s = (ServiceRecord)jt.next();
13473 if (s.startRequested) {
13474 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13475 // This service has seen some activity within
13476 // recent memory, so we will keep its process ahead
13477 // of the background processes.
13478 if (adj > SECONDARY_SERVER_ADJ) {
13479 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013480 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013481 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013482 }
13483 }
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013484 // If we have let the service slide into the background
13485 // state, still have some text describing what it is doing
13486 // even though the service no longer has an impact.
13487 if (adj > SECONDARY_SERVER_ADJ) {
13488 app.adjType = "started-bg-services";
13489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013490 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013491 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13492 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013493 Iterator<ConnectionRecord> kt
13494 = s.connections.values().iterator();
13495 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13496 // XXX should compute this based on the max of
13497 // all connected clients.
13498 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013499 if (cr.binding.client == app) {
13500 // Binding to ourself is not interesting.
13501 continue;
13502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013503 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13504 ProcessRecord client = cr.binding.client;
13505 int myHiddenAdj = hiddenAdj;
13506 if (myHiddenAdj > client.hiddenAdj) {
13507 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13508 myHiddenAdj = client.hiddenAdj;
13509 } else {
13510 myHiddenAdj = VISIBLE_APP_ADJ;
13511 }
13512 }
13513 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013514 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013515 if (adj > clientAdj) {
13516 adj = clientAdj > VISIBLE_APP_ADJ
13517 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013518 if (!client.hidden) {
13519 app.hidden = false;
13520 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013521 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013522 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13523 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013524 app.adjSource = cr.binding.client;
13525 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013526 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013527 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13528 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13529 schedGroup = Process.THREAD_GROUP_DEFAULT;
13530 }
13531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013532 }
13533 HistoryRecord a = cr.activity;
13534 //if (a != null) {
13535 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13536 //}
13537 if (a != null && adj > FOREGROUND_APP_ADJ &&
13538 (a.state == ActivityState.RESUMED
13539 || a.state == ActivityState.PAUSING)) {
13540 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013541 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013542 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013543 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013544 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13545 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013546 app.adjSource = a;
13547 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013548 }
13549 }
13550 }
13551 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013552
13553 // Finally, f this process has active services running in it, we
13554 // would like to avoid killing it unless it would prevent the current
13555 // application from running. By default we put the process in
13556 // with the rest of the background processes; as we scan through
13557 // its services we may bump it up from there.
13558 if (adj > hiddenAdj) {
13559 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013560 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013561 app.adjType = "bg-services";
13562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013563 }
13564
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013565 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13566 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013567 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013568 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13569 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013570 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13571 if (cpr.clients.size() != 0) {
13572 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13573 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13574 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013575 if (client == app) {
13576 // Being our own client is not interesting.
13577 continue;
13578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013579 int myHiddenAdj = hiddenAdj;
13580 if (myHiddenAdj > client.hiddenAdj) {
13581 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13582 myHiddenAdj = client.hiddenAdj;
13583 } else {
13584 myHiddenAdj = FOREGROUND_APP_ADJ;
13585 }
13586 }
13587 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013588 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013589 if (adj > clientAdj) {
13590 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013591 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013592 if (!client.hidden) {
13593 app.hidden = false;
13594 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013595 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013596 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13597 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013598 app.adjSource = client;
13599 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013600 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013601 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13602 schedGroup = Process.THREAD_GROUP_DEFAULT;
13603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013604 }
13605 }
13606 // If the provider has external (non-framework) process
13607 // dependencies, ensure that its adjustment is at least
13608 // FOREGROUND_APP_ADJ.
13609 if (cpr.externals != 0) {
13610 if (adj > FOREGROUND_APP_ADJ) {
13611 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013612 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013613 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013614 app.adjType = "provider";
13615 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013616 }
13617 }
13618 }
13619 }
13620
13621 app.curRawAdj = adj;
13622
13623 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13624 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13625 if (adj > app.maxAdj) {
13626 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013627 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13628 schedGroup = Process.THREAD_GROUP_DEFAULT;
13629 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013630 }
13631
13632 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013633 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013635 return adj;
13636 }
13637
13638 /**
13639 * Ask a given process to GC right now.
13640 */
13641 final void performAppGcLocked(ProcessRecord app) {
13642 try {
13643 app.lastRequestedGc = SystemClock.uptimeMillis();
13644 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013645 if (app.reportLowMemory) {
13646 app.reportLowMemory = false;
13647 app.thread.scheduleLowMemory();
13648 } else {
13649 app.thread.processInBackground();
13650 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013651 }
13652 } catch (Exception e) {
13653 // whatever.
13654 }
13655 }
13656
13657 /**
13658 * Returns true if things are idle enough to perform GCs.
13659 */
13660 private final boolean canGcNow() {
13661 return mParallelBroadcasts.size() == 0
13662 && mOrderedBroadcasts.size() == 0
13663 && (mSleeping || (mResumedActivity != null &&
13664 mResumedActivity.idle));
13665 }
13666
13667 /**
13668 * Perform GCs on all processes that are waiting for it, but only
13669 * if things are idle.
13670 */
13671 final void performAppGcsLocked() {
13672 final int N = mProcessesToGc.size();
13673 if (N <= 0) {
13674 return;
13675 }
13676 if (canGcNow()) {
13677 while (mProcessesToGc.size() > 0) {
13678 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013679 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13680 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13681 <= SystemClock.uptimeMillis()) {
13682 // To avoid spamming the system, we will GC processes one
13683 // at a time, waiting a few seconds between each.
13684 performAppGcLocked(proc);
13685 scheduleAppGcsLocked();
13686 return;
13687 } else {
13688 // It hasn't been long enough since we last GCed this
13689 // process... put it in the list to wait for its time.
13690 addProcessToGcListLocked(proc);
13691 break;
13692 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013693 }
13694 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013695
13696 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013697 }
13698 }
13699
13700 /**
13701 * If all looks good, perform GCs on all processes waiting for them.
13702 */
13703 final void performAppGcsIfAppropriateLocked() {
13704 if (canGcNow()) {
13705 performAppGcsLocked();
13706 return;
13707 }
13708 // Still not idle, wait some more.
13709 scheduleAppGcsLocked();
13710 }
13711
13712 /**
13713 * Schedule the execution of all pending app GCs.
13714 */
13715 final void scheduleAppGcsLocked() {
13716 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013717
13718 if (mProcessesToGc.size() > 0) {
13719 // Schedule a GC for the time to the next process.
13720 ProcessRecord proc = mProcessesToGc.get(0);
13721 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13722
13723 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13724 long now = SystemClock.uptimeMillis();
13725 if (when < (now+GC_TIMEOUT)) {
13726 when = now + GC_TIMEOUT;
13727 }
13728 mHandler.sendMessageAtTime(msg, when);
13729 }
13730 }
13731
13732 /**
13733 * Add a process to the array of processes waiting to be GCed. Keeps the
13734 * list in sorted order by the last GC time. The process can't already be
13735 * on the list.
13736 */
13737 final void addProcessToGcListLocked(ProcessRecord proc) {
13738 boolean added = false;
13739 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13740 if (mProcessesToGc.get(i).lastRequestedGc <
13741 proc.lastRequestedGc) {
13742 added = true;
13743 mProcessesToGc.add(i+1, proc);
13744 break;
13745 }
13746 }
13747 if (!added) {
13748 mProcessesToGc.add(0, proc);
13749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013750 }
13751
13752 /**
13753 * Set up to ask a process to GC itself. This will either do it
13754 * immediately, or put it on the list of processes to gc the next
13755 * time things are idle.
13756 */
13757 final void scheduleAppGcLocked(ProcessRecord app) {
13758 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013759 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013760 return;
13761 }
13762 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013763 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013764 scheduleAppGcsLocked();
13765 }
13766 }
13767
13768 private final boolean updateOomAdjLocked(
13769 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13770 app.hiddenAdj = hiddenAdj;
13771
13772 if (app.thread == null) {
13773 return true;
13774 }
13775
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013776 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013777
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013778 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013779 if (app.curRawAdj != app.setRawAdj) {
13780 if (app.curRawAdj > FOREGROUND_APP_ADJ
13781 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13782 // If this app is transitioning from foreground to
13783 // non-foreground, have it do a gc.
13784 scheduleAppGcLocked(app);
13785 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13786 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13787 // Likewise do a gc when an app is moving in to the
13788 // background (such as a service stopping).
13789 scheduleAppGcLocked(app);
13790 }
13791 app.setRawAdj = app.curRawAdj;
13792 }
13793 if (adj != app.setAdj) {
13794 if (Process.setOomAdj(app.pid, adj)) {
13795 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13796 TAG, "Set app " + app.processName +
13797 " oom adj to " + adj);
13798 app.setAdj = adj;
13799 } else {
13800 return false;
13801 }
13802 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013803 if (app.setSchedGroup != app.curSchedGroup) {
13804 app.setSchedGroup = app.curSchedGroup;
13805 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13806 "Setting process group of " + app.processName
13807 + " to " + app.curSchedGroup);
13808 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013809 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013810 try {
13811 Process.setProcessGroup(app.pid, app.curSchedGroup);
13812 } catch (Exception e) {
13813 Log.w(TAG, "Failed setting process group of " + app.pid
13814 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013815 e.printStackTrace();
13816 } finally {
13817 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013818 }
13819 }
13820 if (false) {
13821 if (app.thread != null) {
13822 try {
13823 app.thread.setSchedulingGroup(app.curSchedGroup);
13824 } catch (RemoteException e) {
13825 }
13826 }
13827 }
13828 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013829 }
13830
13831 return true;
13832 }
13833
13834 private final HistoryRecord resumedAppLocked() {
13835 HistoryRecord resumedActivity = mResumedActivity;
13836 if (resumedActivity == null || resumedActivity.app == null) {
13837 resumedActivity = mPausingActivity;
13838 if (resumedActivity == null || resumedActivity.app == null) {
13839 resumedActivity = topRunningActivityLocked(null);
13840 }
13841 }
13842 return resumedActivity;
13843 }
13844
13845 private final boolean updateOomAdjLocked(ProcessRecord app) {
13846 final HistoryRecord TOP_ACT = resumedAppLocked();
13847 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13848 int curAdj = app.curAdj;
13849 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13850 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13851
13852 mAdjSeq++;
13853
13854 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13855 if (res) {
13856 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13857 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13858 if (nowHidden != wasHidden) {
13859 // Changed to/from hidden state, so apps after it in the LRU
13860 // list may also be changed.
13861 updateOomAdjLocked();
13862 }
13863 }
13864 return res;
13865 }
13866
13867 private final boolean updateOomAdjLocked() {
13868 boolean didOomAdj = true;
13869 final HistoryRecord TOP_ACT = resumedAppLocked();
13870 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13871
13872 if (false) {
13873 RuntimeException e = new RuntimeException();
13874 e.fillInStackTrace();
13875 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13876 }
13877
13878 mAdjSeq++;
13879
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013880 // Let's determine how many processes we have running vs.
13881 // how many slots we have for background processes; we may want
13882 // to put multiple processes in a slot of there are enough of
13883 // them.
13884 int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
13885 int factor = (mLruProcesses.size()-4)/numSlots;
13886 if (factor < 1) factor = 1;
13887 int step = 0;
13888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013889 // First try updating the OOM adjustment for each of the
13890 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013891 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013892 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13893 while (i > 0) {
13894 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013895 ProcessRecord app = mLruProcesses.get(i);
13896 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013897 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013898 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013899 && app.curAdj == curHiddenAdj) {
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013900 step++;
13901 if (step >= factor) {
13902 step = 0;
13903 curHiddenAdj++;
13904 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013905 }
13906 } else {
13907 didOomAdj = false;
13908 }
13909 }
13910
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013911 // If we return false, we will fall back on killing processes to
13912 // have a fixed limit. Do this if a limit has been requested; else
13913 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013914 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13915 }
13916
13917 private final void trimApplications() {
13918 synchronized (this) {
13919 int i;
13920
13921 // First remove any unused application processes whose package
13922 // has been removed.
13923 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13924 final ProcessRecord app = mRemovedProcesses.get(i);
13925 if (app.activities.size() == 0
13926 && app.curReceiver == null && app.services.size() == 0) {
13927 Log.i(
13928 TAG, "Exiting empty application process "
13929 + app.processName + " ("
13930 + (app.thread != null ? app.thread.asBinder() : null)
13931 + ")\n");
13932 if (app.pid > 0 && app.pid != MY_PID) {
13933 Process.killProcess(app.pid);
13934 } else {
13935 try {
13936 app.thread.scheduleExit();
13937 } catch (Exception e) {
13938 // Ignore exceptions.
13939 }
13940 }
13941 cleanUpApplicationRecordLocked(app, false, -1);
13942 mRemovedProcesses.remove(i);
13943
13944 if (app.persistent) {
13945 if (app.persistent) {
13946 addAppLocked(app.info);
13947 }
13948 }
13949 }
13950 }
13951
13952 // Now try updating the OOM adjustment for each of the
13953 // application processes based on their current state.
13954 // If the setOomAdj() API is not supported, then go with our
13955 // back-up plan...
13956 if (!updateOomAdjLocked()) {
13957
13958 // Count how many processes are running services.
13959 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013960 for (i=mLruProcesses.size()-1; i>=0; i--) {
13961 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013962
13963 if (app.persistent || app.services.size() != 0
13964 || app.curReceiver != null
13965 || app.persistentActivities > 0) {
13966 // Don't count processes holding services against our
13967 // maximum process count.
13968 if (localLOGV) Log.v(
13969 TAG, "Not trimming app " + app + " with services: "
13970 + app.services);
13971 numServiceProcs++;
13972 }
13973 }
13974
13975 int curMaxProcs = mProcessLimit;
13976 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13977 if (mAlwaysFinishActivities) {
13978 curMaxProcs = 1;
13979 }
13980 curMaxProcs += numServiceProcs;
13981
13982 // Quit as many processes as we can to get down to the desired
13983 // process count. First remove any processes that no longer
13984 // have activites running in them.
13985 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013986 i<mLruProcesses.size()
13987 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013988 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013989 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013990 // Quit an application only if it is not currently
13991 // running any activities.
13992 if (!app.persistent && app.activities.size() == 0
13993 && app.curReceiver == null && app.services.size() == 0) {
13994 Log.i(
13995 TAG, "Exiting empty application process "
13996 + app.processName + " ("
13997 + (app.thread != null ? app.thread.asBinder() : null)
13998 + ")\n");
13999 if (app.pid > 0 && app.pid != MY_PID) {
14000 Process.killProcess(app.pid);
14001 } else {
14002 try {
14003 app.thread.scheduleExit();
14004 } catch (Exception e) {
14005 // Ignore exceptions.
14006 }
14007 }
14008 // todo: For now we assume the application is not buggy
14009 // or evil, and will quit as a result of our request.
14010 // Eventually we need to drive this off of the death
14011 // notification, and kill the process if it takes too long.
14012 cleanUpApplicationRecordLocked(app, false, i);
14013 i--;
14014 }
14015 }
14016
14017 // If we still have too many processes, now from the least
14018 // recently used process we start finishing activities.
14019 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014020 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014021 " of " + curMaxProcs + " processes");
14022 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014023 i<mLruProcesses.size()
14024 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014025 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014026 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014027 // Quit the application only if we have a state saved for
14028 // all of its activities.
14029 boolean canQuit = !app.persistent && app.curReceiver == null
14030 && app.services.size() == 0
14031 && app.persistentActivities == 0;
14032 int NUMA = app.activities.size();
14033 int j;
14034 if (Config.LOGV) Log.v(
14035 TAG, "Looking to quit " + app.processName);
14036 for (j=0; j<NUMA && canQuit; j++) {
14037 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14038 if (Config.LOGV) Log.v(
14039 TAG, " " + r.intent.getComponent().flattenToShortString()
14040 + ": frozen=" + r.haveState + ", visible=" + r.visible);
14041 canQuit = (r.haveState || !r.stateNotNeeded)
14042 && !r.visible && r.stopped;
14043 }
14044 if (canQuit) {
14045 // Finish all of the activities, and then the app itself.
14046 for (j=0; j<NUMA; j++) {
14047 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14048 if (!r.finishing) {
14049 destroyActivityLocked(r, false);
14050 }
14051 r.resultTo = null;
14052 }
14053 Log.i(TAG, "Exiting application process "
14054 + app.processName + " ("
14055 + (app.thread != null ? app.thread.asBinder() : null)
14056 + ")\n");
14057 if (app.pid > 0 && app.pid != MY_PID) {
14058 Process.killProcess(app.pid);
14059 } else {
14060 try {
14061 app.thread.scheduleExit();
14062 } catch (Exception e) {
14063 // Ignore exceptions.
14064 }
14065 }
14066 // todo: For now we assume the application is not buggy
14067 // or evil, and will quit as a result of our request.
14068 // Eventually we need to drive this off of the death
14069 // notification, and kill the process if it takes too long.
14070 cleanUpApplicationRecordLocked(app, false, i);
14071 i--;
14072 //dump();
14073 }
14074 }
14075
14076 }
14077
14078 int curMaxActivities = MAX_ACTIVITIES;
14079 if (mAlwaysFinishActivities) {
14080 curMaxActivities = 1;
14081 }
14082
14083 // Finally, if there are too many activities now running, try to
14084 // finish as many as we can to get back down to the limit.
14085 for ( i=0;
14086 i<mLRUActivities.size()
14087 && mLRUActivities.size() > curMaxActivities;
14088 i++) {
14089 final HistoryRecord r
14090 = (HistoryRecord)mLRUActivities.get(i);
14091
14092 // We can finish this one if we have its icicle saved and
14093 // it is not persistent.
14094 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14095 && r.stopped && !r.persistent && !r.finishing) {
14096 final int origSize = mLRUActivities.size();
14097 destroyActivityLocked(r, true);
14098
14099 // This will remove it from the LRU list, so keep
14100 // our index at the same value. Note that this check to
14101 // see if the size changes is just paranoia -- if
14102 // something unexpected happens, we don't want to end up
14103 // in an infinite loop.
14104 if (origSize > mLRUActivities.size()) {
14105 i--;
14106 }
14107 }
14108 }
14109 }
14110 }
14111
14112 /** This method sends the specified signal to each of the persistent apps */
14113 public void signalPersistentProcesses(int sig) throws RemoteException {
14114 if (sig != Process.SIGNAL_USR1) {
14115 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14116 }
14117
14118 synchronized (this) {
14119 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14120 != PackageManager.PERMISSION_GRANTED) {
14121 throw new SecurityException("Requires permission "
14122 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14123 }
14124
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014125 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14126 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014127 if (r.thread != null && r.persistent) {
14128 Process.sendSignal(r.pid, sig);
14129 }
14130 }
14131 }
14132 }
14133
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014134 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014135 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014136
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014137 try {
14138 synchronized (this) {
14139 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14140 // its own permission.
14141 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14142 != PackageManager.PERMISSION_GRANTED) {
14143 throw new SecurityException("Requires permission "
14144 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014145 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014146
14147 if (start && fd == null) {
14148 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014149 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014150
14151 ProcessRecord proc = null;
14152 try {
14153 int pid = Integer.parseInt(process);
14154 synchronized (mPidsSelfLocked) {
14155 proc = mPidsSelfLocked.get(pid);
14156 }
14157 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014158 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014159
14160 if (proc == null) {
14161 HashMap<String, SparseArray<ProcessRecord>> all
14162 = mProcessNames.getMap();
14163 SparseArray<ProcessRecord> procs = all.get(process);
14164 if (procs != null && procs.size() > 0) {
14165 proc = procs.valueAt(0);
14166 }
14167 }
14168
14169 if (proc == null || proc.thread == null) {
14170 throw new IllegalArgumentException("Unknown process: " + process);
14171 }
14172
14173 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14174 if (isSecure) {
14175 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14176 throw new SecurityException("Process not debuggable: " + proc);
14177 }
14178 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014179
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014180 proc.thread.profilerControl(start, path, fd);
14181 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014182 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014183 }
14184 } catch (RemoteException e) {
14185 throw new IllegalStateException("Process disappeared");
14186 } finally {
14187 if (fd != null) {
14188 try {
14189 fd.close();
14190 } catch (IOException e) {
14191 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014192 }
14193 }
14194 }
14195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014196 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14197 public void monitor() {
14198 synchronized (this) { }
14199 }
14200}