blob: 4169cc5b3fda256f36444a95d88312520868520e [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
7618 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7619 final boolean firstClass = cpr == null;
7620 if (firstClass) {
7621 try {
7622 ApplicationInfo ai =
7623 ActivityThread.getPackageManager().
7624 getApplicationInfo(
7625 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007626 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007627 if (ai == null) {
7628 Log.w(TAG, "No package info for content provider "
7629 + cpi.name);
7630 return null;
7631 }
7632 cpr = new ContentProviderRecord(cpi, ai);
7633 } catch (RemoteException ex) {
7634 // pm is in same process, this will never happen.
7635 }
7636 }
7637
7638 if (r != null && cpr.canRunHere(r)) {
7639 // If this is a multiprocess provider, then just return its
7640 // info and allow the caller to instantiate it. Only do
7641 // this if the provider is the same user as the caller's
7642 // process, or can run as root (so can be in any process).
7643 return cpr;
7644 }
7645
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007646 if (DEBUG_PROVIDER) {
7647 RuntimeException e = new RuntimeException("here");
7648 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7649 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007650 }
7651
7652 // This is single process, and our app is now connecting to it.
7653 // See if we are already in the process of launching this
7654 // provider.
7655 final int N = mLaunchingProviders.size();
7656 int i;
7657 for (i=0; i<N; i++) {
7658 if (mLaunchingProviders.get(i) == cpr) {
7659 break;
7660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007661 }
7662
7663 // If the provider is not already being launched, then get it
7664 // started.
7665 if (i >= N) {
7666 final long origId = Binder.clearCallingIdentity();
7667 ProcessRecord proc = startProcessLocked(cpi.processName,
7668 cpr.appInfo, false, 0, "content provider",
7669 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007670 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007671 if (proc == null) {
7672 Log.w(TAG, "Unable to launch app "
7673 + cpi.applicationInfo.packageName + "/"
7674 + cpi.applicationInfo.uid + " for provider "
7675 + name + ": process is bad");
7676 return null;
7677 }
7678 cpr.launchingApp = proc;
7679 mLaunchingProviders.add(cpr);
7680 Binder.restoreCallingIdentity(origId);
7681 }
7682
7683 // Make sure the provider is published (the same provider class
7684 // may be published under multiple names).
7685 if (firstClass) {
7686 mProvidersByClass.put(cpi.name, cpr);
7687 }
7688 mProvidersByName.put(name, cpr);
7689
7690 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007691 if (DEBUG_PROVIDER) Log.v(TAG,
7692 "Adding provider requested by "
7693 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007694 + cpr.info.processName);
7695 Integer cnt = r.conProviders.get(cpr);
7696 if (cnt == null) {
7697 r.conProviders.put(cpr, new Integer(1));
7698 } else {
7699 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7700 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007701 cpr.clients.add(r);
7702 } else {
7703 cpr.externals++;
7704 }
7705 }
7706 }
7707
7708 // Wait for the provider to be published...
7709 synchronized (cpr) {
7710 while (cpr.provider == null) {
7711 if (cpr.launchingApp == null) {
7712 Log.w(TAG, "Unable to launch app "
7713 + cpi.applicationInfo.packageName + "/"
7714 + cpi.applicationInfo.uid + " for provider "
7715 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007716 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007717 cpi.applicationInfo.packageName,
7718 cpi.applicationInfo.uid, name);
7719 return null;
7720 }
7721 try {
7722 cpr.wait();
7723 } catch (InterruptedException ex) {
7724 }
7725 }
7726 }
7727 return cpr;
7728 }
7729
7730 public final ContentProviderHolder getContentProvider(
7731 IApplicationThread caller, String name) {
7732 if (caller == null) {
7733 String msg = "null IApplicationThread when getting content provider "
7734 + name;
7735 Log.w(TAG, msg);
7736 throw new SecurityException(msg);
7737 }
7738
7739 return getContentProviderImpl(caller, name);
7740 }
7741
7742 private ContentProviderHolder getContentProviderExternal(String name) {
7743 return getContentProviderImpl(null, name);
7744 }
7745
7746 /**
7747 * Drop a content provider from a ProcessRecord's bookkeeping
7748 * @param cpr
7749 */
7750 public void removeContentProvider(IApplicationThread caller, String name) {
7751 synchronized (this) {
7752 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7753 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007754 // remove from mProvidersByClass
7755 if (DEBUG_PROVIDER) Log.v(TAG, name +
7756 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007757 return;
7758 }
7759 final ProcessRecord r = getRecordForAppLocked(caller);
7760 if (r == null) {
7761 throw new SecurityException(
7762 "Unable to find app for caller " + caller +
7763 " when removing content provider " + name);
7764 }
7765 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007766 ContentProviderRecord localCpr = (ContentProviderRecord)
7767 mProvidersByClass.get(cpr.info.name);
7768 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7769 + r.info.processName + " from process "
7770 + localCpr.appInfo.processName);
7771 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007772 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007773 Log.w(TAG, "removeContentProvider called on local provider: "
7774 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007775 return;
7776 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007777 Integer cnt = r.conProviders.get(localCpr);
7778 if (cnt == null || cnt.intValue() <= 1) {
7779 localCpr.clients.remove(r);
7780 r.conProviders.remove(localCpr);
7781 } else {
7782 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007784 }
7785 updateOomAdjLocked();
7786 }
7787 }
7788
7789 private void removeContentProviderExternal(String name) {
7790 synchronized (this) {
7791 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7792 if(cpr == null) {
7793 //remove from mProvidersByClass
7794 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7795 return;
7796 }
7797
7798 //update content provider record entry info
7799 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7800 localCpr.externals--;
7801 if (localCpr.externals < 0) {
7802 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7803 }
7804 updateOomAdjLocked();
7805 }
7806 }
7807
7808 public final void publishContentProviders(IApplicationThread caller,
7809 List<ContentProviderHolder> providers) {
7810 if (providers == null) {
7811 return;
7812 }
7813
7814 synchronized(this) {
7815 final ProcessRecord r = getRecordForAppLocked(caller);
7816 if (r == null) {
7817 throw new SecurityException(
7818 "Unable to find app for caller " + caller
7819 + " (pid=" + Binder.getCallingPid()
7820 + ") when publishing content providers");
7821 }
7822
7823 final long origId = Binder.clearCallingIdentity();
7824
7825 final int N = providers.size();
7826 for (int i=0; i<N; i++) {
7827 ContentProviderHolder src = providers.get(i);
7828 if (src == null || src.info == null || src.provider == null) {
7829 continue;
7830 }
7831 ContentProviderRecord dst =
7832 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7833 if (dst != null) {
7834 mProvidersByClass.put(dst.info.name, dst);
7835 String names[] = dst.info.authority.split(";");
7836 for (int j = 0; j < names.length; j++) {
7837 mProvidersByName.put(names[j], dst);
7838 }
7839
7840 int NL = mLaunchingProviders.size();
7841 int j;
7842 for (j=0; j<NL; j++) {
7843 if (mLaunchingProviders.get(j) == dst) {
7844 mLaunchingProviders.remove(j);
7845 j--;
7846 NL--;
7847 }
7848 }
7849 synchronized (dst) {
7850 dst.provider = src.provider;
7851 dst.app = r;
7852 dst.notifyAll();
7853 }
7854 updateOomAdjLocked(r);
7855 }
7856 }
7857
7858 Binder.restoreCallingIdentity(origId);
7859 }
7860 }
7861
7862 public static final void installSystemProviders() {
7863 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7864 List providers = mSelf.generateApplicationProvidersLocked(app);
7865 mSystemThread.installSystemProviders(providers);
7866 }
7867
7868 // =========================================================
7869 // GLOBAL MANAGEMENT
7870 // =========================================================
7871
7872 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7873 ApplicationInfo info, String customProcess) {
7874 String proc = customProcess != null ? customProcess : info.processName;
7875 BatteryStatsImpl.Uid.Proc ps = null;
7876 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7877 synchronized (stats) {
7878 ps = stats.getProcessStatsLocked(info.uid, proc);
7879 }
7880 return new ProcessRecord(ps, thread, info, proc);
7881 }
7882
7883 final ProcessRecord addAppLocked(ApplicationInfo info) {
7884 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7885
7886 if (app == null) {
7887 app = newProcessRecordLocked(null, info, null);
7888 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007889 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007890 }
7891
7892 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7893 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7894 app.persistent = true;
7895 app.maxAdj = CORE_SERVER_ADJ;
7896 }
7897 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7898 mPersistentStartingProcesses.add(app);
7899 startProcessLocked(app, "added application", app.processName);
7900 }
7901
7902 return app;
7903 }
7904
7905 public void unhandledBack() {
7906 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7907 "unhandledBack()");
7908
7909 synchronized(this) {
7910 int count = mHistory.size();
Dianne Hackborn03abb812010-01-04 18:43:19 -08007911 if (DEBUG_SWITCH) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007912 TAG, "Performing unhandledBack(): stack size = " + count);
7913 if (count > 1) {
7914 final long origId = Binder.clearCallingIdentity();
7915 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7916 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7917 Binder.restoreCallingIdentity(origId);
7918 }
7919 }
7920 }
7921
7922 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7923 String name = uri.getAuthority();
7924 ContentProviderHolder cph = getContentProviderExternal(name);
7925 ParcelFileDescriptor pfd = null;
7926 if (cph != null) {
7927 // We record the binder invoker's uid in thread-local storage before
7928 // going to the content provider to open the file. Later, in the code
7929 // that handles all permissions checks, we look for this uid and use
7930 // that rather than the Activity Manager's own uid. The effect is that
7931 // we do the check against the caller's permissions even though it looks
7932 // to the content provider like the Activity Manager itself is making
7933 // the request.
7934 sCallerIdentity.set(new Identity(
7935 Binder.getCallingPid(), Binder.getCallingUid()));
7936 try {
7937 pfd = cph.provider.openFile(uri, "r");
7938 } catch (FileNotFoundException e) {
7939 // do nothing; pfd will be returned null
7940 } finally {
7941 // Ensure that whatever happens, we clean up the identity state
7942 sCallerIdentity.remove();
7943 }
7944
7945 // We've got the fd now, so we're done with the provider.
7946 removeContentProviderExternal(name);
7947 } else {
7948 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7949 }
7950 return pfd;
7951 }
7952
7953 public void goingToSleep() {
7954 synchronized(this) {
7955 mSleeping = true;
7956 mWindowManager.setEventDispatching(false);
7957
7958 if (mResumedActivity != null) {
7959 pauseIfSleepingLocked();
7960 } else {
7961 Log.w(TAG, "goingToSleep with no resumed activity!");
7962 }
7963 }
7964 }
7965
Dianne Hackborn55280a92009-05-07 15:53:46 -07007966 public boolean shutdown(int timeout) {
7967 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7968 != PackageManager.PERMISSION_GRANTED) {
7969 throw new SecurityException("Requires permission "
7970 + android.Manifest.permission.SHUTDOWN);
7971 }
7972
7973 boolean timedout = false;
7974
7975 synchronized(this) {
7976 mShuttingDown = true;
7977 mWindowManager.setEventDispatching(false);
7978
7979 if (mResumedActivity != null) {
7980 pauseIfSleepingLocked();
7981 final long endTime = System.currentTimeMillis() + timeout;
7982 while (mResumedActivity != null || mPausingActivity != null) {
7983 long delay = endTime - System.currentTimeMillis();
7984 if (delay <= 0) {
7985 Log.w(TAG, "Activity manager shutdown timed out");
7986 timedout = true;
7987 break;
7988 }
7989 try {
7990 this.wait();
7991 } catch (InterruptedException e) {
7992 }
7993 }
7994 }
7995 }
7996
7997 mUsageStatsService.shutdown();
7998 mBatteryStatsService.shutdown();
7999
8000 return timedout;
8001 }
8002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008003 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07008004 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008005 if (!mGoingToSleep.isHeld()) {
8006 mGoingToSleep.acquire();
8007 if (mLaunchingActivity.isHeld()) {
8008 mLaunchingActivity.release();
8009 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
8010 }
8011 }
8012
8013 // If we are not currently pausing an activity, get the current
8014 // one to pause. If we are pausing one, we will just let that stuff
8015 // run and release the wake lock when all done.
8016 if (mPausingActivity == null) {
8017 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8018 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8019 startPausingLocked(false, true);
8020 }
8021 }
8022 }
8023
8024 public void wakingUp() {
8025 synchronized(this) {
8026 if (mGoingToSleep.isHeld()) {
8027 mGoingToSleep.release();
8028 }
8029 mWindowManager.setEventDispatching(true);
8030 mSleeping = false;
8031 resumeTopActivityLocked(null);
8032 }
8033 }
8034
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008035 public void stopAppSwitches() {
8036 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8037 != PackageManager.PERMISSION_GRANTED) {
8038 throw new SecurityException("Requires permission "
8039 + android.Manifest.permission.STOP_APP_SWITCHES);
8040 }
8041
8042 synchronized(this) {
8043 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8044 + APP_SWITCH_DELAY_TIME;
8045 mDidAppSwitch = false;
8046 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8047 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8048 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8049 }
8050 }
8051
8052 public void resumeAppSwitches() {
8053 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8054 != PackageManager.PERMISSION_GRANTED) {
8055 throw new SecurityException("Requires permission "
8056 + android.Manifest.permission.STOP_APP_SWITCHES);
8057 }
8058
8059 synchronized(this) {
8060 // Note that we don't execute any pending app switches... we will
8061 // let those wait until either the timeout, or the next start
8062 // activity request.
8063 mAppSwitchesAllowedTime = 0;
8064 }
8065 }
8066
8067 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8068 String name) {
8069 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8070 return true;
8071 }
8072
8073 final int perm = checkComponentPermission(
8074 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8075 callingUid, -1);
8076 if (perm == PackageManager.PERMISSION_GRANTED) {
8077 return true;
8078 }
8079
8080 Log.w(TAG, name + " request from " + callingUid + " stopped");
8081 return false;
8082 }
8083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008084 public void setDebugApp(String packageName, boolean waitForDebugger,
8085 boolean persistent) {
8086 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8087 "setDebugApp()");
8088
8089 // Note that this is not really thread safe if there are multiple
8090 // callers into it at the same time, but that's not a situation we
8091 // care about.
8092 if (persistent) {
8093 final ContentResolver resolver = mContext.getContentResolver();
8094 Settings.System.putString(
8095 resolver, Settings.System.DEBUG_APP,
8096 packageName);
8097 Settings.System.putInt(
8098 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8099 waitForDebugger ? 1 : 0);
8100 }
8101
8102 synchronized (this) {
8103 if (!persistent) {
8104 mOrigDebugApp = mDebugApp;
8105 mOrigWaitForDebugger = mWaitForDebugger;
8106 }
8107 mDebugApp = packageName;
8108 mWaitForDebugger = waitForDebugger;
8109 mDebugTransient = !persistent;
8110 if (packageName != null) {
8111 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08008112 forceStopPackageLocked(packageName, -1, false, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008113 Binder.restoreCallingIdentity(origId);
8114 }
8115 }
8116 }
8117
8118 public void setAlwaysFinish(boolean enabled) {
8119 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8120 "setAlwaysFinish()");
8121
8122 Settings.System.putInt(
8123 mContext.getContentResolver(),
8124 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8125
8126 synchronized (this) {
8127 mAlwaysFinishActivities = enabled;
8128 }
8129 }
8130
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008131 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008132 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008133 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008134 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008135 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008136 }
8137 }
8138
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08008139 public boolean isUserAMonkey() {
8140 // For now the fact that there is a controller implies
8141 // we have a monkey.
8142 synchronized (this) {
8143 return mController != null;
8144 }
8145 }
8146
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008147 public void registerActivityWatcher(IActivityWatcher watcher) {
8148 mWatchers.register(watcher);
8149 }
8150
8151 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8152 mWatchers.unregister(watcher);
8153 }
8154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008155 public final void enterSafeMode() {
8156 synchronized(this) {
8157 // It only makes sense to do this before the system is ready
8158 // and started launching other packages.
8159 if (!mSystemReady) {
8160 try {
8161 ActivityThread.getPackageManager().enterSafeMode();
8162 } catch (RemoteException e) {
8163 }
8164
8165 View v = LayoutInflater.from(mContext).inflate(
8166 com.android.internal.R.layout.safe_mode, null);
8167 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8168 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8169 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8170 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8171 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8172 lp.format = v.getBackground().getOpacity();
8173 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8174 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8175 ((WindowManager)mContext.getSystemService(
8176 Context.WINDOW_SERVICE)).addView(v, lp);
8177 }
8178 }
8179 }
8180
8181 public void noteWakeupAlarm(IIntentSender sender) {
8182 if (!(sender instanceof PendingIntentRecord)) {
8183 return;
8184 }
8185 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8186 synchronized (stats) {
8187 if (mBatteryStatsService.isOnBattery()) {
8188 mBatteryStatsService.enforceCallingPermission();
8189 PendingIntentRecord rec = (PendingIntentRecord)sender;
8190 int MY_UID = Binder.getCallingUid();
8191 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8192 BatteryStatsImpl.Uid.Pkg pkg =
8193 stats.getPackageStatsLocked(uid, rec.key.packageName);
8194 pkg.incWakeupsLocked();
8195 }
8196 }
8197 }
8198
8199 public boolean killPidsForMemory(int[] pids) {
8200 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8201 throw new SecurityException("killPidsForMemory only available to the system");
8202 }
8203
8204 // XXX Note: don't acquire main activity lock here, because the window
8205 // manager calls in with its locks held.
8206
8207 boolean killed = false;
8208 synchronized (mPidsSelfLocked) {
8209 int[] types = new int[pids.length];
8210 int worstType = 0;
8211 for (int i=0; i<pids.length; i++) {
8212 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8213 if (proc != null) {
8214 int type = proc.setAdj;
8215 types[i] = type;
8216 if (type > worstType) {
8217 worstType = type;
8218 }
8219 }
8220 }
8221
8222 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8223 // then constrain it so we will kill all hidden procs.
8224 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8225 worstType = HIDDEN_APP_MIN_ADJ;
8226 }
8227 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8228 for (int i=0; i<pids.length; i++) {
8229 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8230 if (proc == null) {
8231 continue;
8232 }
8233 int adj = proc.setAdj;
8234 if (adj >= worstType) {
8235 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8236 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008237 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008238 proc.processName, adj);
8239 killed = true;
8240 Process.killProcess(pids[i]);
8241 }
8242 }
8243 }
8244 return killed;
8245 }
8246
8247 public void reportPss(IApplicationThread caller, int pss) {
8248 Watchdog.PssRequestor req;
8249 String name;
8250 ProcessRecord callerApp;
8251 synchronized (this) {
8252 if (caller == null) {
8253 return;
8254 }
8255 callerApp = getRecordForAppLocked(caller);
8256 if (callerApp == null) {
8257 return;
8258 }
8259 callerApp.lastPss = pss;
8260 req = callerApp;
8261 name = callerApp.processName;
8262 }
8263 Watchdog.getInstance().reportPss(req, name, pss);
8264 if (!callerApp.persistent) {
8265 removeRequestedPss(callerApp);
8266 }
8267 }
8268
8269 public void requestPss(Runnable completeCallback) {
8270 ArrayList<ProcessRecord> procs;
8271 synchronized (this) {
8272 mRequestPssCallback = completeCallback;
8273 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008274 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8275 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008276 if (!proc.persistent) {
8277 mRequestPssList.add(proc);
8278 }
8279 }
8280 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8281 }
8282
8283 int oldPri = Process.getThreadPriority(Process.myTid());
8284 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8285 for (int i=procs.size()-1; i>=0; i--) {
8286 ProcessRecord proc = procs.get(i);
8287 proc.lastPss = 0;
8288 proc.requestPss();
8289 }
8290 Process.setThreadPriority(oldPri);
8291 }
8292
8293 void removeRequestedPss(ProcessRecord proc) {
8294 Runnable callback = null;
8295 synchronized (this) {
8296 if (mRequestPssList.remove(proc)) {
8297 if (mRequestPssList.size() == 0) {
8298 callback = mRequestPssCallback;
8299 mRequestPssCallback = null;
8300 }
8301 }
8302 }
8303
8304 if (callback != null) {
8305 callback.run();
8306 }
8307 }
8308
8309 public void collectPss(Watchdog.PssStats stats) {
8310 stats.mEmptyPss = 0;
8311 stats.mEmptyCount = 0;
8312 stats.mBackgroundPss = 0;
8313 stats.mBackgroundCount = 0;
8314 stats.mServicePss = 0;
8315 stats.mServiceCount = 0;
8316 stats.mVisiblePss = 0;
8317 stats.mVisibleCount = 0;
8318 stats.mForegroundPss = 0;
8319 stats.mForegroundCount = 0;
8320 stats.mNoPssCount = 0;
8321 synchronized (this) {
8322 int i;
8323 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8324 ? mProcDeaths.length : stats.mProcDeaths.length;
8325 int aggr = 0;
8326 for (i=0; i<NPD; i++) {
8327 aggr += mProcDeaths[i];
8328 stats.mProcDeaths[i] = aggr;
8329 }
8330 while (i<stats.mProcDeaths.length) {
8331 stats.mProcDeaths[i] = 0;
8332 i++;
8333 }
8334
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008335 for (i=mLruProcesses.size()-1; i>=0; i--) {
8336 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008337 if (proc.persistent) {
8338 continue;
8339 }
8340 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8341 if (proc.lastPss == 0) {
8342 stats.mNoPssCount++;
8343 continue;
8344 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008345 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8346 if (proc.empty) {
8347 stats.mEmptyPss += proc.lastPss;
8348 stats.mEmptyCount++;
8349 } else {
8350 stats.mBackgroundPss += proc.lastPss;
8351 stats.mBackgroundCount++;
8352 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008353 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8354 stats.mVisiblePss += proc.lastPss;
8355 stats.mVisibleCount++;
8356 } else {
8357 stats.mForegroundPss += proc.lastPss;
8358 stats.mForegroundCount++;
8359 }
8360 }
8361 }
8362 }
8363
8364 public final void startRunning(String pkg, String cls, String action,
8365 String data) {
8366 synchronized(this) {
8367 if (mStartRunning) {
8368 return;
8369 }
8370 mStartRunning = true;
8371 mTopComponent = pkg != null && cls != null
8372 ? new ComponentName(pkg, cls) : null;
8373 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8374 mTopData = data;
8375 if (!mSystemReady) {
8376 return;
8377 }
8378 }
8379
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008380 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008381 }
8382
8383 private void retrieveSettings() {
8384 final ContentResolver resolver = mContext.getContentResolver();
8385 String debugApp = Settings.System.getString(
8386 resolver, Settings.System.DEBUG_APP);
8387 boolean waitForDebugger = Settings.System.getInt(
8388 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8389 boolean alwaysFinishActivities = Settings.System.getInt(
8390 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8391
8392 Configuration configuration = new Configuration();
8393 Settings.System.getConfiguration(resolver, configuration);
8394
8395 synchronized (this) {
8396 mDebugApp = mOrigDebugApp = debugApp;
8397 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8398 mAlwaysFinishActivities = alwaysFinishActivities;
8399 // This happens before any activities are started, so we can
8400 // change mConfiguration in-place.
8401 mConfiguration.updateFrom(configuration);
Dianne Hackborne36d6e22010-02-17 19:46:25 -08008402 mConfigurationSeq = mConfiguration.seq = 1;
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008403 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008404 }
8405 }
8406
8407 public boolean testIsSystemReady() {
8408 // no need to synchronize(this) just to read & return the value
8409 return mSystemReady;
8410 }
8411
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008412 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008413 // In the simulator, startRunning will never have been called, which
8414 // normally sets a few crucial variables. Do it here instead.
8415 if (!Process.supportsProcesses()) {
8416 mStartRunning = true;
8417 mTopAction = Intent.ACTION_MAIN;
8418 }
8419
8420 synchronized(this) {
8421 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008422 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008423 return;
8424 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008425
8426 // Check to see if there are any update receivers to run.
8427 if (!mDidUpdate) {
8428 if (mWaitingUpdate) {
8429 return;
8430 }
8431 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8432 List<ResolveInfo> ris = null;
8433 try {
8434 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8435 intent, null, 0);
8436 } catch (RemoteException e) {
8437 }
8438 if (ris != null) {
8439 for (int i=ris.size()-1; i>=0; i--) {
8440 if ((ris.get(i).activityInfo.applicationInfo.flags
8441 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8442 ris.remove(i);
8443 }
8444 }
8445 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8446 for (int i=0; i<ris.size(); i++) {
8447 ActivityInfo ai = ris.get(i).activityInfo;
8448 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8449 IIntentReceiver finisher = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -08008450 if (i == ris.size()-1) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008451 finisher = new IIntentReceiver.Stub() {
8452 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008453 String data, Bundle extras, boolean ordered,
8454 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008455 throws RemoteException {
8456 synchronized (ActivityManagerService.this) {
8457 mDidUpdate = true;
8458 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008459 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008460 }
8461 };
8462 }
8463 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8464 broadcastIntentLocked(null, null, intent, null, finisher,
8465 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornd6847842010-01-12 18:14:19 -08008466 if (finisher != null) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008467 mWaitingUpdate = true;
8468 }
8469 }
8470 }
8471 if (mWaitingUpdate) {
8472 return;
8473 }
8474 mDidUpdate = true;
8475 }
8476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008477 mSystemReady = true;
8478 if (!mStartRunning) {
8479 return;
8480 }
8481 }
8482
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008483 ArrayList<ProcessRecord> procsToKill = null;
8484 synchronized(mPidsSelfLocked) {
8485 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8486 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8487 if (!isAllowedWhileBooting(proc.info)){
8488 if (procsToKill == null) {
8489 procsToKill = new ArrayList<ProcessRecord>();
8490 }
8491 procsToKill.add(proc);
8492 }
8493 }
8494 }
8495
8496 if (procsToKill != null) {
8497 synchronized(this) {
8498 for (int i=procsToKill.size()-1; i>=0; i--) {
8499 ProcessRecord proc = procsToKill.get(i);
8500 Log.i(TAG, "Removing system update proc: " + proc);
8501 removeProcessLocked(proc, true);
8502 }
8503 }
8504 }
8505
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008506 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008507 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008508 SystemClock.uptimeMillis());
8509
8510 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008511 // Make sure we have no pre-ready processes sitting around.
8512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008513 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8514 ResolveInfo ri = mContext.getPackageManager()
8515 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008516 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008517 CharSequence errorMsg = null;
8518 if (ri != null) {
8519 ActivityInfo ai = ri.activityInfo;
8520 ApplicationInfo app = ai.applicationInfo;
8521 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8522 mTopAction = Intent.ACTION_FACTORY_TEST;
8523 mTopData = null;
8524 mTopComponent = new ComponentName(app.packageName,
8525 ai.name);
8526 } else {
8527 errorMsg = mContext.getResources().getText(
8528 com.android.internal.R.string.factorytest_not_system);
8529 }
8530 } else {
8531 errorMsg = mContext.getResources().getText(
8532 com.android.internal.R.string.factorytest_no_action);
8533 }
8534 if (errorMsg != null) {
8535 mTopAction = null;
8536 mTopData = null;
8537 mTopComponent = null;
8538 Message msg = Message.obtain();
8539 msg.what = SHOW_FACTORY_ERROR_MSG;
8540 msg.getData().putCharSequence("msg", errorMsg);
8541 mHandler.sendMessage(msg);
8542 }
8543 }
8544 }
8545
8546 retrieveSettings();
8547
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008548 if (goingCallback != null) goingCallback.run();
8549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008550 synchronized (this) {
8551 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8552 try {
8553 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008554 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008555 if (apps != null) {
8556 int N = apps.size();
8557 int i;
8558 for (i=0; i<N; i++) {
8559 ApplicationInfo info
8560 = (ApplicationInfo)apps.get(i);
8561 if (info != null &&
8562 !info.packageName.equals("android")) {
8563 addAppLocked(info);
8564 }
8565 }
8566 }
8567 } catch (RemoteException ex) {
8568 // pm is in same process, this will never happen.
8569 }
8570 }
8571
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008572 // Start up initial activity.
8573 mBooting = true;
8574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008575 try {
8576 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8577 Message msg = Message.obtain();
8578 msg.what = SHOW_UID_ERROR_MSG;
8579 mHandler.sendMessage(msg);
8580 }
8581 } catch (RemoteException e) {
8582 }
8583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008584 resumeTopActivityLocked(null);
8585 }
8586 }
8587
Dan Egnorb7f03672009-12-09 16:22:32 -08008588 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008589 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008590 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008591 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008592 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008593 startAppProblemLocked(app);
8594 app.stopFreezingAllLocked();
8595 return handleAppCrashLocked(app);
8596 }
8597
Dan Egnorb7f03672009-12-09 16:22:32 -08008598 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008599 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008600 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008601 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008602 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8603 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008604 startAppProblemLocked(app);
8605 app.stopFreezingAllLocked();
8606 }
8607
8608 /**
8609 * Generate a process error record, suitable for attachment to a ProcessRecord.
8610 *
8611 * @param app The ProcessRecord in which the error occurred.
8612 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8613 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008614 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008615 * @param shortMsg Short message describing the crash.
8616 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008617 * @param stackTrace Full crash stack trace, may be null.
8618 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008619 * @return Returns a fully-formed AppErrorStateInfo record.
8620 */
8621 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008622 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008623 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008625 report.condition = condition;
8626 report.processName = app.processName;
8627 report.pid = app.pid;
8628 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008629 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008630 report.shortMsg = shortMsg;
8631 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008632 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008633
8634 return report;
8635 }
8636
Dan Egnor42471dd2010-01-07 17:25:22 -08008637 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008638 synchronized (this) {
8639 app.crashing = false;
8640 app.crashingReport = null;
8641 app.notResponding = false;
8642 app.notRespondingReport = null;
8643 if (app.anrDialog == fromDialog) {
8644 app.anrDialog = null;
8645 }
8646 if (app.waitDialog == fromDialog) {
8647 app.waitDialog = null;
8648 }
8649 if (app.pid > 0 && app.pid != MY_PID) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008650 handleAppCrashLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008651 Log.i(ActivityManagerService.TAG, "Killing process "
8652 + app.processName
8653 + " (pid=" + app.pid + ") at user's request");
8654 Process.killProcess(app.pid);
8655 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008656 }
8657 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008658
Dan Egnorb7f03672009-12-09 16:22:32 -08008659 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008660 long now = SystemClock.uptimeMillis();
8661
8662 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8663 app.info.uid);
8664 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8665 // This process loses!
8666 Log.w(TAG, "Process " + app.info.processName
8667 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008668 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008669 app.info.processName, app.info.uid);
8670 killServicesLocked(app, false);
8671 for (int i=mHistory.size()-1; i>=0; i--) {
8672 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8673 if (r.app == app) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08008674 Log.w(TAG, " Force finishing activity "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008675 + r.intent.getComponent().flattenToShortString());
8676 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8677 }
8678 }
8679 if (!app.persistent) {
8680 // We don't want to start this process again until the user
8681 // explicitly does so... but for persistent process, we really
8682 // need to keep it running. If a persistent process is actually
8683 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008684 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008685 app.info.processName);
8686 mBadProcesses.put(app.info.processName, app.info.uid, now);
8687 app.bad = true;
8688 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8689 app.removed = true;
8690 removeProcessLocked(app, false);
8691 return false;
8692 }
8693 }
8694
8695 // Bump up the crash count of any services currently running in the proc.
8696 if (app.services.size() != 0) {
8697 // Any services running in the application need to be placed
8698 // back in the pending list.
8699 Iterator it = app.services.iterator();
8700 while (it.hasNext()) {
8701 ServiceRecord sr = (ServiceRecord)it.next();
8702 sr.crashCount++;
8703 }
8704 }
8705
8706 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8707 return true;
8708 }
8709
8710 void startAppProblemLocked(ProcessRecord app) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08008711 app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
8712 mContext, app.info.packageName, app.info.flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008713 skipCurrentReceiverLocked(app);
8714 }
8715
8716 void skipCurrentReceiverLocked(ProcessRecord app) {
8717 boolean reschedule = false;
8718 BroadcastRecord r = app.curReceiver;
8719 if (r != null) {
8720 // The current broadcast is waiting for this app's receiver
8721 // to be finished. Looks like that's not going to happen, so
8722 // let the broadcast continue.
8723 logBroadcastReceiverDiscard(r);
8724 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8725 r.resultExtras, r.resultAbort, true);
8726 reschedule = true;
8727 }
8728 r = mPendingBroadcast;
8729 if (r != null && r.curApp == app) {
8730 if (DEBUG_BROADCAST) Log.v(TAG,
8731 "skip & discard pending app " + r);
8732 logBroadcastReceiverDiscard(r);
8733 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8734 r.resultExtras, r.resultAbort, true);
8735 reschedule = true;
8736 }
8737 if (reschedule) {
8738 scheduleBroadcastsLocked();
8739 }
8740 }
8741
Dan Egnor60d87622009-12-16 16:32:58 -08008742 /**
8743 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8744 * The application process will exit immediately after this call returns.
8745 * @param app object of the crashing app, null for the system server
8746 * @param crashInfo describing the exception
8747 */
8748 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8749 ProcessRecord r = findAppProcess(app);
8750
8751 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8752 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008753 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008754 crashInfo.exceptionClassName,
8755 crashInfo.exceptionMessage,
8756 crashInfo.throwFileName,
8757 crashInfo.throwLineNumber);
8758
Dan Egnor42471dd2010-01-07 17:25:22 -08008759 addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008760
8761 crashApplication(r, crashInfo);
8762 }
8763
8764 /**
8765 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8766 * @param app object of the crashing app, null for the system server
8767 * @param tag reported by the caller
8768 * @param crashInfo describing the context of the error
8769 * @return true if the process should exit immediately (WTF is fatal)
8770 */
8771 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008772 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008773 ProcessRecord r = findAppProcess(app);
8774
8775 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8776 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008777 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008778 tag, crashInfo.exceptionMessage);
8779
Dan Egnor42471dd2010-01-07 17:25:22 -08008780 addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008781
Doug Zongker43866e02010-01-07 12:09:54 -08008782 if (Settings.Secure.getInt(mContext.getContentResolver(),
8783 Settings.Secure.WTF_IS_FATAL, 0) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008784 crashApplication(r, crashInfo);
8785 return true;
8786 } else {
8787 return false;
8788 }
8789 }
8790
8791 /**
8792 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8793 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8794 */
8795 private ProcessRecord findAppProcess(IBinder app) {
8796 if (app == null) {
8797 return null;
8798 }
8799
8800 synchronized (this) {
8801 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8802 final int NA = apps.size();
8803 for (int ia=0; ia<NA; ia++) {
8804 ProcessRecord p = apps.valueAt(ia);
8805 if (p.thread != null && p.thread.asBinder() == app) {
8806 return p;
8807 }
8808 }
8809 }
8810
8811 Log.w(TAG, "Can't find mystery application: " + app);
8812 return null;
8813 }
8814 }
8815
8816 /**
Dan Egnor42471dd2010-01-07 17:25:22 -08008817 * Write a description of an error (crash, WTF, ANR) to the drop box.
Dan Egnor60d87622009-12-16 16:32:58 -08008818 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
Dan Egnor42471dd2010-01-07 17:25:22 -08008819 * @param process which caused the error, null means the system server
8820 * @param activity which triggered the error, null if unknown
8821 * @param parent activity related to the error, null if unknown
8822 * @param subject line related to the error, null if absent
8823 * @param report in long form describing the error, null if absent
8824 * @param logFile to include in the report, null if none
8825 * @param crashInfo giving an application stack trace, null if absent
Dan Egnor60d87622009-12-16 16:32:58 -08008826 */
Dan Egnor42471dd2010-01-07 17:25:22 -08008827 private void addErrorToDropBox(String eventType,
8828 ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
8829 String subject, String report, File logFile,
Dan Egnor60d87622009-12-16 16:32:58 -08008830 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008831 String dropboxTag;
8832 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008833 dropboxTag = "system_server_" + eventType;
Dan Egnor42471dd2010-01-07 17:25:22 -08008834 } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008835 dropboxTag = "system_app_" + eventType;
8836 } else {
8837 dropboxTag = "data_app_" + eventType;
8838 }
8839
8840 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8841 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8842 StringBuilder sb = new StringBuilder(1024);
Dan Egnor42471dd2010-01-07 17:25:22 -08008843 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008844 sb.append("Process: system_server\n");
8845 } else {
Dan Egnor42471dd2010-01-07 17:25:22 -08008846 sb.append("Process: ").append(process.processName).append("\n");
Dan Egnor66c40e72010-01-26 16:23:11 -08008847 }
8848 if (process != null) {
8849 int flags = process.info.flags;
8850 IPackageManager pm = ActivityThread.getPackageManager();
8851 sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
8852 for (String pkg : process.pkgList) {
8853 sb.append("Package: ").append(pkg);
8854 try {
8855 PackageInfo pi = pm.getPackageInfo(pkg, 0);
8856 if (pi != null) {
8857 sb.append(" v").append(pi.versionCode);
8858 if (pi.versionName != null) {
8859 sb.append(" (").append(pi.versionName).append(")");
8860 }
8861 }
8862 } catch (RemoteException e) {
8863 Log.e(TAG, "Error getting package info: " + pkg, e);
8864 }
8865 sb.append("\n");
8866 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008867 }
8868 if (activity != null) {
8869 sb.append("Activity: ").append(activity.shortComponentName).append("\n");
8870 }
8871 if (parent != null && parent.app != null && parent.app.pid != process.pid) {
8872 sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
8873 }
8874 if (parent != null && parent != activity) {
8875 sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
8876 }
8877 if (subject != null) {
8878 sb.append("Subject: ").append(subject).append("\n");
8879 }
8880 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8881 sb.append("\n");
8882 if (report != null) {
8883 sb.append(report);
8884 }
8885 if (logFile != null) {
8886 try {
8887 sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
8888 } catch (IOException e) {
8889 Log.e(TAG, "Error reading " + logFile, e);
Dan Egnor60d87622009-12-16 16:32:58 -08008890 }
8891 }
Dan Egnor60d87622009-12-16 16:32:58 -08008892 if (crashInfo != null && crashInfo.stackTrace != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008893 sb.append(crashInfo.stackTrace);
Dan Egnor60d87622009-12-16 16:32:58 -08008894 }
8895 dbox.addText(dropboxTag, sb.toString());
8896 }
8897 }
8898
8899 /**
8900 * Bring up the "unexpected error" dialog box for a crashing app.
8901 * Deal with edge cases (intercepts from instrumented applications,
8902 * ActivityController, error intent receivers, that sort of thing).
8903 * @param r the application crashing
8904 * @param crashInfo describing the failure
8905 */
8906 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008907 long timeMillis = System.currentTimeMillis();
8908 String shortMsg = crashInfo.exceptionClassName;
8909 String longMsg = crashInfo.exceptionMessage;
8910 String stackTrace = crashInfo.stackTrace;
8911 if (shortMsg != null && longMsg != null) {
8912 longMsg = shortMsg + ": " + longMsg;
8913 } else if (shortMsg != null) {
8914 longMsg = shortMsg;
8915 }
8916
Dan Egnor60d87622009-12-16 16:32:58 -08008917 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008918 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008919 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008920 try {
8921 String name = r != null ? r.processName : null;
8922 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008923 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008924 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008925 Log.w(TAG, "Force-killing crashed app " + name
8926 + " at watcher's request");
8927 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008928 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008929 }
8930 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008931 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008932 }
8933 }
8934
8935 final long origId = Binder.clearCallingIdentity();
8936
8937 // If this process is running instrumentation, finish it.
8938 if (r != null && r.instrumentationClass != null) {
8939 Log.w(TAG, "Error in app " + r.processName
8940 + " running instrumentation " + r.instrumentationClass + ":");
8941 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8942 if (longMsg != null) Log.w(TAG, " " + longMsg);
8943 Bundle info = new Bundle();
8944 info.putString("shortMsg", shortMsg);
8945 info.putString("longMsg", longMsg);
8946 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8947 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008948 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008949 }
8950
Dan Egnor60d87622009-12-16 16:32:58 -08008951 // If we can't identify the process or it's already exceeded its crash quota,
8952 // quit right away without showing a crash dialog.
8953 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008954 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008955 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008956 }
8957
8958 Message msg = Message.obtain();
8959 msg.what = SHOW_ERROR_MSG;
8960 HashMap data = new HashMap();
8961 data.put("result", result);
8962 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008963 msg.obj = data;
8964 mHandler.sendMessage(msg);
8965
8966 Binder.restoreCallingIdentity(origId);
8967 }
8968
8969 int res = result.get();
8970
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008971 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008972 synchronized (this) {
8973 if (r != null) {
8974 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8975 SystemClock.uptimeMillis());
8976 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008977 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008978 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008979 }
8980 }
8981
8982 if (appErrorIntent != null) {
8983 try {
8984 mContext.startActivity(appErrorIntent);
8985 } catch (ActivityNotFoundException e) {
8986 Log.w(TAG, "bug report receiver dissappeared", e);
8987 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008989 }
Dan Egnorb7f03672009-12-09 16:22:32 -08008990
8991 Intent createAppErrorIntentLocked(ProcessRecord r,
8992 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
8993 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008994 if (report == null) {
8995 return null;
8996 }
8997 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8998 result.setComponent(r.errorReportReceiver);
8999 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
9000 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
9001 return result;
9002 }
9003
Dan Egnorb7f03672009-12-09 16:22:32 -08009004 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
9005 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009006 if (r.errorReportReceiver == null) {
9007 return null;
9008 }
9009
9010 if (!r.crashing && !r.notResponding) {
9011 return null;
9012 }
9013
Dan Egnorb7f03672009-12-09 16:22:32 -08009014 ApplicationErrorReport report = new ApplicationErrorReport();
9015 report.packageName = r.info.packageName;
9016 report.installerPackageName = r.errorReportReceiver.getPackageName();
9017 report.processName = r.processName;
9018 report.time = timeMillis;
Jacek Surazskie0ee6ef2010-01-07 16:23:03 +01009019 report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009020
Dan Egnorb7f03672009-12-09 16:22:32 -08009021 if (r.crashing) {
9022 report.type = ApplicationErrorReport.TYPE_CRASH;
9023 report.crashInfo = crashInfo;
9024 } else if (r.notResponding) {
9025 report.type = ApplicationErrorReport.TYPE_ANR;
9026 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009027
Dan Egnorb7f03672009-12-09 16:22:32 -08009028 report.anrInfo.activity = r.notRespondingReport.tag;
9029 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9030 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009031 }
9032
Dan Egnorb7f03672009-12-09 16:22:32 -08009033 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009034 }
9035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009036 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9037 // assume our apps are happy - lazy create the list
9038 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9039
9040 synchronized (this) {
9041
9042 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009043 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9044 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009045 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9046 // This one's in trouble, so we'll generate a report for it
9047 // crashes are higher priority (in case there's a crash *and* an anr)
9048 ActivityManager.ProcessErrorStateInfo report = null;
9049 if (app.crashing) {
9050 report = app.crashingReport;
9051 } else if (app.notResponding) {
9052 report = app.notRespondingReport;
9053 }
9054
9055 if (report != null) {
9056 if (errList == null) {
9057 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9058 }
9059 errList.add(report);
9060 } else {
9061 Log.w(TAG, "Missing app error report, app = " + app.processName +
9062 " crashing = " + app.crashing +
9063 " notResponding = " + app.notResponding);
9064 }
9065 }
9066 }
9067 }
9068
9069 return errList;
9070 }
9071
9072 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9073 // Lazy instantiation of list
9074 List<ActivityManager.RunningAppProcessInfo> runList = null;
9075 synchronized (this) {
9076 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009077 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9078 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009079 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9080 // Generate process state info for running application
9081 ActivityManager.RunningAppProcessInfo currApp =
9082 new ActivityManager.RunningAppProcessInfo(app.processName,
9083 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009084 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009085 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009086 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009087 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9088 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9089 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009090 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9091 } else if (adj >= HOME_APP_ADJ) {
9092 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9093 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009094 } else if (adj >= SECONDARY_SERVER_ADJ) {
9095 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9096 } else if (adj >= VISIBLE_APP_ADJ) {
9097 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9098 } else {
9099 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9100 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009101 currApp.importanceReasonCode = app.adjTypeCode;
9102 if (app.adjSource instanceof ProcessRecord) {
9103 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9104 } else if (app.adjSource instanceof HistoryRecord) {
9105 HistoryRecord r = (HistoryRecord)app.adjSource;
9106 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9107 }
9108 if (app.adjTarget instanceof ComponentName) {
9109 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9110 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009111 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9112 // + " lru=" + currApp.lru);
9113 if (runList == null) {
9114 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9115 }
9116 runList.add(currApp);
9117 }
9118 }
9119 }
9120 return runList;
9121 }
9122
9123 @Override
9124 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009125 if (checkCallingPermission(android.Manifest.permission.DUMP)
9126 != PackageManager.PERMISSION_GRANTED) {
9127 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9128 + Binder.getCallingPid()
9129 + ", uid=" + Binder.getCallingUid()
9130 + " without permission "
9131 + android.Manifest.permission.DUMP);
9132 return;
9133 }
9134
9135 boolean dumpAll = false;
9136
9137 int opti = 0;
9138 while (opti < args.length) {
9139 String opt = args[opti];
9140 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9141 break;
9142 }
9143 opti++;
9144 if ("-a".equals(opt)) {
9145 dumpAll = true;
9146 } else if ("-h".equals(opt)) {
9147 pw.println("Activity manager dump options:");
9148 pw.println(" [-a] [h- [cmd] ...");
9149 pw.println(" cmd may be one of:");
9150 pw.println(" activities: activity stack state");
9151 pw.println(" broadcasts: broadcast state");
9152 pw.println(" intents: pending intent state");
9153 pw.println(" processes: process state");
9154 pw.println(" providers: content provider state");
9155 pw.println(" services: service state");
9156 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009157 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009158 } else {
9159 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009160 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009161 }
9162
9163 // Is the caller requesting to dump a particular piece of data?
9164 if (opti < args.length) {
9165 String cmd = args[opti];
9166 opti++;
9167 if ("activities".equals(cmd) || "a".equals(cmd)) {
9168 synchronized (this) {
9169 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009170 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009171 return;
9172 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9173 synchronized (this) {
9174 dumpBroadcastsLocked(fd, pw, args, opti, true);
9175 }
9176 return;
9177 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9178 synchronized (this) {
9179 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9180 }
9181 return;
9182 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9183 synchronized (this) {
9184 dumpProcessesLocked(fd, pw, args, opti, true);
9185 }
9186 return;
9187 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9188 synchronized (this) {
9189 dumpProvidersLocked(fd, pw, args, opti, true);
9190 }
9191 return;
9192 } else if ("service".equals(cmd)) {
9193 dumpService(fd, pw, args, opti, true);
9194 return;
9195 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9196 synchronized (this) {
9197 dumpServicesLocked(fd, pw, args, opti, true);
9198 }
9199 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009200 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009201 }
9202
9203 // No piece of data specified, dump everything.
9204 synchronized (this) {
9205 boolean needSep;
9206 if (dumpAll) {
9207 pw.println("Providers in Current Activity Manager State:");
9208 }
9209 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9210 if (needSep) {
9211 pw.println(" ");
9212 }
9213 if (dumpAll) {
9214 pw.println("-------------------------------------------------------------------------------");
9215 pw.println("Broadcasts in Current Activity Manager State:");
9216 }
9217 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9218 if (needSep) {
9219 pw.println(" ");
9220 }
9221 if (dumpAll) {
9222 pw.println("-------------------------------------------------------------------------------");
9223 pw.println("Services in Current Activity Manager State:");
9224 }
9225 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9226 if (needSep) {
9227 pw.println(" ");
9228 }
9229 if (dumpAll) {
9230 pw.println("-------------------------------------------------------------------------------");
9231 pw.println("PendingIntents in Current Activity Manager State:");
9232 }
9233 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9234 if (needSep) {
9235 pw.println(" ");
9236 }
9237 if (dumpAll) {
9238 pw.println("-------------------------------------------------------------------------------");
9239 pw.println("Activities in Current Activity Manager State:");
9240 }
9241 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9242 if (needSep) {
9243 pw.println(" ");
9244 }
9245 if (dumpAll) {
9246 pw.println("-------------------------------------------------------------------------------");
9247 pw.println("Processes in Current Activity Manager State:");
9248 }
9249 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9250 }
9251 }
9252
9253 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9254 int opti, boolean dumpAll, boolean needHeader) {
9255 if (needHeader) {
9256 pw.println(" Activity stack:");
9257 }
9258 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9259 pw.println(" ");
9260 pw.println(" Running activities (most recent first):");
9261 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9262 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009263 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009264 pw.println(" Activities waiting for another to become visible:");
9265 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9266 }
9267 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009268 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009269 pw.println(" Activities waiting to stop:");
9270 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9271 }
9272 if (mFinishingActivities.size() > 0) {
9273 pw.println(" ");
9274 pw.println(" Activities waiting to finish:");
9275 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009277
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009278 pw.println(" ");
9279 pw.println(" mPausingActivity: " + mPausingActivity);
9280 pw.println(" mResumedActivity: " + mResumedActivity);
9281 pw.println(" mFocusedActivity: " + mFocusedActivity);
9282 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009283
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009284 if (dumpAll && mRecentTasks.size() > 0) {
9285 pw.println(" ");
9286 pw.println("Recent tasks in Current Activity Manager State:");
9287
9288 final int N = mRecentTasks.size();
9289 for (int i=0; i<N; i++) {
9290 TaskRecord tr = mRecentTasks.get(i);
9291 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9292 pw.println(tr);
9293 mRecentTasks.get(i).dump(pw, " ");
9294 }
9295 }
9296
9297 pw.println(" ");
9298 pw.println(" mCurTask: " + mCurTask);
9299
9300 return true;
9301 }
9302
9303 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9304 int opti, boolean dumpAll) {
9305 boolean needSep = false;
9306 int numPers = 0;
9307
9308 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009309 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9310 final int NA = procs.size();
9311 for (int ia=0; ia<NA; ia++) {
9312 if (!needSep) {
9313 pw.println(" All known processes:");
9314 needSep = true;
9315 }
9316 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009317 pw.print(r.persistent ? " *PERS*" : " *APP*");
9318 pw.print(" UID "); pw.print(procs.keyAt(ia));
9319 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009320 r.dump(pw, " ");
9321 if (r.persistent) {
9322 numPers++;
9323 }
9324 }
9325 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009326 }
9327
9328 if (mLruProcesses.size() > 0) {
9329 if (needSep) pw.println(" ");
9330 needSep = true;
9331 pw.println(" Running processes (most recent first):");
9332 dumpProcessList(pw, this, mLruProcesses, " ",
9333 "App ", "PERS", true);
9334 needSep = true;
9335 }
9336
9337 synchronized (mPidsSelfLocked) {
9338 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009339 if (needSep) pw.println(" ");
9340 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009341 pw.println(" PID mappings:");
9342 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9343 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9344 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009345 }
9346 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009347 }
9348
9349 if (mForegroundProcesses.size() > 0) {
9350 if (needSep) pw.println(" ");
9351 needSep = true;
9352 pw.println(" Foreground Processes:");
9353 for (int i=0; i<mForegroundProcesses.size(); i++) {
9354 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9355 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009356 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009357 }
9358
9359 if (mPersistentStartingProcesses.size() > 0) {
9360 if (needSep) pw.println(" ");
9361 needSep = true;
9362 pw.println(" Persisent processes that are starting:");
9363 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9364 "Starting Norm", "Restarting PERS", false);
9365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009366
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009367 if (mStartingProcesses.size() > 0) {
9368 if (needSep) pw.println(" ");
9369 needSep = true;
9370 pw.println(" Processes that are starting:");
9371 dumpProcessList(pw, this, mStartingProcesses, " ",
9372 "Starting Norm", "Starting PERS", false);
9373 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009374
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009375 if (mRemovedProcesses.size() > 0) {
9376 if (needSep) pw.println(" ");
9377 needSep = true;
9378 pw.println(" Processes that are being removed:");
9379 dumpProcessList(pw, this, mRemovedProcesses, " ",
9380 "Removed Norm", "Removed PERS", false);
9381 }
9382
9383 if (mProcessesOnHold.size() > 0) {
9384 if (needSep) pw.println(" ");
9385 needSep = true;
9386 pw.println(" Processes that are on old until the system is ready:");
9387 dumpProcessList(pw, this, mProcessesOnHold, " ",
9388 "OnHold Norm", "OnHold PERS", false);
9389 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009390
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009391 if (mProcessesToGc.size() > 0) {
9392 if (needSep) pw.println(" ");
9393 needSep = true;
9394 pw.println(" Processes that are waiting to GC:");
9395 long now = SystemClock.uptimeMillis();
9396 for (int i=0; i<mProcessesToGc.size(); i++) {
9397 ProcessRecord proc = mProcessesToGc.get(i);
9398 pw.print(" Process "); pw.println(proc);
9399 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9400 pw.print(", last gced=");
9401 pw.print(now-proc.lastRequestedGc);
9402 pw.print(" ms ago, last lowMem=");
9403 pw.print(now-proc.lastLowMemory);
9404 pw.println(" ms ago");
9405
9406 }
9407 }
9408
9409 if (mProcessCrashTimes.getMap().size() > 0) {
9410 if (needSep) pw.println(" ");
9411 needSep = true;
9412 pw.println(" Time since processes crashed:");
9413 long now = SystemClock.uptimeMillis();
9414 for (Map.Entry<String, SparseArray<Long>> procs
9415 : mProcessCrashTimes.getMap().entrySet()) {
9416 SparseArray<Long> uids = procs.getValue();
9417 final int N = uids.size();
9418 for (int i=0; i<N; i++) {
9419 pw.print(" Process "); pw.print(procs.getKey());
9420 pw.print(" uid "); pw.print(uids.keyAt(i));
9421 pw.print(": last crashed ");
9422 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009423 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009424 }
9425 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009426 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009427
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009428 if (mBadProcesses.getMap().size() > 0) {
9429 if (needSep) pw.println(" ");
9430 needSep = true;
9431 pw.println(" Bad processes:");
9432 for (Map.Entry<String, SparseArray<Long>> procs
9433 : mBadProcesses.getMap().entrySet()) {
9434 SparseArray<Long> uids = procs.getValue();
9435 final int N = uids.size();
9436 for (int i=0; i<N; i++) {
9437 pw.print(" Bad process "); pw.print(procs.getKey());
9438 pw.print(" uid "); pw.print(uids.keyAt(i));
9439 pw.print(": crashed at time ");
9440 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009441 }
9442 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009444
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009445 pw.println(" ");
9446 pw.println(" mHomeProcess: " + mHomeProcess);
9447 pw.println(" mConfiguration: " + mConfiguration);
9448 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9449 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9450 || mOrigWaitForDebugger) {
9451 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9452 + " mDebugTransient=" + mDebugTransient
9453 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9454 }
9455 if (mAlwaysFinishActivities || mController != null) {
9456 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9457 + " mController=" + mController);
9458 }
9459 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009460 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009461 pw.println(" mStartRunning=" + mStartRunning
9462 + " mSystemReady=" + mSystemReady
9463 + " mBooting=" + mBooting
9464 + " mBooted=" + mBooted
9465 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009466 pw.println(" mGoingToSleep=" + mGoingToSleep);
9467 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009468 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009469
9470 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009471 }
9472
9473 /**
9474 * There are three ways to call this:
9475 * - no service specified: dump all the services
9476 * - a flattened component name that matched an existing service was specified as the
9477 * first arg: dump that one service
9478 * - the first arg isn't the flattened component name of an existing service:
9479 * dump all services whose component contains the first arg as a substring
9480 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009481 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9482 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009483 String[] newArgs;
9484 String componentNameString;
9485 ServiceRecord r;
Kenny Root3619b9ab2010-02-13 10:05:42 -08009486 if (opti >= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009487 componentNameString = null;
9488 newArgs = EMPTY_STRING_ARRAY;
9489 r = null;
9490 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009491 componentNameString = args[opti];
9492 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009493 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9494 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009495 newArgs = new String[args.length - opti];
9496 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009497 }
9498
9499 if (r != null) {
9500 dumpService(fd, pw, r, newArgs);
9501 } else {
9502 for (ServiceRecord r1 : mServices.values()) {
9503 if (componentNameString == null
9504 || r1.name.flattenToString().contains(componentNameString)) {
9505 dumpService(fd, pw, r1, newArgs);
9506 }
9507 }
9508 }
9509 }
9510
9511 /**
9512 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9513 * there is a thread associated with the service.
9514 */
9515 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9516 pw.println(" Service " + r.name.flattenToString());
9517 if (r.app != null && r.app.thread != null) {
9518 try {
9519 // flush anything that is already in the PrintWriter since the thread is going
9520 // to write to the file descriptor directly
9521 pw.flush();
9522 r.app.thread.dumpService(fd, r, args);
9523 pw.print("\n");
9524 } catch (RemoteException e) {
9525 pw.println("got a RemoteException while dumping the service");
9526 }
9527 }
9528 }
9529
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009530 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9531 int opti, boolean dumpAll) {
9532 boolean needSep = false;
9533
9534 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009535 if (mRegisteredReceivers.size() > 0) {
9536 pw.println(" ");
9537 pw.println(" Registered Receivers:");
9538 Iterator it = mRegisteredReceivers.values().iterator();
9539 while (it.hasNext()) {
9540 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009541 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009542 r.dump(pw, " ");
9543 }
9544 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009546 pw.println(" ");
9547 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009548 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009549 needSep = true;
9550 }
9551
9552 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9553 || mPendingBroadcast != null) {
9554 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009555 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009556 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009557 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009558 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9559 pw.println(" Broadcast #" + i + ":");
9560 mParallelBroadcasts.get(i).dump(pw, " ");
9561 }
9562 if (mOrderedBroadcasts.size() > 0) {
9563 pw.println(" ");
9564 pw.println(" Active serialized broadcasts:");
9565 }
9566 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9567 pw.println(" Serialized Broadcast #" + i + ":");
9568 mOrderedBroadcasts.get(i).dump(pw, " ");
9569 }
9570 pw.println(" ");
9571 pw.println(" Pending broadcast:");
9572 if (mPendingBroadcast != null) {
9573 mPendingBroadcast.dump(pw, " ");
9574 } else {
9575 pw.println(" (null)");
9576 }
9577 needSep = true;
9578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009579
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009580 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009581 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009582 pw.println(" Historical broadcasts:");
9583 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9584 BroadcastRecord r = mBroadcastHistory[i];
9585 if (r == null) {
9586 break;
9587 }
9588 pw.println(" Historical Broadcast #" + i + ":");
9589 r.dump(pw, " ");
9590 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009591 needSep = true;
9592 }
9593
9594 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009595 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009596 pw.println(" Sticky broadcasts:");
9597 StringBuilder sb = new StringBuilder(128);
9598 for (Map.Entry<String, ArrayList<Intent>> ent
9599 : mStickyBroadcasts.entrySet()) {
9600 pw.print(" * Sticky action "); pw.print(ent.getKey());
9601 pw.println(":");
9602 ArrayList<Intent> intents = ent.getValue();
9603 final int N = intents.size();
9604 for (int i=0; i<N; i++) {
9605 sb.setLength(0);
9606 sb.append(" Intent: ");
9607 intents.get(i).toShortString(sb, true, false);
9608 pw.println(sb.toString());
9609 Bundle bundle = intents.get(i).getExtras();
9610 if (bundle != null) {
9611 pw.print(" ");
9612 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009613 }
9614 }
9615 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009616 needSep = true;
9617 }
9618
9619 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009620 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009621 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009622 pw.println(" mHandler:");
9623 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009624 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009625 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009626
9627 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009628 }
9629
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009630 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9631 int opti, boolean dumpAll) {
9632 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009633
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009634 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009635 if (mServices.size() > 0) {
9636 pw.println(" Active services:");
9637 Iterator<ServiceRecord> it = mServices.values().iterator();
9638 while (it.hasNext()) {
9639 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009640 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009641 r.dump(pw, " ");
9642 }
9643 needSep = true;
9644 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009646
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009647 if (mPendingServices.size() > 0) {
9648 if (needSep) pw.println(" ");
9649 pw.println(" Pending services:");
9650 for (int i=0; i<mPendingServices.size(); i++) {
9651 ServiceRecord r = mPendingServices.get(i);
9652 pw.print(" * Pending "); pw.println(r);
9653 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009654 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009655 needSep = true;
9656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009657
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009658 if (mRestartingServices.size() > 0) {
9659 if (needSep) pw.println(" ");
9660 pw.println(" Restarting services:");
9661 for (int i=0; i<mRestartingServices.size(); i++) {
9662 ServiceRecord r = mRestartingServices.get(i);
9663 pw.print(" * Restarting "); pw.println(r);
9664 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009665 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009666 needSep = true;
9667 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009668
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009669 if (mStoppingServices.size() > 0) {
9670 if (needSep) pw.println(" ");
9671 pw.println(" Stopping services:");
9672 for (int i=0; i<mStoppingServices.size(); i++) {
9673 ServiceRecord r = mStoppingServices.get(i);
9674 pw.print(" * Stopping "); pw.println(r);
9675 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009676 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009677 needSep = true;
9678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009679
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009680 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009681 if (mServiceConnections.size() > 0) {
9682 if (needSep) pw.println(" ");
9683 pw.println(" Connection bindings to services:");
9684 Iterator<ConnectionRecord> it
9685 = mServiceConnections.values().iterator();
9686 while (it.hasNext()) {
9687 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009688 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009689 r.dump(pw, " ");
9690 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009691 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009692 }
9693 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009694
9695 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009696 }
9697
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009698 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9699 int opti, boolean dumpAll) {
9700 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009701
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009702 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009703 if (mProvidersByClass.size() > 0) {
9704 if (needSep) pw.println(" ");
9705 pw.println(" Published content providers (by class):");
9706 Iterator it = mProvidersByClass.entrySet().iterator();
9707 while (it.hasNext()) {
9708 Map.Entry e = (Map.Entry)it.next();
9709 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009710 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009711 r.dump(pw, " ");
9712 }
9713 needSep = true;
9714 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009715
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009716 if (mProvidersByName.size() > 0) {
9717 pw.println(" ");
9718 pw.println(" Authority to provider mappings:");
9719 Iterator it = mProvidersByName.entrySet().iterator();
9720 while (it.hasNext()) {
9721 Map.Entry e = (Map.Entry)it.next();
9722 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9723 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9724 pw.println(r);
9725 }
9726 needSep = true;
9727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009728 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009729
9730 if (mLaunchingProviders.size() > 0) {
9731 if (needSep) pw.println(" ");
9732 pw.println(" Launching content providers:");
9733 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9734 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9735 pw.println(mLaunchingProviders.get(i));
9736 }
9737 needSep = true;
9738 }
9739
9740 if (mGrantedUriPermissions.size() > 0) {
9741 pw.println();
9742 pw.println("Granted Uri Permissions:");
9743 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9744 int uid = mGrantedUriPermissions.keyAt(i);
9745 HashMap<Uri, UriPermission> perms
9746 = mGrantedUriPermissions.valueAt(i);
9747 pw.print(" * UID "); pw.print(uid);
9748 pw.println(" holds:");
9749 for (UriPermission perm : perms.values()) {
9750 pw.print(" "); pw.println(perm);
9751 perm.dump(pw, " ");
9752 }
9753 }
9754 needSep = true;
9755 }
9756
9757 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009758 }
9759
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009760 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9761 int opti, boolean dumpAll) {
9762 boolean needSep = false;
9763
9764 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009765 if (this.mIntentSenderRecords.size() > 0) {
9766 Iterator<WeakReference<PendingIntentRecord>> it
9767 = mIntentSenderRecords.values().iterator();
9768 while (it.hasNext()) {
9769 WeakReference<PendingIntentRecord> ref = it.next();
9770 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009771 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009772 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009773 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009774 rec.dump(pw, " ");
9775 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009776 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009777 }
9778 }
9779 }
9780 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009781
9782 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009783 }
9784
9785 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009786 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009787 TaskRecord lastTask = null;
9788 for (int i=list.size()-1; i>=0; i--) {
9789 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009790 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009791 if (lastTask != r.task) {
9792 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009793 pw.print(prefix);
9794 pw.print(full ? "* " : " ");
9795 pw.println(lastTask);
9796 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009797 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009798 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009799 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009800 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9801 pw.print(" #"); pw.print(i); pw.print(": ");
9802 pw.println(r);
9803 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009804 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009805 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009806 }
9807 }
9808
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009809 private static String buildOomTag(String prefix, String space, int val, int base) {
9810 if (val == base) {
9811 if (space == null) return prefix;
9812 return prefix + " ";
9813 }
9814 return prefix + "+" + Integer.toString(val-base);
9815 }
9816
9817 private static final int dumpProcessList(PrintWriter pw,
9818 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009819 String prefix, String normalLabel, String persistentLabel,
9820 boolean inclOomAdj) {
9821 int numPers = 0;
9822 for (int i=list.size()-1; i>=0; i--) {
9823 ProcessRecord r = (ProcessRecord)list.get(i);
9824 if (false) {
9825 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9826 + " #" + i + ":");
9827 r.dump(pw, prefix + " ");
9828 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009829 String oomAdj;
9830 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009831 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009832 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009833 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9834 } else if (r.setAdj >= HOME_APP_ADJ) {
9835 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9836 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9837 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9838 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9839 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9840 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9841 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9842 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9843 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009844 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009845 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009846 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009847 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009848 } else {
9849 oomAdj = Integer.toString(r.setAdj);
9850 }
9851 String schedGroup;
9852 switch (r.setSchedGroup) {
9853 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9854 schedGroup = "B";
9855 break;
9856 case Process.THREAD_GROUP_DEFAULT:
9857 schedGroup = "F";
9858 break;
9859 default:
9860 schedGroup = Integer.toString(r.setSchedGroup);
9861 break;
9862 }
9863 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009864 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009865 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009866 if (r.adjSource != null || r.adjTarget != null) {
9867 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009868 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009869 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009870 } else {
9871 pw.println(String.format("%s%s #%2d: %s",
9872 prefix, (r.persistent ? persistentLabel : normalLabel),
9873 i, r.toString()));
9874 }
9875 if (r.persistent) {
9876 numPers++;
9877 }
9878 }
9879 return numPers;
9880 }
9881
9882 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9883 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009884 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009885 long uptime = SystemClock.uptimeMillis();
9886 long realtime = SystemClock.elapsedRealtime();
9887
9888 if (isCheckinRequest) {
9889 // short checkin version
9890 pw.println(uptime + "," + realtime);
9891 pw.flush();
9892 } else {
9893 pw.println("Applications Memory Usage (kB):");
9894 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9895 }
9896 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9897 ProcessRecord r = (ProcessRecord)list.get(i);
9898 if (r.thread != null) {
9899 if (!isCheckinRequest) {
9900 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9901 pw.flush();
9902 }
9903 try {
9904 r.thread.asBinder().dump(fd, args);
9905 } catch (RemoteException e) {
9906 if (!isCheckinRequest) {
9907 pw.println("Got RemoteException!");
9908 pw.flush();
9909 }
9910 }
9911 }
9912 }
9913 }
9914
9915 /**
9916 * Searches array of arguments for the specified string
9917 * @param args array of argument strings
9918 * @param value value to search for
9919 * @return true if the value is contained in the array
9920 */
9921 private static boolean scanArgs(String[] args, String value) {
9922 if (args != null) {
9923 for (String arg : args) {
9924 if (value.equals(arg)) {
9925 return true;
9926 }
9927 }
9928 }
9929 return false;
9930 }
9931
Dianne Hackborn75b03852009-06-12 15:43:26 -07009932 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009933 int count = mHistory.size();
9934
9935 // convert the token to an entry in the history.
9936 HistoryRecord r = null;
9937 int index = -1;
9938 for (int i=count-1; i>=0; i--) {
9939 Object o = mHistory.get(i);
9940 if (o == token) {
9941 r = (HistoryRecord)o;
9942 index = i;
9943 break;
9944 }
9945 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009946
9947 return index;
9948 }
9949
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009950 private final void killServicesLocked(ProcessRecord app,
9951 boolean allowRestart) {
9952 // Report disconnected services.
9953 if (false) {
9954 // XXX we are letting the client link to the service for
9955 // death notifications.
9956 if (app.services.size() > 0) {
9957 Iterator it = app.services.iterator();
9958 while (it.hasNext()) {
9959 ServiceRecord r = (ServiceRecord)it.next();
9960 if (r.connections.size() > 0) {
9961 Iterator<ConnectionRecord> jt
9962 = r.connections.values().iterator();
9963 while (jt.hasNext()) {
9964 ConnectionRecord c = jt.next();
9965 if (c.binding.client != app) {
9966 try {
9967 //c.conn.connected(r.className, null);
9968 } catch (Exception e) {
9969 // todo: this should be asynchronous!
9970 Log.w(TAG, "Exception thrown disconnected servce "
9971 + r.shortName
9972 + " from app " + app.processName, e);
9973 }
9974 }
9975 }
9976 }
9977 }
9978 }
9979 }
9980
9981 // Clean up any connections this application has to other services.
9982 if (app.connections.size() > 0) {
9983 Iterator<ConnectionRecord> it = app.connections.iterator();
9984 while (it.hasNext()) {
9985 ConnectionRecord r = it.next();
9986 removeConnectionLocked(r, app, null);
9987 }
9988 }
9989 app.connections.clear();
9990
9991 if (app.services.size() != 0) {
9992 // Any services running in the application need to be placed
9993 // back in the pending list.
9994 Iterator it = app.services.iterator();
9995 while (it.hasNext()) {
9996 ServiceRecord sr = (ServiceRecord)it.next();
9997 synchronized (sr.stats.getBatteryStats()) {
9998 sr.stats.stopLaunchedLocked();
9999 }
10000 sr.app = null;
10001 sr.executeNesting = 0;
10002 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010003
10004 boolean hasClients = sr.bindings.size() > 0;
10005 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010006 Iterator<IntentBindRecord> bindings
10007 = sr.bindings.values().iterator();
10008 while (bindings.hasNext()) {
10009 IntentBindRecord b = bindings.next();
10010 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
10011 + ": shouldUnbind=" + b.hasBound);
10012 b.binder = null;
10013 b.requested = b.received = b.hasBound = false;
10014 }
10015 }
10016
10017 if (sr.crashCount >= 2) {
10018 Log.w(TAG, "Service crashed " + sr.crashCount
10019 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010020 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010021 sr.crashCount, sr.shortName, app.pid);
10022 bringDownServiceLocked(sr, true);
10023 } else if (!allowRestart) {
10024 bringDownServiceLocked(sr, true);
10025 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010026 boolean canceled = scheduleServiceRestartLocked(sr, true);
10027
10028 // Should the service remain running? Note that in the
10029 // extreme case of so many attempts to deliver a command
10030 // that it failed, that we also will stop it here.
10031 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10032 if (sr.pendingStarts.size() == 0) {
10033 sr.startRequested = false;
10034 if (!hasClients) {
10035 // Whoops, no reason to restart!
10036 bringDownServiceLocked(sr, true);
10037 }
10038 }
10039 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010040 }
10041 }
10042
10043 if (!allowRestart) {
10044 app.services.clear();
10045 }
10046 }
10047
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010048 // Make sure we have no more records on the stopping list.
10049 int i = mStoppingServices.size();
10050 while (i > 0) {
10051 i--;
10052 ServiceRecord sr = mStoppingServices.get(i);
10053 if (sr.app == app) {
10054 mStoppingServices.remove(i);
10055 }
10056 }
10057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010058 app.executingServices.clear();
10059 }
10060
10061 private final void removeDyingProviderLocked(ProcessRecord proc,
10062 ContentProviderRecord cpr) {
10063 synchronized (cpr) {
10064 cpr.launchingApp = null;
10065 cpr.notifyAll();
10066 }
10067
10068 mProvidersByClass.remove(cpr.info.name);
10069 String names[] = cpr.info.authority.split(";");
10070 for (int j = 0; j < names.length; j++) {
10071 mProvidersByName.remove(names[j]);
10072 }
10073
10074 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10075 while (cit.hasNext()) {
10076 ProcessRecord capp = cit.next();
10077 if (!capp.persistent && capp.thread != null
10078 && capp.pid != 0
10079 && capp.pid != MY_PID) {
10080 Log.i(TAG, "Killing app " + capp.processName
10081 + " (pid " + capp.pid
10082 + ") because provider " + cpr.info.name
10083 + " is in dying process " + proc.processName);
10084 Process.killProcess(capp.pid);
10085 }
10086 }
10087
10088 mLaunchingProviders.remove(cpr);
10089 }
10090
10091 /**
10092 * Main code for cleaning up a process when it has gone away. This is
10093 * called both as a result of the process dying, or directly when stopping
10094 * a process when running in single process mode.
10095 */
10096 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10097 boolean restarting, int index) {
10098 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010099 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010100 }
10101
Dianne Hackborn36124872009-10-08 16:22:03 -070010102 mProcessesToGc.remove(app);
10103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010104 // Dismiss any open dialogs.
10105 if (app.crashDialog != null) {
10106 app.crashDialog.dismiss();
10107 app.crashDialog = null;
10108 }
10109 if (app.anrDialog != null) {
10110 app.anrDialog.dismiss();
10111 app.anrDialog = null;
10112 }
10113 if (app.waitDialog != null) {
10114 app.waitDialog.dismiss();
10115 app.waitDialog = null;
10116 }
10117
10118 app.crashing = false;
10119 app.notResponding = false;
10120
10121 app.resetPackageList();
10122 app.thread = null;
10123 app.forcingToForeground = null;
10124 app.foregroundServices = false;
10125
10126 killServicesLocked(app, true);
10127
10128 boolean restart = false;
10129
10130 int NL = mLaunchingProviders.size();
10131
10132 // Remove published content providers.
10133 if (!app.pubProviders.isEmpty()) {
10134 Iterator it = app.pubProviders.values().iterator();
10135 while (it.hasNext()) {
10136 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10137 cpr.provider = null;
10138 cpr.app = null;
10139
10140 // See if someone is waiting for this provider... in which
10141 // case we don't remove it, but just let it restart.
10142 int i = 0;
10143 if (!app.bad) {
10144 for (; i<NL; i++) {
10145 if (mLaunchingProviders.get(i) == cpr) {
10146 restart = true;
10147 break;
10148 }
10149 }
10150 } else {
10151 i = NL;
10152 }
10153
10154 if (i >= NL) {
10155 removeDyingProviderLocked(app, cpr);
10156 NL = mLaunchingProviders.size();
10157 }
10158 }
10159 app.pubProviders.clear();
10160 }
10161
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010162 // Take care of any launching providers waiting for this process.
10163 if (checkAppInLaunchingProvidersLocked(app, false)) {
10164 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010165 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010167 // Unregister from connected content providers.
10168 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010169 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010170 while (it.hasNext()) {
10171 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10172 cpr.clients.remove(app);
10173 }
10174 app.conProviders.clear();
10175 }
10176
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010177 // At this point there may be remaining entries in mLaunchingProviders
10178 // where we were the only one waiting, so they are no longer of use.
10179 // Look for these and clean up if found.
10180 // XXX Commented out for now. Trying to figure out a way to reproduce
10181 // the actual situation to identify what is actually going on.
10182 if (false) {
10183 for (int i=0; i<NL; i++) {
10184 ContentProviderRecord cpr = (ContentProviderRecord)
10185 mLaunchingProviders.get(i);
10186 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10187 synchronized (cpr) {
10188 cpr.launchingApp = null;
10189 cpr.notifyAll();
10190 }
10191 }
10192 }
10193 }
10194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010195 skipCurrentReceiverLocked(app);
10196
10197 // Unregister any receivers.
10198 if (app.receivers.size() > 0) {
10199 Iterator<ReceiverList> it = app.receivers.iterator();
10200 while (it.hasNext()) {
10201 removeReceiverLocked(it.next());
10202 }
10203 app.receivers.clear();
10204 }
10205
Christopher Tate181fafa2009-05-14 11:12:14 -070010206 // If the app is undergoing backup, tell the backup manager about it
10207 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10208 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10209 try {
10210 IBackupManager bm = IBackupManager.Stub.asInterface(
10211 ServiceManager.getService(Context.BACKUP_SERVICE));
10212 bm.agentDisconnected(app.info.packageName);
10213 } catch (RemoteException e) {
10214 // can't happen; backup manager is local
10215 }
10216 }
10217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010218 // If the caller is restarting this app, then leave it in its
10219 // current lists and let the caller take care of it.
10220 if (restarting) {
10221 return;
10222 }
10223
10224 if (!app.persistent) {
10225 if (DEBUG_PROCESSES) Log.v(TAG,
10226 "Removing non-persistent process during cleanup: " + app);
10227 mProcessNames.remove(app.processName, app.info.uid);
10228 } else if (!app.removed) {
10229 // This app is persistent, so we need to keep its record around.
10230 // If it is not already on the pending app list, add it there
10231 // and start a new process for it.
10232 app.thread = null;
10233 app.forcingToForeground = null;
10234 app.foregroundServices = false;
10235 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10236 mPersistentStartingProcesses.add(app);
10237 restart = true;
10238 }
10239 }
10240 mProcessesOnHold.remove(app);
10241
The Android Open Source Project4df24232009-03-05 14:34:35 -080010242 if (app == mHomeProcess) {
10243 mHomeProcess = null;
10244 }
10245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010246 if (restart) {
10247 // We have components that still need to be running in the
10248 // process, so re-launch it.
10249 mProcessNames.put(app.processName, app.info.uid, app);
10250 startProcessLocked(app, "restart", app.processName);
10251 } else if (app.pid > 0 && app.pid != MY_PID) {
10252 // Goodbye!
10253 synchronized (mPidsSelfLocked) {
10254 mPidsSelfLocked.remove(app.pid);
10255 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10256 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010257 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010258 }
10259 }
10260
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010261 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10262 // Look through the content providers we are waiting to have launched,
10263 // and if any run in this process then either schedule a restart of
10264 // the process or kill the client waiting for it if this process has
10265 // gone bad.
10266 int NL = mLaunchingProviders.size();
10267 boolean restart = false;
10268 for (int i=0; i<NL; i++) {
10269 ContentProviderRecord cpr = (ContentProviderRecord)
10270 mLaunchingProviders.get(i);
10271 if (cpr.launchingApp == app) {
10272 if (!alwaysBad && !app.bad) {
10273 restart = true;
10274 } else {
10275 removeDyingProviderLocked(app, cpr);
10276 NL = mLaunchingProviders.size();
10277 }
10278 }
10279 }
10280 return restart;
10281 }
10282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010283 // =========================================================
10284 // SERVICES
10285 // =========================================================
10286
10287 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10288 ActivityManager.RunningServiceInfo info =
10289 new ActivityManager.RunningServiceInfo();
10290 info.service = r.name;
10291 if (r.app != null) {
10292 info.pid = r.app.pid;
10293 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010294 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010295 info.process = r.processName;
10296 info.foreground = r.isForeground;
10297 info.activeSince = r.createTime;
10298 info.started = r.startRequested;
10299 info.clientCount = r.connections.size();
10300 info.crashCount = r.crashCount;
10301 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010302 if (r.isForeground) {
10303 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10304 }
10305 if (r.startRequested) {
10306 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10307 }
Dan Egnor42471dd2010-01-07 17:25:22 -080010308 if (r.app != null && r.app.pid == MY_PID) {
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010309 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10310 }
10311 if (r.app != null && r.app.persistent) {
10312 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10313 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010314 for (ConnectionRecord conn : r.connections.values()) {
10315 if (conn.clientLabel != 0) {
10316 info.clientPackage = conn.binding.client.info.packageName;
10317 info.clientLabel = conn.clientLabel;
10318 break;
10319 }
10320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010321 return info;
10322 }
10323
10324 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10325 int flags) {
10326 synchronized (this) {
10327 ArrayList<ActivityManager.RunningServiceInfo> res
10328 = new ArrayList<ActivityManager.RunningServiceInfo>();
10329
10330 if (mServices.size() > 0) {
10331 Iterator<ServiceRecord> it = mServices.values().iterator();
10332 while (it.hasNext() && res.size() < maxNum) {
10333 res.add(makeRunningServiceInfoLocked(it.next()));
10334 }
10335 }
10336
10337 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10338 ServiceRecord r = mRestartingServices.get(i);
10339 ActivityManager.RunningServiceInfo info =
10340 makeRunningServiceInfoLocked(r);
10341 info.restarting = r.nextRestartTime;
10342 res.add(info);
10343 }
10344
10345 return res;
10346 }
10347 }
10348
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010349 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10350 synchronized (this) {
10351 ServiceRecord r = mServices.get(name);
10352 if (r != null) {
10353 for (ConnectionRecord conn : r.connections.values()) {
10354 if (conn.clientIntent != null) {
10355 return conn.clientIntent;
10356 }
10357 }
10358 }
10359 }
10360 return null;
10361 }
10362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010363 private final ServiceRecord findServiceLocked(ComponentName name,
10364 IBinder token) {
10365 ServiceRecord r = mServices.get(name);
10366 return r == token ? r : null;
10367 }
10368
10369 private final class ServiceLookupResult {
10370 final ServiceRecord record;
10371 final String permission;
10372
10373 ServiceLookupResult(ServiceRecord _record, String _permission) {
10374 record = _record;
10375 permission = _permission;
10376 }
10377 };
10378
10379 private ServiceLookupResult findServiceLocked(Intent service,
10380 String resolvedType) {
10381 ServiceRecord r = null;
10382 if (service.getComponent() != null) {
10383 r = mServices.get(service.getComponent());
10384 }
10385 if (r == null) {
10386 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10387 r = mServicesByIntent.get(filter);
10388 }
10389
10390 if (r == null) {
10391 try {
10392 ResolveInfo rInfo =
10393 ActivityThread.getPackageManager().resolveService(
10394 service, resolvedType, 0);
10395 ServiceInfo sInfo =
10396 rInfo != null ? rInfo.serviceInfo : null;
10397 if (sInfo == null) {
10398 return null;
10399 }
10400
10401 ComponentName name = new ComponentName(
10402 sInfo.applicationInfo.packageName, sInfo.name);
10403 r = mServices.get(name);
10404 } catch (RemoteException ex) {
10405 // pm is in same process, this will never happen.
10406 }
10407 }
10408 if (r != null) {
10409 int callingPid = Binder.getCallingPid();
10410 int callingUid = Binder.getCallingUid();
10411 if (checkComponentPermission(r.permission,
10412 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10413 != PackageManager.PERMISSION_GRANTED) {
10414 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10415 + " from pid=" + callingPid
10416 + ", uid=" + callingUid
10417 + " requires " + r.permission);
10418 return new ServiceLookupResult(null, r.permission);
10419 }
10420 return new ServiceLookupResult(r, null);
10421 }
10422 return null;
10423 }
10424
10425 private class ServiceRestarter implements Runnable {
10426 private ServiceRecord mService;
10427
10428 void setService(ServiceRecord service) {
10429 mService = service;
10430 }
10431
10432 public void run() {
10433 synchronized(ActivityManagerService.this) {
10434 performServiceRestartLocked(mService);
10435 }
10436 }
10437 }
10438
10439 private ServiceLookupResult retrieveServiceLocked(Intent service,
10440 String resolvedType, int callingPid, int callingUid) {
10441 ServiceRecord r = null;
10442 if (service.getComponent() != null) {
10443 r = mServices.get(service.getComponent());
10444 }
10445 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10446 r = mServicesByIntent.get(filter);
10447 if (r == null) {
10448 try {
10449 ResolveInfo rInfo =
10450 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010451 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010452 ServiceInfo sInfo =
10453 rInfo != null ? rInfo.serviceInfo : null;
10454 if (sInfo == null) {
10455 Log.w(TAG, "Unable to start service " + service +
10456 ": not found");
10457 return null;
10458 }
10459
10460 ComponentName name = new ComponentName(
10461 sInfo.applicationInfo.packageName, sInfo.name);
10462 r = mServices.get(name);
10463 if (r == null) {
10464 filter = new Intent.FilterComparison(service.cloneFilter());
10465 ServiceRestarter res = new ServiceRestarter();
10466 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10467 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10468 synchronized (stats) {
10469 ss = stats.getServiceStatsLocked(
10470 sInfo.applicationInfo.uid, sInfo.packageName,
10471 sInfo.name);
10472 }
Dianne Hackbornb1c4a2a2010-01-19 15:36:42 -080010473 r = new ServiceRecord(this, ss, name, filter, sInfo, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010474 res.setService(r);
10475 mServices.put(name, r);
10476 mServicesByIntent.put(filter, r);
10477
10478 // Make sure this component isn't in the pending list.
10479 int N = mPendingServices.size();
10480 for (int i=0; i<N; i++) {
10481 ServiceRecord pr = mPendingServices.get(i);
10482 if (pr.name.equals(name)) {
10483 mPendingServices.remove(i);
10484 i--;
10485 N--;
10486 }
10487 }
10488 }
10489 } catch (RemoteException ex) {
10490 // pm is in same process, this will never happen.
10491 }
10492 }
10493 if (r != null) {
10494 if (checkComponentPermission(r.permission,
10495 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10496 != PackageManager.PERMISSION_GRANTED) {
10497 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10498 + " from pid=" + Binder.getCallingPid()
10499 + ", uid=" + Binder.getCallingUid()
10500 + " requires " + r.permission);
10501 return new ServiceLookupResult(null, r.permission);
10502 }
10503 return new ServiceLookupResult(r, null);
10504 }
10505 return null;
10506 }
10507
10508 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10509 long now = SystemClock.uptimeMillis();
10510 if (r.executeNesting == 0 && r.app != null) {
10511 if (r.app.executingServices.size() == 0) {
10512 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10513 msg.obj = r.app;
10514 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10515 }
10516 r.app.executingServices.add(r);
10517 }
10518 r.executeNesting++;
10519 r.executingStart = now;
10520 }
10521
10522 private final void sendServiceArgsLocked(ServiceRecord r,
10523 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010524 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010525 if (N == 0) {
10526 return;
10527 }
10528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010529 int i = 0;
10530 while (i < N) {
10531 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010532 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010533 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010534 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010535 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010536 // If somehow we got a dummy start at the front, then
10537 // just drop it here.
10538 i++;
10539 continue;
10540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010541 bumpServiceExecutingLocked(r);
10542 if (!oomAdjusted) {
10543 oomAdjusted = true;
10544 updateOomAdjLocked(r.app);
10545 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010546 int flags = 0;
10547 if (si.deliveryCount > 0) {
10548 flags |= Service.START_FLAG_RETRY;
10549 }
10550 if (si.doneExecutingCount > 0) {
10551 flags |= Service.START_FLAG_REDELIVERY;
10552 }
10553 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10554 si.deliveredTime = SystemClock.uptimeMillis();
10555 r.deliveredStarts.add(si);
10556 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010557 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010558 } catch (RemoteException e) {
10559 // Remote process gone... we'll let the normal cleanup take
10560 // care of this.
10561 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010562 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010563 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010564 break;
10565 }
10566 }
10567 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010568 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010569 } else {
10570 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010571 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010572 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010573 }
10574 }
10575 }
10576
10577 private final boolean requestServiceBindingLocked(ServiceRecord r,
10578 IntentBindRecord i, boolean rebind) {
10579 if (r.app == null || r.app.thread == null) {
10580 // If service is not currently running, can't yet bind.
10581 return false;
10582 }
10583 if ((!i.requested || rebind) && i.apps.size() > 0) {
10584 try {
10585 bumpServiceExecutingLocked(r);
10586 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10587 + ": shouldUnbind=" + i.hasBound);
10588 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10589 if (!rebind) {
10590 i.requested = true;
10591 }
10592 i.hasBound = true;
10593 i.doRebind = false;
10594 } catch (RemoteException e) {
10595 return false;
10596 }
10597 }
10598 return true;
10599 }
10600
10601 private final void requestServiceBindingsLocked(ServiceRecord r) {
10602 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10603 while (bindings.hasNext()) {
10604 IntentBindRecord i = bindings.next();
10605 if (!requestServiceBindingLocked(r, i, false)) {
10606 break;
10607 }
10608 }
10609 }
10610
10611 private final void realStartServiceLocked(ServiceRecord r,
10612 ProcessRecord app) throws RemoteException {
10613 if (app.thread == null) {
10614 throw new RemoteException();
10615 }
10616
10617 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010618 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010619
10620 app.services.add(r);
10621 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010622 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010623
10624 boolean created = false;
10625 try {
10626 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10627 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010628 mStringBuilder.setLength(0);
10629 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010630 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010631 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010632 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010633 synchronized (r.stats.getBatteryStats()) {
10634 r.stats.startLaunchedLocked();
10635 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010636 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010637 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010638 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010639 created = true;
10640 } finally {
10641 if (!created) {
10642 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010643 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010644 }
10645 }
10646
10647 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010648
10649 // If the service is in the started state, and there are no
10650 // pending arguments, then fake up one so its onStartCommand() will
10651 // be called.
10652 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10653 r.lastStartId++;
10654 if (r.lastStartId < 1) {
10655 r.lastStartId = 1;
10656 }
10657 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10658 }
10659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010660 sendServiceArgsLocked(r, true);
10661 }
10662
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010663 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10664 boolean allowCancel) {
10665 boolean canceled = false;
10666
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010667 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010668 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010669 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010670
10671 // Any delivered but not yet finished starts should be put back
10672 // on the pending list.
10673 final int N = r.deliveredStarts.size();
10674 if (N > 0) {
10675 for (int i=N-1; i>=0; i--) {
10676 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10677 if (si.intent == null) {
10678 // We'll generate this again if needed.
10679 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10680 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10681 r.pendingStarts.add(0, si);
10682 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10683 dur *= 2;
10684 if (minDuration < dur) minDuration = dur;
10685 if (resetTime < dur) resetTime = dur;
10686 } else {
10687 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10688 + r.name);
10689 canceled = true;
10690 }
10691 }
10692 r.deliveredStarts.clear();
10693 }
10694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010695 r.totalRestartCount++;
10696 if (r.restartDelay == 0) {
10697 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010698 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010699 } else {
10700 // If it has been a "reasonably long time" since the service
10701 // was started, then reset our restart duration back to
10702 // the beginning, so we don't infinitely increase the duration
10703 // on a service that just occasionally gets killed (which is
10704 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010705 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010706 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010707 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010708 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010709 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010710 if (r.restartDelay < minDuration) {
10711 r.restartDelay = minDuration;
10712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010713 }
10714 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010715
10716 r.nextRestartTime = now + r.restartDelay;
10717
10718 // Make sure that we don't end up restarting a bunch of services
10719 // all at the same time.
10720 boolean repeat;
10721 do {
10722 repeat = false;
10723 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10724 ServiceRecord r2 = mRestartingServices.get(i);
10725 if (r2 != r && r.nextRestartTime
10726 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10727 && r.nextRestartTime
10728 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10729 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10730 r.restartDelay = r.nextRestartTime - now;
10731 repeat = true;
10732 break;
10733 }
10734 }
10735 } while (repeat);
10736
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010737 if (!mRestartingServices.contains(r)) {
10738 mRestartingServices.add(r);
10739 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010740
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010741 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010743 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010744 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010745 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10746 Log.w(TAG, "Scheduling restart of crashed service "
10747 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010748 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010749 r.shortName, r.restartDelay);
10750
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010751 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010752 }
10753
10754 final void performServiceRestartLocked(ServiceRecord r) {
10755 if (!mRestartingServices.contains(r)) {
10756 return;
10757 }
10758 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10759 }
10760
10761 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10762 if (r.restartDelay == 0) {
10763 return false;
10764 }
10765 r.resetRestartCounter();
10766 mRestartingServices.remove(r);
10767 mHandler.removeCallbacks(r.restarter);
10768 return true;
10769 }
10770
10771 private final boolean bringUpServiceLocked(ServiceRecord r,
10772 int intentFlags, boolean whileRestarting) {
10773 //Log.i(TAG, "Bring up service:");
10774 //r.dump(" ");
10775
Dianne Hackborn36124872009-10-08 16:22:03 -070010776 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010777 sendServiceArgsLocked(r, false);
10778 return true;
10779 }
10780
10781 if (!whileRestarting && r.restartDelay > 0) {
10782 // If waiting for a restart, then do nothing.
10783 return true;
10784 }
10785
10786 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10787 + " " + r.intent);
10788
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010789 // We are now bringing the service up, so no longer in the
10790 // restarting state.
10791 mRestartingServices.remove(r);
10792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010793 final String appName = r.processName;
10794 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10795 if (app != null && app.thread != null) {
10796 try {
10797 realStartServiceLocked(r, app);
10798 return true;
10799 } catch (RemoteException e) {
10800 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10801 }
10802
10803 // If a dead object exception was thrown -- fall through to
10804 // restart the application.
10805 }
10806
Dianne Hackborn36124872009-10-08 16:22:03 -070010807 // Not running -- get it started, and enqueue this service record
10808 // to be executed when the app comes up.
10809 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10810 "service", r.name, false) == null) {
10811 Log.w(TAG, "Unable to launch app "
10812 + r.appInfo.packageName + "/"
10813 + r.appInfo.uid + " for service "
10814 + r.intent.getIntent() + ": process is bad");
10815 bringDownServiceLocked(r, true);
10816 return false;
10817 }
10818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010819 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010820 mPendingServices.add(r);
10821 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010823 return true;
10824 }
10825
10826 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10827 //Log.i(TAG, "Bring down service:");
10828 //r.dump(" ");
10829
10830 // Does it still need to run?
10831 if (!force && r.startRequested) {
10832 return;
10833 }
10834 if (r.connections.size() > 0) {
10835 if (!force) {
10836 // XXX should probably keep a count of the number of auto-create
10837 // connections directly in the service.
10838 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10839 while (it.hasNext()) {
10840 ConnectionRecord cr = it.next();
10841 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10842 return;
10843 }
10844 }
10845 }
10846
10847 // Report to all of the connections that the service is no longer
10848 // available.
10849 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10850 while (it.hasNext()) {
10851 ConnectionRecord c = it.next();
10852 try {
10853 // todo: shouldn't be a synchronous call!
10854 c.conn.connected(r.name, null);
10855 } catch (Exception e) {
10856 Log.w(TAG, "Failure disconnecting service " + r.name +
10857 " to connection " + c.conn.asBinder() +
10858 " (in " + c.binding.client.processName + ")", e);
10859 }
10860 }
10861 }
10862
10863 // Tell the service that it has been unbound.
10864 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10865 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10866 while (it.hasNext()) {
10867 IntentBindRecord ibr = it.next();
10868 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10869 + ": hasBound=" + ibr.hasBound);
10870 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10871 try {
10872 bumpServiceExecutingLocked(r);
10873 updateOomAdjLocked(r.app);
10874 ibr.hasBound = false;
10875 r.app.thread.scheduleUnbindService(r,
10876 ibr.intent.getIntent());
10877 } catch (Exception e) {
10878 Log.w(TAG, "Exception when unbinding service "
10879 + r.shortName, e);
10880 serviceDoneExecutingLocked(r, true);
10881 }
10882 }
10883 }
10884 }
10885
10886 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10887 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010888 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010889 System.identityHashCode(r), r.shortName,
10890 (r.app != null) ? r.app.pid : -1);
10891
10892 mServices.remove(r.name);
10893 mServicesByIntent.remove(r.intent);
10894 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10895 r.totalRestartCount = 0;
10896 unscheduleServiceRestartLocked(r);
10897
10898 // Also make sure it is not on the pending list.
10899 int N = mPendingServices.size();
10900 for (int i=0; i<N; i++) {
10901 if (mPendingServices.get(i) == r) {
10902 mPendingServices.remove(i);
10903 if (DEBUG_SERVICE) Log.v(
10904 TAG, "Removed pending service: " + r.shortName);
10905 i--;
10906 N--;
10907 }
10908 }
10909
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010910 r.cancelNotification();
10911 r.isForeground = false;
10912 r.foregroundId = 0;
10913 r.foregroundNoti = null;
10914
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010915 // Clear start entries.
10916 r.deliveredStarts.clear();
10917 r.pendingStarts.clear();
10918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010919 if (r.app != null) {
10920 synchronized (r.stats.getBatteryStats()) {
10921 r.stats.stopLaunchedLocked();
10922 }
10923 r.app.services.remove(r);
10924 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010925 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010926 if (DEBUG_SERVICE) Log.v(TAG,
10927 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010928 bumpServiceExecutingLocked(r);
10929 mStoppingServices.add(r);
10930 updateOomAdjLocked(r.app);
10931 r.app.thread.scheduleStopService(r);
10932 } catch (Exception e) {
10933 Log.w(TAG, "Exception when stopping service "
10934 + r.shortName, e);
10935 serviceDoneExecutingLocked(r, true);
10936 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010937 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010938 } else {
10939 if (DEBUG_SERVICE) Log.v(
10940 TAG, "Removed service that has no process: " + r.shortName);
10941 }
10942 } else {
10943 if (DEBUG_SERVICE) Log.v(
10944 TAG, "Removed service that is not running: " + r.shortName);
10945 }
10946 }
10947
10948 ComponentName startServiceLocked(IApplicationThread caller,
10949 Intent service, String resolvedType,
10950 int callingPid, int callingUid) {
10951 synchronized(this) {
10952 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10953 + " type=" + resolvedType + " args=" + service.getExtras());
10954
10955 if (caller != null) {
10956 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10957 if (callerApp == null) {
10958 throw new SecurityException(
10959 "Unable to find app for caller " + caller
10960 + " (pid=" + Binder.getCallingPid()
10961 + ") when starting service " + service);
10962 }
10963 }
10964
10965 ServiceLookupResult res =
10966 retrieveServiceLocked(service, resolvedType,
10967 callingPid, callingUid);
10968 if (res == null) {
10969 return null;
10970 }
10971 if (res.record == null) {
10972 return new ComponentName("!", res.permission != null
10973 ? res.permission : "private to package");
10974 }
10975 ServiceRecord r = res.record;
10976 if (unscheduleServiceRestartLocked(r)) {
10977 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10978 + r.shortName);
10979 }
10980 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010981 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010982 r.lastStartId++;
10983 if (r.lastStartId < 1) {
10984 r.lastStartId = 1;
10985 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010986 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010987 r.lastActivity = SystemClock.uptimeMillis();
10988 synchronized (r.stats.getBatteryStats()) {
10989 r.stats.startRunningLocked();
10990 }
10991 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10992 return new ComponentName("!", "Service process is bad");
10993 }
10994 return r.name;
10995 }
10996 }
10997
10998 public ComponentName startService(IApplicationThread caller, Intent service,
10999 String resolvedType) {
11000 // Refuse possible leaked file descriptors
11001 if (service != null && service.hasFileDescriptors() == true) {
11002 throw new IllegalArgumentException("File descriptors passed in Intent");
11003 }
11004
11005 synchronized(this) {
11006 final int callingPid = Binder.getCallingPid();
11007 final int callingUid = Binder.getCallingUid();
11008 final long origId = Binder.clearCallingIdentity();
11009 ComponentName res = startServiceLocked(caller, service,
11010 resolvedType, callingPid, callingUid);
11011 Binder.restoreCallingIdentity(origId);
11012 return res;
11013 }
11014 }
11015
11016 ComponentName startServiceInPackage(int uid,
11017 Intent service, String resolvedType) {
11018 synchronized(this) {
11019 final long origId = Binder.clearCallingIdentity();
11020 ComponentName res = startServiceLocked(null, service,
11021 resolvedType, -1, uid);
11022 Binder.restoreCallingIdentity(origId);
11023 return res;
11024 }
11025 }
11026
11027 public int stopService(IApplicationThread caller, Intent service,
11028 String resolvedType) {
11029 // Refuse possible leaked file descriptors
11030 if (service != null && service.hasFileDescriptors() == true) {
11031 throw new IllegalArgumentException("File descriptors passed in Intent");
11032 }
11033
11034 synchronized(this) {
11035 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11036 + " type=" + resolvedType);
11037
11038 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11039 if (caller != null && callerApp == null) {
11040 throw new SecurityException(
11041 "Unable to find app for caller " + caller
11042 + " (pid=" + Binder.getCallingPid()
11043 + ") when stopping service " + service);
11044 }
11045
11046 // If this service is active, make sure it is stopped.
11047 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11048 if (r != null) {
11049 if (r.record != null) {
11050 synchronized (r.record.stats.getBatteryStats()) {
11051 r.record.stats.stopRunningLocked();
11052 }
11053 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011054 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011055 final long origId = Binder.clearCallingIdentity();
11056 bringDownServiceLocked(r.record, false);
11057 Binder.restoreCallingIdentity(origId);
11058 return 1;
11059 }
11060 return -1;
11061 }
11062 }
11063
11064 return 0;
11065 }
11066
11067 public IBinder peekService(Intent service, String resolvedType) {
11068 // Refuse possible leaked file descriptors
11069 if (service != null && service.hasFileDescriptors() == true) {
11070 throw new IllegalArgumentException("File descriptors passed in Intent");
11071 }
11072
11073 IBinder ret = null;
11074
11075 synchronized(this) {
11076 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11077
11078 if (r != null) {
11079 // r.record is null if findServiceLocked() failed the caller permission check
11080 if (r.record == null) {
11081 throw new SecurityException(
11082 "Permission Denial: Accessing service " + r.record.name
11083 + " from pid=" + Binder.getCallingPid()
11084 + ", uid=" + Binder.getCallingUid()
11085 + " requires " + r.permission);
11086 }
11087 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11088 if (ib != null) {
11089 ret = ib.binder;
11090 }
11091 }
11092 }
11093
11094 return ret;
11095 }
11096
11097 public boolean stopServiceToken(ComponentName className, IBinder token,
11098 int startId) {
11099 synchronized(this) {
11100 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11101 + " " + token + " startId=" + startId);
11102 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011103 if (r != null) {
11104 if (startId >= 0) {
11105 // Asked to only stop if done with all work. Note that
11106 // to avoid leaks, we will take this as dropping all
11107 // start items up to and including this one.
11108 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11109 if (si != null) {
11110 while (r.deliveredStarts.size() > 0) {
11111 if (r.deliveredStarts.remove(0) == si) {
11112 break;
11113 }
11114 }
11115 }
11116
11117 if (r.lastStartId != startId) {
11118 return false;
11119 }
11120
11121 if (r.deliveredStarts.size() > 0) {
11122 Log.w(TAG, "stopServiceToken startId " + startId
11123 + " is last, but have " + r.deliveredStarts.size()
11124 + " remaining args");
11125 }
11126 }
11127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011128 synchronized (r.stats.getBatteryStats()) {
11129 r.stats.stopRunningLocked();
11130 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011131 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011132 }
11133 final long origId = Binder.clearCallingIdentity();
11134 bringDownServiceLocked(r, false);
11135 Binder.restoreCallingIdentity(origId);
11136 return true;
11137 }
11138 }
11139 return false;
11140 }
11141
11142 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011143 int id, Notification notification, boolean removeNotification) {
11144 final long origId = Binder.clearCallingIdentity();
11145 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011146 synchronized(this) {
11147 ServiceRecord r = findServiceLocked(className, token);
11148 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011149 if (id != 0) {
11150 if (notification == null) {
11151 throw new IllegalArgumentException("null notification");
11152 }
11153 if (r.foregroundId != id) {
11154 r.cancelNotification();
11155 r.foregroundId = id;
11156 }
11157 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11158 r.foregroundNoti = notification;
11159 r.isForeground = true;
11160 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011161 if (r.app != null) {
11162 updateServiceForegroundLocked(r.app, true);
11163 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011164 } else {
11165 if (r.isForeground) {
11166 r.isForeground = false;
11167 if (r.app != null) {
11168 updateServiceForegroundLocked(r.app, true);
11169 }
11170 }
11171 if (removeNotification) {
11172 r.cancelNotification();
11173 r.foregroundId = 0;
11174 r.foregroundNoti = null;
11175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011176 }
11177 }
11178 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011179 } finally {
11180 Binder.restoreCallingIdentity(origId);
11181 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011182 }
11183
11184 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11185 boolean anyForeground = false;
11186 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11187 if (sr.isForeground) {
11188 anyForeground = true;
11189 break;
11190 }
11191 }
11192 if (anyForeground != proc.foregroundServices) {
11193 proc.foregroundServices = anyForeground;
11194 if (oomAdj) {
11195 updateOomAdjLocked();
11196 }
11197 }
11198 }
11199
11200 public int bindService(IApplicationThread caller, IBinder token,
11201 Intent service, String resolvedType,
11202 IServiceConnection connection, int flags) {
11203 // Refuse possible leaked file descriptors
11204 if (service != null && service.hasFileDescriptors() == true) {
11205 throw new IllegalArgumentException("File descriptors passed in Intent");
11206 }
11207
11208 synchronized(this) {
11209 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11210 + " type=" + resolvedType + " conn=" + connection.asBinder()
11211 + " flags=0x" + Integer.toHexString(flags));
11212 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11213 if (callerApp == null) {
11214 throw new SecurityException(
11215 "Unable to find app for caller " + caller
11216 + " (pid=" + Binder.getCallingPid()
11217 + ") when binding service " + service);
11218 }
11219
11220 HistoryRecord activity = null;
11221 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011222 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011223 if (aindex < 0) {
11224 Log.w(TAG, "Binding with unknown activity: " + token);
11225 return 0;
11226 }
11227 activity = (HistoryRecord)mHistory.get(aindex);
11228 }
11229
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011230 int clientLabel = 0;
11231 PendingIntent clientIntent = null;
11232
11233 if (callerApp.info.uid == Process.SYSTEM_UID) {
11234 // Hacky kind of thing -- allow system stuff to tell us
11235 // what they are, so we can report this elsewhere for
11236 // others to know why certain services are running.
11237 try {
11238 clientIntent = (PendingIntent)service.getParcelableExtra(
11239 Intent.EXTRA_CLIENT_INTENT);
11240 } catch (RuntimeException e) {
11241 }
11242 if (clientIntent != null) {
11243 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11244 if (clientLabel != 0) {
11245 // There are no useful extras in the intent, trash them.
11246 // System code calling with this stuff just needs to know
11247 // this will happen.
11248 service = service.cloneFilter();
11249 }
11250 }
11251 }
11252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011253 ServiceLookupResult res =
11254 retrieveServiceLocked(service, resolvedType,
11255 Binder.getCallingPid(), Binder.getCallingUid());
11256 if (res == null) {
11257 return 0;
11258 }
11259 if (res.record == null) {
11260 return -1;
11261 }
11262 ServiceRecord s = res.record;
11263
11264 final long origId = Binder.clearCallingIdentity();
11265
11266 if (unscheduleServiceRestartLocked(s)) {
11267 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11268 + s.shortName);
11269 }
11270
11271 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11272 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011273 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011274
11275 IBinder binder = connection.asBinder();
11276 s.connections.put(binder, c);
11277 b.connections.add(c);
11278 if (activity != null) {
11279 if (activity.connections == null) {
11280 activity.connections = new HashSet<ConnectionRecord>();
11281 }
11282 activity.connections.add(c);
11283 }
11284 b.client.connections.add(c);
11285 mServiceConnections.put(binder, c);
11286
11287 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11288 s.lastActivity = SystemClock.uptimeMillis();
11289 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11290 return 0;
11291 }
11292 }
11293
11294 if (s.app != null) {
11295 // This could have made the service more important.
11296 updateOomAdjLocked(s.app);
11297 }
11298
11299 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11300 + ": received=" + b.intent.received
11301 + " apps=" + b.intent.apps.size()
11302 + " doRebind=" + b.intent.doRebind);
11303
11304 if (s.app != null && b.intent.received) {
11305 // Service is already running, so we can immediately
11306 // publish the connection.
11307 try {
11308 c.conn.connected(s.name, b.intent.binder);
11309 } catch (Exception e) {
11310 Log.w(TAG, "Failure sending service " + s.shortName
11311 + " to connection " + c.conn.asBinder()
11312 + " (in " + c.binding.client.processName + ")", e);
11313 }
11314
11315 // If this is the first app connected back to this binding,
11316 // and the service had previously asked to be told when
11317 // rebound, then do so.
11318 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11319 requestServiceBindingLocked(s, b.intent, true);
11320 }
11321 } else if (!b.intent.requested) {
11322 requestServiceBindingLocked(s, b.intent, false);
11323 }
11324
11325 Binder.restoreCallingIdentity(origId);
11326 }
11327
11328 return 1;
11329 }
11330
11331 private void removeConnectionLocked(
11332 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11333 IBinder binder = c.conn.asBinder();
11334 AppBindRecord b = c.binding;
11335 ServiceRecord s = b.service;
11336 s.connections.remove(binder);
11337 b.connections.remove(c);
11338 if (c.activity != null && c.activity != skipAct) {
11339 if (c.activity.connections != null) {
11340 c.activity.connections.remove(c);
11341 }
11342 }
11343 if (b.client != skipApp) {
11344 b.client.connections.remove(c);
11345 }
11346 mServiceConnections.remove(binder);
11347
11348 if (b.connections.size() == 0) {
11349 b.intent.apps.remove(b.client);
11350 }
11351
11352 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11353 + ": shouldUnbind=" + b.intent.hasBound);
11354 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11355 && b.intent.hasBound) {
11356 try {
11357 bumpServiceExecutingLocked(s);
11358 updateOomAdjLocked(s.app);
11359 b.intent.hasBound = false;
11360 // Assume the client doesn't want to know about a rebind;
11361 // we will deal with that later if it asks for one.
11362 b.intent.doRebind = false;
11363 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11364 } catch (Exception e) {
11365 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11366 serviceDoneExecutingLocked(s, true);
11367 }
11368 }
11369
11370 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11371 bringDownServiceLocked(s, false);
11372 }
11373 }
11374
11375 public boolean unbindService(IServiceConnection connection) {
11376 synchronized (this) {
11377 IBinder binder = connection.asBinder();
11378 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11379 ConnectionRecord r = mServiceConnections.get(binder);
11380 if (r == null) {
11381 Log.w(TAG, "Unbind failed: could not find connection for "
11382 + connection.asBinder());
11383 return false;
11384 }
11385
11386 final long origId = Binder.clearCallingIdentity();
11387
11388 removeConnectionLocked(r, null, null);
11389
11390 if (r.binding.service.app != null) {
11391 // This could have made the service less important.
11392 updateOomAdjLocked(r.binding.service.app);
11393 }
11394
11395 Binder.restoreCallingIdentity(origId);
11396 }
11397
11398 return true;
11399 }
11400
11401 public void publishService(IBinder token, Intent intent, IBinder service) {
11402 // Refuse possible leaked file descriptors
11403 if (intent != null && intent.hasFileDescriptors() == true) {
11404 throw new IllegalArgumentException("File descriptors passed in Intent");
11405 }
11406
11407 synchronized(this) {
11408 if (!(token instanceof ServiceRecord)) {
11409 throw new IllegalArgumentException("Invalid service token");
11410 }
11411 ServiceRecord r = (ServiceRecord)token;
11412
11413 final long origId = Binder.clearCallingIdentity();
11414
11415 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11416 + " " + intent + ": " + service);
11417 if (r != null) {
11418 Intent.FilterComparison filter
11419 = new Intent.FilterComparison(intent);
11420 IntentBindRecord b = r.bindings.get(filter);
11421 if (b != null && !b.received) {
11422 b.binder = service;
11423 b.requested = true;
11424 b.received = true;
11425 if (r.connections.size() > 0) {
11426 Iterator<ConnectionRecord> it
11427 = r.connections.values().iterator();
11428 while (it.hasNext()) {
11429 ConnectionRecord c = it.next();
11430 if (!filter.equals(c.binding.intent.intent)) {
11431 if (DEBUG_SERVICE) Log.v(
11432 TAG, "Not publishing to: " + c);
11433 if (DEBUG_SERVICE) Log.v(
11434 TAG, "Bound intent: " + c.binding.intent.intent);
11435 if (DEBUG_SERVICE) Log.v(
11436 TAG, "Published intent: " + intent);
11437 continue;
11438 }
11439 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11440 try {
11441 c.conn.connected(r.name, service);
11442 } catch (Exception e) {
11443 Log.w(TAG, "Failure sending service " + r.name +
11444 " to connection " + c.conn.asBinder() +
11445 " (in " + c.binding.client.processName + ")", e);
11446 }
11447 }
11448 }
11449 }
11450
11451 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11452
11453 Binder.restoreCallingIdentity(origId);
11454 }
11455 }
11456 }
11457
11458 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11459 // Refuse possible leaked file descriptors
11460 if (intent != null && intent.hasFileDescriptors() == true) {
11461 throw new IllegalArgumentException("File descriptors passed in Intent");
11462 }
11463
11464 synchronized(this) {
11465 if (!(token instanceof ServiceRecord)) {
11466 throw new IllegalArgumentException("Invalid service token");
11467 }
11468 ServiceRecord r = (ServiceRecord)token;
11469
11470 final long origId = Binder.clearCallingIdentity();
11471
11472 if (r != null) {
11473 Intent.FilterComparison filter
11474 = new Intent.FilterComparison(intent);
11475 IntentBindRecord b = r.bindings.get(filter);
11476 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11477 + " at " + b + ": apps="
11478 + (b != null ? b.apps.size() : 0));
11479 if (b != null) {
11480 if (b.apps.size() > 0) {
11481 // Applications have already bound since the last
11482 // unbind, so just rebind right here.
11483 requestServiceBindingLocked(r, b, true);
11484 } else {
11485 // Note to tell the service the next time there is
11486 // a new client.
11487 b.doRebind = true;
11488 }
11489 }
11490
11491 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11492
11493 Binder.restoreCallingIdentity(origId);
11494 }
11495 }
11496 }
11497
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011498 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011499 synchronized(this) {
11500 if (!(token instanceof ServiceRecord)) {
11501 throw new IllegalArgumentException("Invalid service token");
11502 }
11503 ServiceRecord r = (ServiceRecord)token;
11504 boolean inStopping = mStoppingServices.contains(token);
11505 if (r != null) {
11506 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11507 + ": nesting=" + r.executeNesting
11508 + ", inStopping=" + inStopping);
11509 if (r != token) {
11510 Log.w(TAG, "Done executing service " + r.name
11511 + " with incorrect token: given " + token
11512 + ", expected " + r);
11513 return;
11514 }
11515
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011516 if (type == 1) {
11517 // This is a call from a service start... take care of
11518 // book-keeping.
11519 r.callStart = true;
11520 switch (res) {
11521 case Service.START_STICKY_COMPATIBILITY:
11522 case Service.START_STICKY: {
11523 // We are done with the associated start arguments.
11524 r.findDeliveredStart(startId, true);
11525 // Don't stop if killed.
11526 r.stopIfKilled = false;
11527 break;
11528 }
11529 case Service.START_NOT_STICKY: {
11530 // We are done with the associated start arguments.
11531 r.findDeliveredStart(startId, true);
11532 if (r.lastStartId == startId) {
11533 // There is no more work, and this service
11534 // doesn't want to hang around if killed.
11535 r.stopIfKilled = true;
11536 }
11537 break;
11538 }
11539 case Service.START_REDELIVER_INTENT: {
11540 // We'll keep this item until they explicitly
11541 // call stop for it, but keep track of the fact
11542 // that it was delivered.
11543 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11544 if (si != null) {
11545 si.deliveryCount = 0;
11546 si.doneExecutingCount++;
11547 // Don't stop if killed.
11548 r.stopIfKilled = true;
11549 }
11550 break;
11551 }
11552 default:
11553 throw new IllegalArgumentException(
11554 "Unknown service start result: " + res);
11555 }
11556 if (res == Service.START_STICKY_COMPATIBILITY) {
11557 r.callStart = false;
11558 }
11559 }
11560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011561 final long origId = Binder.clearCallingIdentity();
11562 serviceDoneExecutingLocked(r, inStopping);
11563 Binder.restoreCallingIdentity(origId);
11564 } else {
11565 Log.w(TAG, "Done executing unknown service " + r.name
11566 + " with token " + token);
11567 }
11568 }
11569 }
11570
11571 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11572 r.executeNesting--;
11573 if (r.executeNesting <= 0 && r.app != null) {
11574 r.app.executingServices.remove(r);
11575 if (r.app.executingServices.size() == 0) {
11576 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11577 }
11578 if (inStopping) {
11579 mStoppingServices.remove(r);
11580 }
11581 updateOomAdjLocked(r.app);
11582 }
11583 }
11584
11585 void serviceTimeout(ProcessRecord proc) {
11586 synchronized(this) {
11587 if (proc.executingServices.size() == 0 || proc.thread == null) {
11588 return;
11589 }
11590 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11591 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11592 ServiceRecord timeout = null;
11593 long nextTime = 0;
11594 while (it.hasNext()) {
11595 ServiceRecord sr = it.next();
11596 if (sr.executingStart < maxTime) {
11597 timeout = sr;
11598 break;
11599 }
11600 if (sr.executingStart > nextTime) {
11601 nextTime = sr.executingStart;
11602 }
11603 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011604 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011605 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnor42471dd2010-01-07 17:25:22 -080011606 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011607 } else {
11608 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11609 msg.obj = proc;
11610 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11611 }
11612 }
11613 }
11614
11615 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011616 // BACKUP AND RESTORE
11617 // =========================================================
11618
11619 // Cause the target app to be launched if necessary and its backup agent
11620 // instantiated. The backup agent will invoke backupAgentCreated() on the
11621 // activity manager to announce its creation.
11622 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11623 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11624 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11625
11626 synchronized(this) {
11627 // !!! TODO: currently no check here that we're already bound
11628 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11629 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11630 synchronized (stats) {
11631 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11632 }
11633
11634 BackupRecord r = new BackupRecord(ss, app, backupMode);
11635 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11636 // startProcessLocked() returns existing proc's record if it's already running
11637 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011638 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011639 if (proc == null) {
11640 Log.e(TAG, "Unable to start backup agent process " + r);
11641 return false;
11642 }
11643
11644 r.app = proc;
11645 mBackupTarget = r;
11646 mBackupAppName = app.packageName;
11647
Christopher Tate6fa95972009-06-05 18:43:55 -070011648 // Try not to kill the process during backup
11649 updateOomAdjLocked(proc);
11650
Christopher Tate181fafa2009-05-14 11:12:14 -070011651 // If the process is already attached, schedule the creation of the backup agent now.
11652 // If it is not yet live, this will be done when it attaches to the framework.
11653 if (proc.thread != null) {
11654 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11655 try {
11656 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11657 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011658 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011659 }
11660 } else {
11661 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11662 }
11663 // Invariants: at this point, the target app process exists and the application
11664 // is either already running or in the process of coming up. mBackupTarget and
11665 // mBackupAppName describe the app, so that when it binds back to the AM we
11666 // know that it's scheduled for a backup-agent operation.
11667 }
11668
11669 return true;
11670 }
11671
11672 // A backup agent has just come up
11673 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11674 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11675 + " = " + agent);
11676
11677 synchronized(this) {
11678 if (!agentPackageName.equals(mBackupAppName)) {
11679 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11680 return;
11681 }
11682
Christopher Tate043dadc2009-06-02 16:11:00 -070011683 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011684 try {
11685 IBackupManager bm = IBackupManager.Stub.asInterface(
11686 ServiceManager.getService(Context.BACKUP_SERVICE));
11687 bm.agentConnected(agentPackageName, agent);
11688 } catch (RemoteException e) {
11689 // can't happen; the backup manager service is local
11690 } catch (Exception e) {
11691 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11692 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011693 } finally {
11694 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011695 }
11696 }
11697 }
11698
11699 // done with this agent
11700 public void unbindBackupAgent(ApplicationInfo appInfo) {
11701 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011702 if (appInfo == null) {
11703 Log.w(TAG, "unbind backup agent for null app");
11704 return;
11705 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011706
11707 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011708 if (mBackupAppName == null) {
11709 Log.w(TAG, "Unbinding backup agent with no active backup");
11710 return;
11711 }
11712
Christopher Tate181fafa2009-05-14 11:12:14 -070011713 if (!mBackupAppName.equals(appInfo.packageName)) {
11714 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11715 return;
11716 }
11717
Christopher Tate6fa95972009-06-05 18:43:55 -070011718 ProcessRecord proc = mBackupTarget.app;
11719 mBackupTarget = null;
11720 mBackupAppName = null;
11721
11722 // Not backing this app up any more; reset its OOM adjustment
11723 updateOomAdjLocked(proc);
11724
Christopher Tatec7b31e32009-06-10 15:49:30 -070011725 // If the app crashed during backup, 'thread' will be null here
11726 if (proc.thread != null) {
11727 try {
11728 proc.thread.scheduleDestroyBackupAgent(appInfo);
11729 } catch (Exception e) {
11730 Log.e(TAG, "Exception when unbinding backup agent:");
11731 e.printStackTrace();
11732 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011733 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011734 }
11735 }
11736 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011737 // BROADCASTS
11738 // =========================================================
11739
11740 private final List getStickies(String action, IntentFilter filter,
11741 List cur) {
11742 final ContentResolver resolver = mContext.getContentResolver();
11743 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11744 if (list == null) {
11745 return cur;
11746 }
11747 int N = list.size();
11748 for (int i=0; i<N; i++) {
11749 Intent intent = list.get(i);
11750 if (filter.match(resolver, intent, true, TAG) >= 0) {
11751 if (cur == null) {
11752 cur = new ArrayList<Intent>();
11753 }
11754 cur.add(intent);
11755 }
11756 }
11757 return cur;
11758 }
11759
11760 private final void scheduleBroadcastsLocked() {
11761 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11762 + mBroadcastsScheduled);
11763
11764 if (mBroadcastsScheduled) {
11765 return;
11766 }
11767 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11768 mBroadcastsScheduled = true;
11769 }
11770
11771 public Intent registerReceiver(IApplicationThread caller,
11772 IIntentReceiver receiver, IntentFilter filter, String permission) {
11773 synchronized(this) {
11774 ProcessRecord callerApp = null;
11775 if (caller != null) {
11776 callerApp = getRecordForAppLocked(caller);
11777 if (callerApp == null) {
11778 throw new SecurityException(
11779 "Unable to find app for caller " + caller
11780 + " (pid=" + Binder.getCallingPid()
11781 + ") when registering receiver " + receiver);
11782 }
11783 }
11784
11785 List allSticky = null;
11786
11787 // Look for any matching sticky broadcasts...
11788 Iterator actions = filter.actionsIterator();
11789 if (actions != null) {
11790 while (actions.hasNext()) {
11791 String action = (String)actions.next();
11792 allSticky = getStickies(action, filter, allSticky);
11793 }
11794 } else {
11795 allSticky = getStickies(null, filter, allSticky);
11796 }
11797
11798 // The first sticky in the list is returned directly back to
11799 // the client.
11800 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11801
11802 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11803 + ": " + sticky);
11804
11805 if (receiver == null) {
11806 return sticky;
11807 }
11808
11809 ReceiverList rl
11810 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11811 if (rl == null) {
11812 rl = new ReceiverList(this, callerApp,
11813 Binder.getCallingPid(),
11814 Binder.getCallingUid(), receiver);
11815 if (rl.app != null) {
11816 rl.app.receivers.add(rl);
11817 } else {
11818 try {
11819 receiver.asBinder().linkToDeath(rl, 0);
11820 } catch (RemoteException e) {
11821 return sticky;
11822 }
11823 rl.linkedToDeath = true;
11824 }
11825 mRegisteredReceivers.put(receiver.asBinder(), rl);
11826 }
11827 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11828 rl.add(bf);
11829 if (!bf.debugCheck()) {
11830 Log.w(TAG, "==> For Dynamic broadast");
11831 }
11832 mReceiverResolver.addFilter(bf);
11833
11834 // Enqueue broadcasts for all existing stickies that match
11835 // this filter.
11836 if (allSticky != null) {
11837 ArrayList receivers = new ArrayList();
11838 receivers.add(bf);
11839
11840 int N = allSticky.size();
11841 for (int i=0; i<N; i++) {
11842 Intent intent = (Intent)allSticky.get(i);
11843 BroadcastRecord r = new BroadcastRecord(intent, null,
11844 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011845 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011846 if (mParallelBroadcasts.size() == 0) {
11847 scheduleBroadcastsLocked();
11848 }
11849 mParallelBroadcasts.add(r);
11850 }
11851 }
11852
11853 return sticky;
11854 }
11855 }
11856
11857 public void unregisterReceiver(IIntentReceiver receiver) {
11858 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11859
11860 boolean doNext = false;
11861
11862 synchronized(this) {
11863 ReceiverList rl
11864 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11865 if (rl != null) {
11866 if (rl.curBroadcast != null) {
11867 BroadcastRecord r = rl.curBroadcast;
11868 doNext = finishReceiverLocked(
11869 receiver.asBinder(), r.resultCode, r.resultData,
11870 r.resultExtras, r.resultAbort, true);
11871 }
11872
11873 if (rl.app != null) {
11874 rl.app.receivers.remove(rl);
11875 }
11876 removeReceiverLocked(rl);
11877 if (rl.linkedToDeath) {
11878 rl.linkedToDeath = false;
11879 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11880 }
11881 }
11882 }
11883
11884 if (!doNext) {
11885 return;
11886 }
11887
11888 final long origId = Binder.clearCallingIdentity();
11889 processNextBroadcast(false);
11890 trimApplications();
11891 Binder.restoreCallingIdentity(origId);
11892 }
11893
11894 void removeReceiverLocked(ReceiverList rl) {
11895 mRegisteredReceivers.remove(rl.receiver.asBinder());
11896 int N = rl.size();
11897 for (int i=0; i<N; i++) {
11898 mReceiverResolver.removeFilter(rl.get(i));
11899 }
11900 }
11901
11902 private final int broadcastIntentLocked(ProcessRecord callerApp,
11903 String callerPackage, Intent intent, String resolvedType,
11904 IIntentReceiver resultTo, int resultCode, String resultData,
11905 Bundle map, String requiredPermission,
11906 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11907 intent = new Intent(intent);
11908
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011909 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011910 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11911 + " ordered=" + ordered);
11912 if ((resultTo != null) && !ordered) {
11913 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11914 }
11915
11916 // Handle special intents: if this broadcast is from the package
11917 // manager about a package being removed, we need to remove all of
11918 // its activities from the history stack.
11919 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11920 intent.getAction());
11921 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11922 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080011923 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011924 || uidRemoved) {
11925 if (checkComponentPermission(
11926 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11927 callingPid, callingUid, -1)
11928 == PackageManager.PERMISSION_GRANTED) {
11929 if (uidRemoved) {
11930 final Bundle intentExtras = intent.getExtras();
11931 final int uid = intentExtras != null
11932 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11933 if (uid >= 0) {
11934 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11935 synchronized (bs) {
11936 bs.removeUidStatsLocked(uid);
11937 }
11938 }
11939 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011940 // If resources are unvailble just force stop all
11941 // those packages and flush the attribute cache as well.
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080011942 if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011943 String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
11944 if (list != null && (list.length > 0)) {
11945 for (String pkg : list) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080011946 forceStopPackageLocked(pkg, -1, false, true, true);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011947 }
11948 }
11949 } else {
11950 Uri data = intent.getData();
11951 String ssp;
11952 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11953 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11954 forceStopPackageLocked(ssp,
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080011955 intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011956 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011957 }
11958 }
11959 }
11960 } else {
11961 String msg = "Permission Denial: " + intent.getAction()
11962 + " broadcast from " + callerPackage + " (pid=" + callingPid
11963 + ", uid=" + callingUid + ")"
11964 + " requires "
11965 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11966 Log.w(TAG, msg);
11967 throw new SecurityException(msg);
11968 }
11969 }
11970
11971 /*
11972 * If this is the time zone changed action, queue up a message that will reset the timezone
11973 * of all currently running processes. This message will get queued up before the broadcast
11974 * happens.
11975 */
11976 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11977 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11978 }
11979
Dianne Hackborn854060af2009-07-09 18:14:31 -070011980 /*
11981 * Prevent non-system code (defined here to be non-persistent
11982 * processes) from sending protected broadcasts.
11983 */
11984 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11985 || callingUid == Process.SHELL_UID || callingUid == 0) {
11986 // Always okay.
11987 } else if (callerApp == null || !callerApp.persistent) {
11988 try {
11989 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11990 intent.getAction())) {
11991 String msg = "Permission Denial: not allowed to send broadcast "
11992 + intent.getAction() + " from pid="
11993 + callingPid + ", uid=" + callingUid;
11994 Log.w(TAG, msg);
11995 throw new SecurityException(msg);
11996 }
11997 } catch (RemoteException e) {
11998 Log.w(TAG, "Remote exception", e);
11999 return BROADCAST_SUCCESS;
12000 }
12001 }
12002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012003 // Add to the sticky list if requested.
12004 if (sticky) {
12005 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
12006 callingPid, callingUid)
12007 != PackageManager.PERMISSION_GRANTED) {
12008 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
12009 + callingPid + ", uid=" + callingUid
12010 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12011 Log.w(TAG, msg);
12012 throw new SecurityException(msg);
12013 }
12014 if (requiredPermission != null) {
12015 Log.w(TAG, "Can't broadcast sticky intent " + intent
12016 + " and enforce permission " + requiredPermission);
12017 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
12018 }
12019 if (intent.getComponent() != null) {
12020 throw new SecurityException(
12021 "Sticky broadcasts can't target a specific component");
12022 }
12023 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12024 if (list == null) {
12025 list = new ArrayList<Intent>();
12026 mStickyBroadcasts.put(intent.getAction(), list);
12027 }
12028 int N = list.size();
12029 int i;
12030 for (i=0; i<N; i++) {
12031 if (intent.filterEquals(list.get(i))) {
12032 // This sticky already exists, replace it.
12033 list.set(i, new Intent(intent));
12034 break;
12035 }
12036 }
12037 if (i >= N) {
12038 list.add(new Intent(intent));
12039 }
12040 }
12041
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012042 // Figure out who all will receive this broadcast.
12043 List receivers = null;
12044 List<BroadcastFilter> registeredReceivers = null;
12045 try {
12046 if (intent.getComponent() != null) {
12047 // Broadcast is going to one specific receiver class...
12048 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012049 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012050 if (ai != null) {
12051 receivers = new ArrayList();
12052 ResolveInfo ri = new ResolveInfo();
12053 ri.activityInfo = ai;
12054 receivers.add(ri);
12055 }
12056 } else {
12057 // Need to resolve the intent to interested receivers...
12058 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12059 == 0) {
12060 receivers =
12061 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012062 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012063 }
Mihai Preda074edef2009-05-18 17:13:31 +020012064 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012065 }
12066 } catch (RemoteException ex) {
12067 // pm is in same process, this will never happen.
12068 }
12069
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012070 final boolean replacePending =
12071 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12072
12073 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12074 + " replacePending=" + replacePending);
12075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012076 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12077 if (!ordered && NR > 0) {
12078 // If we are not serializing this broadcast, then send the
12079 // registered receivers separately so they don't wait for the
12080 // components to be launched.
12081 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12082 callerPackage, callingPid, callingUid, requiredPermission,
12083 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012084 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012085 if (DEBUG_BROADCAST) Log.v(
12086 TAG, "Enqueueing parallel broadcast " + r
12087 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012088 boolean replaced = false;
12089 if (replacePending) {
12090 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12091 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12092 if (DEBUG_BROADCAST) Log.v(TAG,
12093 "***** DROPPING PARALLEL: " + intent);
12094 mParallelBroadcasts.set(i, r);
12095 replaced = true;
12096 break;
12097 }
12098 }
12099 }
12100 if (!replaced) {
12101 mParallelBroadcasts.add(r);
12102 scheduleBroadcastsLocked();
12103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012104 registeredReceivers = null;
12105 NR = 0;
12106 }
12107
12108 // Merge into one list.
12109 int ir = 0;
12110 if (receivers != null) {
12111 // A special case for PACKAGE_ADDED: do not allow the package
12112 // being added to see this broadcast. This prevents them from
12113 // using this as a back door to get run as soon as they are
12114 // installed. Maybe in the future we want to have a special install
12115 // broadcast or such for apps, but we'd like to deliberately make
12116 // this decision.
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012117 String skipPackages[] = null;
12118 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
12119 || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
12120 || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12121 Uri data = intent.getData();
12122 if (data != null) {
12123 String pkgName = data.getSchemeSpecificPart();
12124 if (pkgName != null) {
12125 skipPackages = new String[] { pkgName };
12126 }
12127 }
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080012128 } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012129 skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
The Android Open Source Project10592532009-03-18 17:39:46 -070012130 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012131 if (skipPackages != null && (skipPackages.length > 0)) {
12132 for (String skipPackage : skipPackages) {
12133 if (skipPackage != null) {
12134 int NT = receivers.size();
12135 for (int it=0; it<NT; it++) {
12136 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12137 if (curt.activityInfo.packageName.equals(skipPackage)) {
12138 receivers.remove(it);
12139 it--;
12140 NT--;
12141 }
12142 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012143 }
12144 }
12145 }
12146
12147 int NT = receivers != null ? receivers.size() : 0;
12148 int it = 0;
12149 ResolveInfo curt = null;
12150 BroadcastFilter curr = null;
12151 while (it < NT && ir < NR) {
12152 if (curt == null) {
12153 curt = (ResolveInfo)receivers.get(it);
12154 }
12155 if (curr == null) {
12156 curr = registeredReceivers.get(ir);
12157 }
12158 if (curr.getPriority() >= curt.priority) {
12159 // Insert this broadcast record into the final list.
12160 receivers.add(it, curr);
12161 ir++;
12162 curr = null;
12163 it++;
12164 NT++;
12165 } else {
12166 // Skip to the next ResolveInfo in the final list.
12167 it++;
12168 curt = null;
12169 }
12170 }
12171 }
12172 while (ir < NR) {
12173 if (receivers == null) {
12174 receivers = new ArrayList();
12175 }
12176 receivers.add(registeredReceivers.get(ir));
12177 ir++;
12178 }
12179
12180 if ((receivers != null && receivers.size() > 0)
12181 || resultTo != null) {
12182 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12183 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012184 receivers, resultTo, resultCode, resultData, map, ordered,
12185 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012186 if (DEBUG_BROADCAST) Log.v(
12187 TAG, "Enqueueing ordered broadcast " + r
12188 + ": prev had " + mOrderedBroadcasts.size());
12189 if (DEBUG_BROADCAST) {
12190 int seq = r.intent.getIntExtra("seq", -1);
12191 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12192 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012193 boolean replaced = false;
12194 if (replacePending) {
12195 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12196 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12197 if (DEBUG_BROADCAST) Log.v(TAG,
12198 "***** DROPPING ORDERED: " + intent);
12199 mOrderedBroadcasts.set(i, r);
12200 replaced = true;
12201 break;
12202 }
12203 }
12204 }
12205 if (!replaced) {
12206 mOrderedBroadcasts.add(r);
12207 scheduleBroadcastsLocked();
12208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012209 }
12210
12211 return BROADCAST_SUCCESS;
12212 }
12213
12214 public final int broadcastIntent(IApplicationThread caller,
12215 Intent intent, String resolvedType, IIntentReceiver resultTo,
12216 int resultCode, String resultData, Bundle map,
12217 String requiredPermission, boolean serialized, boolean sticky) {
12218 // Refuse possible leaked file descriptors
12219 if (intent != null && intent.hasFileDescriptors() == true) {
12220 throw new IllegalArgumentException("File descriptors passed in Intent");
12221 }
12222
12223 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012224 int flags = intent.getFlags();
12225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012226 if (!mSystemReady) {
12227 // if the caller really truly claims to know what they're doing, go
12228 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012229 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12230 intent = new Intent(intent);
12231 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12232 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12233 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12234 + " before boot completion");
12235 throw new IllegalStateException("Cannot broadcast before boot completed");
12236 }
12237 }
12238
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012239 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12240 throw new IllegalArgumentException(
12241 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12242 }
12243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012244 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12245 final int callingPid = Binder.getCallingPid();
12246 final int callingUid = Binder.getCallingUid();
12247 final long origId = Binder.clearCallingIdentity();
12248 int res = broadcastIntentLocked(callerApp,
12249 callerApp != null ? callerApp.info.packageName : null,
12250 intent, resolvedType, resultTo,
12251 resultCode, resultData, map, requiredPermission, serialized,
12252 sticky, callingPid, callingUid);
12253 Binder.restoreCallingIdentity(origId);
12254 return res;
12255 }
12256 }
12257
12258 int broadcastIntentInPackage(String packageName, int uid,
12259 Intent intent, String resolvedType, IIntentReceiver resultTo,
12260 int resultCode, String resultData, Bundle map,
12261 String requiredPermission, boolean serialized, boolean sticky) {
12262 synchronized(this) {
12263 final long origId = Binder.clearCallingIdentity();
12264 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12265 resultTo, resultCode, resultData, map, requiredPermission,
12266 serialized, sticky, -1, uid);
12267 Binder.restoreCallingIdentity(origId);
12268 return res;
12269 }
12270 }
12271
12272 public final void unbroadcastIntent(IApplicationThread caller,
12273 Intent intent) {
12274 // Refuse possible leaked file descriptors
12275 if (intent != null && intent.hasFileDescriptors() == true) {
12276 throw new IllegalArgumentException("File descriptors passed in Intent");
12277 }
12278
12279 synchronized(this) {
12280 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12281 != PackageManager.PERMISSION_GRANTED) {
12282 String msg = "Permission Denial: unbroadcastIntent() from pid="
12283 + Binder.getCallingPid()
12284 + ", uid=" + Binder.getCallingUid()
12285 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12286 Log.w(TAG, msg);
12287 throw new SecurityException(msg);
12288 }
12289 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12290 if (list != null) {
12291 int N = list.size();
12292 int i;
12293 for (i=0; i<N; i++) {
12294 if (intent.filterEquals(list.get(i))) {
12295 list.remove(i);
12296 break;
12297 }
12298 }
12299 }
12300 }
12301 }
12302
12303 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12304 String resultData, Bundle resultExtras, boolean resultAbort,
12305 boolean explicit) {
12306 if (mOrderedBroadcasts.size() == 0) {
12307 if (explicit) {
12308 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12309 }
12310 return false;
12311 }
12312 BroadcastRecord r = mOrderedBroadcasts.get(0);
12313 if (r.receiver == null) {
12314 if (explicit) {
12315 Log.w(TAG, "finishReceiver called but none active");
12316 }
12317 return false;
12318 }
12319 if (r.receiver != receiver) {
12320 Log.w(TAG, "finishReceiver called but active receiver is different");
12321 return false;
12322 }
12323 int state = r.state;
12324 r.state = r.IDLE;
12325 if (state == r.IDLE) {
12326 if (explicit) {
12327 Log.w(TAG, "finishReceiver called but state is IDLE");
12328 }
12329 }
12330 r.receiver = null;
12331 r.intent.setComponent(null);
12332 if (r.curApp != null) {
12333 r.curApp.curReceiver = null;
12334 }
12335 if (r.curFilter != null) {
12336 r.curFilter.receiverList.curBroadcast = null;
12337 }
12338 r.curFilter = null;
12339 r.curApp = null;
12340 r.curComponent = null;
12341 r.curReceiver = null;
12342 mPendingBroadcast = null;
12343
12344 r.resultCode = resultCode;
12345 r.resultData = resultData;
12346 r.resultExtras = resultExtras;
12347 r.resultAbort = resultAbort;
12348
12349 // We will process the next receiver right now if this is finishing
12350 // an app receiver (which is always asynchronous) or after we have
12351 // come back from calling a receiver.
12352 return state == BroadcastRecord.APP_RECEIVE
12353 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12354 }
12355
12356 public void finishReceiver(IBinder who, int resultCode, String resultData,
12357 Bundle resultExtras, boolean resultAbort) {
12358 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12359
12360 // Refuse possible leaked file descriptors
12361 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12362 throw new IllegalArgumentException("File descriptors passed in Bundle");
12363 }
12364
12365 boolean doNext;
12366
12367 final long origId = Binder.clearCallingIdentity();
12368
12369 synchronized(this) {
12370 doNext = finishReceiverLocked(
12371 who, resultCode, resultData, resultExtras, resultAbort, true);
12372 }
12373
12374 if (doNext) {
12375 processNextBroadcast(false);
12376 }
12377 trimApplications();
12378
12379 Binder.restoreCallingIdentity(origId);
12380 }
12381
12382 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12383 if (r.nextReceiver > 0) {
12384 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12385 if (curReceiver instanceof BroadcastFilter) {
12386 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012387 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012388 System.identityHashCode(r),
12389 r.intent.getAction(),
12390 r.nextReceiver - 1,
12391 System.identityHashCode(bf));
12392 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012393 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012394 System.identityHashCode(r),
12395 r.intent.getAction(),
12396 r.nextReceiver - 1,
12397 ((ResolveInfo)curReceiver).toString());
12398 }
12399 } else {
12400 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12401 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012402 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012403 System.identityHashCode(r),
12404 r.intent.getAction(),
12405 r.nextReceiver,
12406 "NONE");
12407 }
12408 }
12409
12410 private final void broadcastTimeout() {
12411 synchronized (this) {
12412 if (mOrderedBroadcasts.size() == 0) {
12413 return;
12414 }
12415 long now = SystemClock.uptimeMillis();
12416 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012417 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012418 if (DEBUG_BROADCAST) Log.v(TAG,
12419 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012420 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012421 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012422 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012423 return;
12424 }
12425
12426 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012427 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012428 r.anrCount++;
12429
12430 // Current receiver has passed its expiration date.
12431 if (r.nextReceiver <= 0) {
12432 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12433 return;
12434 }
12435
12436 ProcessRecord app = null;
12437
12438 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12439 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12440 logBroadcastReceiverDiscard(r);
12441 if (curReceiver instanceof BroadcastFilter) {
12442 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12443 if (bf.receiverList.pid != 0
12444 && bf.receiverList.pid != MY_PID) {
12445 synchronized (this.mPidsSelfLocked) {
12446 app = this.mPidsSelfLocked.get(
12447 bf.receiverList.pid);
12448 }
12449 }
12450 } else {
12451 app = r.curApp;
12452 }
12453
12454 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012455 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012456 }
12457
12458 if (mPendingBroadcast == r) {
12459 mPendingBroadcast = null;
12460 }
12461
12462 // Move on to the next receiver.
12463 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12464 r.resultExtras, r.resultAbort, true);
12465 scheduleBroadcastsLocked();
12466 }
12467 }
12468
12469 private final void processCurBroadcastLocked(BroadcastRecord r,
12470 ProcessRecord app) throws RemoteException {
12471 if (app.thread == null) {
12472 throw new RemoteException();
12473 }
12474 r.receiver = app.thread.asBinder();
12475 r.curApp = app;
12476 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012477 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012478
12479 // Tell the application to launch this receiver.
12480 r.intent.setComponent(r.curComponent);
12481
12482 boolean started = false;
12483 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012484 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012485 "Delivering to component " + r.curComponent
12486 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012487 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012488 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12489 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12490 started = true;
12491 } finally {
12492 if (!started) {
12493 r.receiver = null;
12494 r.curApp = null;
12495 app.curReceiver = null;
12496 }
12497 }
12498
12499 }
12500
12501 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012502 Intent intent, int resultCode, String data, Bundle extras,
12503 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012504 if (app != null && app.thread != null) {
12505 // If we have an app thread, do the call through that so it is
12506 // correctly ordered with other one-way calls.
12507 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012508 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012509 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012510 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012511 }
12512 }
12513
12514 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12515 BroadcastFilter filter, boolean ordered) {
12516 boolean skip = false;
12517 if (filter.requiredPermission != null) {
12518 int perm = checkComponentPermission(filter.requiredPermission,
12519 r.callingPid, r.callingUid, -1);
12520 if (perm != PackageManager.PERMISSION_GRANTED) {
12521 Log.w(TAG, "Permission Denial: broadcasting "
12522 + r.intent.toString()
12523 + " from " + r.callerPackage + " (pid="
12524 + r.callingPid + ", uid=" + r.callingUid + ")"
12525 + " requires " + filter.requiredPermission
12526 + " due to registered receiver " + filter);
12527 skip = true;
12528 }
12529 }
12530 if (r.requiredPermission != null) {
12531 int perm = checkComponentPermission(r.requiredPermission,
12532 filter.receiverList.pid, filter.receiverList.uid, -1);
12533 if (perm != PackageManager.PERMISSION_GRANTED) {
12534 Log.w(TAG, "Permission Denial: receiving "
12535 + r.intent.toString()
12536 + " to " + filter.receiverList.app
12537 + " (pid=" + filter.receiverList.pid
12538 + ", uid=" + filter.receiverList.uid + ")"
12539 + " requires " + r.requiredPermission
12540 + " due to sender " + r.callerPackage
12541 + " (uid " + r.callingUid + ")");
12542 skip = true;
12543 }
12544 }
12545
12546 if (!skip) {
12547 // If this is not being sent as an ordered broadcast, then we
12548 // don't want to touch the fields that keep track of the current
12549 // state of ordered broadcasts.
12550 if (ordered) {
12551 r.receiver = filter.receiverList.receiver.asBinder();
12552 r.curFilter = filter;
12553 filter.receiverList.curBroadcast = r;
12554 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012555 if (filter.receiverList.app != null) {
12556 // Bump hosting application to no longer be in background
12557 // scheduling class. Note that we can't do that if there
12558 // isn't an app... but we can only be in that case for
12559 // things that directly call the IActivityManager API, which
12560 // are already core system stuff so don't matter for this.
12561 r.curApp = filter.receiverList.app;
12562 filter.receiverList.app.curReceiver = r;
12563 updateOomAdjLocked();
12564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012565 }
12566 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012567 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012568 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012569 Log.i(TAG, "Delivering to " + filter.receiverList.app
12570 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012571 }
12572 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12573 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012574 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012575 if (ordered) {
12576 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12577 }
12578 } catch (RemoteException e) {
12579 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12580 if (ordered) {
12581 r.receiver = null;
12582 r.curFilter = null;
12583 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012584 if (filter.receiverList.app != null) {
12585 filter.receiverList.app.curReceiver = null;
12586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012587 }
12588 }
12589 }
12590 }
12591
Dianne Hackborn12527f92009-11-11 17:39:50 -080012592 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12593 if (r.callingUid < 0) {
12594 // This was from a registerReceiver() call; ignore it.
12595 return;
12596 }
12597 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12598 MAX_BROADCAST_HISTORY-1);
12599 r.finishTime = SystemClock.uptimeMillis();
12600 mBroadcastHistory[0] = r;
12601 }
12602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012603 private final void processNextBroadcast(boolean fromMsg) {
12604 synchronized(this) {
12605 BroadcastRecord r;
12606
12607 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12608 + mParallelBroadcasts.size() + " broadcasts, "
12609 + mOrderedBroadcasts.size() + " serialized broadcasts");
12610
12611 updateCpuStats();
12612
12613 if (fromMsg) {
12614 mBroadcastsScheduled = false;
12615 }
12616
12617 // First, deliver any non-serialized broadcasts right away.
12618 while (mParallelBroadcasts.size() > 0) {
12619 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012620 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012621 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012622 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12623 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012624 for (int i=0; i<N; i++) {
12625 Object target = r.receivers.get(i);
12626 if (DEBUG_BROADCAST) Log.v(TAG,
12627 "Delivering non-serialized to registered "
12628 + target + ": " + r);
12629 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12630 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012631 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012632 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12633 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012634 }
12635
12636 // Now take care of the next serialized one...
12637
12638 // If we are waiting for a process to come up to handle the next
12639 // broadcast, then do nothing at this point. Just in case, we
12640 // check that the process we're waiting for still exists.
12641 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012642 if (DEBUG_BROADCAST_LIGHT) {
12643 Log.v(TAG, "processNextBroadcast: waiting for "
12644 + mPendingBroadcast.curApp);
12645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012646
12647 boolean isDead;
12648 synchronized (mPidsSelfLocked) {
12649 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12650 }
12651 if (!isDead) {
12652 // It's still alive, so keep waiting
12653 return;
12654 } else {
12655 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12656 + " died before responding to broadcast");
12657 mPendingBroadcast = null;
12658 }
12659 }
12660
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012661 boolean looped = false;
12662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012663 do {
12664 if (mOrderedBroadcasts.size() == 0) {
12665 // No more broadcasts pending, so all done!
12666 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012667 if (looped) {
12668 // If we had finished the last ordered broadcast, then
12669 // make sure all processes have correct oom and sched
12670 // adjustments.
12671 updateOomAdjLocked();
12672 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012673 return;
12674 }
12675 r = mOrderedBroadcasts.get(0);
12676 boolean forceReceive = false;
12677
12678 // Ensure that even if something goes awry with the timeout
12679 // detection, we catch "hung" broadcasts here, discard them,
12680 // and continue to make progress.
12681 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12682 long now = SystemClock.uptimeMillis();
12683 if (r.dispatchTime > 0) {
12684 if ((numReceivers > 0) &&
12685 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12686 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12687 + " now=" + now
12688 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012689 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012690 + " intent=" + r.intent
12691 + " numReceivers=" + numReceivers
12692 + " nextReceiver=" + r.nextReceiver
12693 + " state=" + r.state);
12694 broadcastTimeout(); // forcibly finish this broadcast
12695 forceReceive = true;
12696 r.state = BroadcastRecord.IDLE;
12697 }
12698 }
12699
12700 if (r.state != BroadcastRecord.IDLE) {
12701 if (DEBUG_BROADCAST) Log.d(TAG,
12702 "processNextBroadcast() called when not idle (state="
12703 + r.state + ")");
12704 return;
12705 }
12706
12707 if (r.receivers == null || r.nextReceiver >= numReceivers
12708 || r.resultAbort || forceReceive) {
12709 // No more receivers for this broadcast! Send the final
12710 // result if requested...
12711 if (r.resultTo != null) {
12712 try {
12713 if (DEBUG_BROADCAST) {
12714 int seq = r.intent.getIntExtra("seq", -1);
12715 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12716 + " seq=" + seq + " app=" + r.callerApp);
12717 }
12718 performReceive(r.callerApp, r.resultTo,
12719 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012720 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012721 } catch (RemoteException e) {
12722 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12723 }
12724 }
12725
12726 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12727 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12728
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012729 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12730 + r);
12731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012732 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012733 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012734 mOrderedBroadcasts.remove(0);
12735 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012736 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012737 continue;
12738 }
12739 } while (r == null);
12740
12741 // Get the next receiver...
12742 int recIdx = r.nextReceiver++;
12743
12744 // Keep track of when this receiver started, and make sure there
12745 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012746 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012747 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012748 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012749
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012750 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12751 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012752 if (DEBUG_BROADCAST) Log.v(TAG,
12753 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012754 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012755 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012756 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012757 }
12758
12759 Object nextReceiver = r.receivers.get(recIdx);
12760 if (nextReceiver instanceof BroadcastFilter) {
12761 // Simple case: this is a registered receiver who gets
12762 // a direct call.
12763 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12764 if (DEBUG_BROADCAST) Log.v(TAG,
12765 "Delivering serialized to registered "
12766 + filter + ": " + r);
12767 deliverToRegisteredReceiver(r, filter, r.ordered);
12768 if (r.receiver == null || !r.ordered) {
12769 // The receiver has already finished, so schedule to
12770 // process the next one.
12771 r.state = BroadcastRecord.IDLE;
12772 scheduleBroadcastsLocked();
12773 }
12774 return;
12775 }
12776
12777 // Hard case: need to instantiate the receiver, possibly
12778 // starting its application process to host it.
12779
12780 ResolveInfo info =
12781 (ResolveInfo)nextReceiver;
12782
12783 boolean skip = false;
12784 int perm = checkComponentPermission(info.activityInfo.permission,
12785 r.callingPid, r.callingUid,
12786 info.activityInfo.exported
12787 ? -1 : info.activityInfo.applicationInfo.uid);
12788 if (perm != PackageManager.PERMISSION_GRANTED) {
12789 Log.w(TAG, "Permission Denial: broadcasting "
12790 + r.intent.toString()
12791 + " from " + r.callerPackage + " (pid=" + r.callingPid
12792 + ", uid=" + r.callingUid + ")"
12793 + " requires " + info.activityInfo.permission
12794 + " due to receiver " + info.activityInfo.packageName
12795 + "/" + info.activityInfo.name);
12796 skip = true;
12797 }
12798 if (r.callingUid != Process.SYSTEM_UID &&
12799 r.requiredPermission != null) {
12800 try {
12801 perm = ActivityThread.getPackageManager().
12802 checkPermission(r.requiredPermission,
12803 info.activityInfo.applicationInfo.packageName);
12804 } catch (RemoteException e) {
12805 perm = PackageManager.PERMISSION_DENIED;
12806 }
12807 if (perm != PackageManager.PERMISSION_GRANTED) {
12808 Log.w(TAG, "Permission Denial: receiving "
12809 + r.intent + " to "
12810 + info.activityInfo.applicationInfo.packageName
12811 + " requires " + r.requiredPermission
12812 + " due to sender " + r.callerPackage
12813 + " (uid " + r.callingUid + ")");
12814 skip = true;
12815 }
12816 }
12817 if (r.curApp != null && r.curApp.crashing) {
12818 // If the target process is crashing, just skip it.
12819 skip = true;
12820 }
12821
12822 if (skip) {
12823 r.receiver = null;
12824 r.curFilter = null;
12825 r.state = BroadcastRecord.IDLE;
12826 scheduleBroadcastsLocked();
12827 return;
12828 }
12829
12830 r.state = BroadcastRecord.APP_RECEIVE;
12831 String targetProcess = info.activityInfo.processName;
12832 r.curComponent = new ComponentName(
12833 info.activityInfo.applicationInfo.packageName,
12834 info.activityInfo.name);
12835 r.curReceiver = info.activityInfo;
12836
12837 // Is this receiver's application already running?
12838 ProcessRecord app = getProcessRecordLocked(targetProcess,
12839 info.activityInfo.applicationInfo.uid);
12840 if (app != null && app.thread != null) {
12841 try {
12842 processCurBroadcastLocked(r, app);
12843 return;
12844 } catch (RemoteException e) {
12845 Log.w(TAG, "Exception when sending broadcast to "
12846 + r.curComponent, e);
12847 }
12848
12849 // If a dead object exception was thrown -- fall through to
12850 // restart the application.
12851 }
12852
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012853 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012854 if ((r.curApp=startProcessLocked(targetProcess,
12855 info.activityInfo.applicationInfo, true,
12856 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012857 "broadcast", r.curComponent,
12858 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12859 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012860 // Ah, this recipient is unavailable. Finish it if necessary,
12861 // and mark the broadcast record as ready for the next.
12862 Log.w(TAG, "Unable to launch app "
12863 + info.activityInfo.applicationInfo.packageName + "/"
12864 + info.activityInfo.applicationInfo.uid + " for broadcast "
12865 + r.intent + ": process is bad");
12866 logBroadcastReceiverDiscard(r);
12867 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12868 r.resultExtras, r.resultAbort, true);
12869 scheduleBroadcastsLocked();
12870 r.state = BroadcastRecord.IDLE;
12871 return;
12872 }
12873
12874 mPendingBroadcast = r;
12875 }
12876 }
12877
12878 // =========================================================
12879 // INSTRUMENTATION
12880 // =========================================================
12881
12882 public boolean startInstrumentation(ComponentName className,
12883 String profileFile, int flags, Bundle arguments,
12884 IInstrumentationWatcher watcher) {
12885 // Refuse possible leaked file descriptors
12886 if (arguments != null && arguments.hasFileDescriptors()) {
12887 throw new IllegalArgumentException("File descriptors passed in Bundle");
12888 }
12889
12890 synchronized(this) {
12891 InstrumentationInfo ii = null;
12892 ApplicationInfo ai = null;
12893 try {
12894 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012895 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012896 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012897 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012898 } catch (PackageManager.NameNotFoundException e) {
12899 }
12900 if (ii == null) {
12901 reportStartInstrumentationFailure(watcher, className,
12902 "Unable to find instrumentation info for: " + className);
12903 return false;
12904 }
12905 if (ai == null) {
12906 reportStartInstrumentationFailure(watcher, className,
12907 "Unable to find instrumentation target package: " + ii.targetPackage);
12908 return false;
12909 }
12910
12911 int match = mContext.getPackageManager().checkSignatures(
12912 ii.targetPackage, ii.packageName);
12913 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12914 String msg = "Permission Denial: starting instrumentation "
12915 + className + " from pid="
12916 + Binder.getCallingPid()
12917 + ", uid=" + Binder.getCallingPid()
12918 + " not allowed because package " + ii.packageName
12919 + " does not have a signature matching the target "
12920 + ii.targetPackage;
12921 reportStartInstrumentationFailure(watcher, className, msg);
12922 throw new SecurityException(msg);
12923 }
12924
12925 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080012926 forceStopPackageLocked(ii.targetPackage, -1, true, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012927 ProcessRecord app = addAppLocked(ai);
12928 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012929 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012930 app.instrumentationProfileFile = profileFile;
12931 app.instrumentationArguments = arguments;
12932 app.instrumentationWatcher = watcher;
12933 app.instrumentationResultClass = className;
12934 Binder.restoreCallingIdentity(origId);
12935 }
12936
12937 return true;
12938 }
12939
12940 /**
12941 * Report errors that occur while attempting to start Instrumentation. Always writes the
12942 * error to the logs, but if somebody is watching, send the report there too. This enables
12943 * the "am" command to report errors with more information.
12944 *
12945 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12946 * @param cn The component name of the instrumentation.
12947 * @param report The error report.
12948 */
12949 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12950 ComponentName cn, String report) {
12951 Log.w(TAG, report);
12952 try {
12953 if (watcher != null) {
12954 Bundle results = new Bundle();
12955 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12956 results.putString("Error", report);
12957 watcher.instrumentationStatus(cn, -1, results);
12958 }
12959 } catch (RemoteException e) {
12960 Log.w(TAG, e);
12961 }
12962 }
12963
12964 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12965 if (app.instrumentationWatcher != null) {
12966 try {
12967 // NOTE: IInstrumentationWatcher *must* be oneway here
12968 app.instrumentationWatcher.instrumentationFinished(
12969 app.instrumentationClass,
12970 resultCode,
12971 results);
12972 } catch (RemoteException e) {
12973 }
12974 }
12975 app.instrumentationWatcher = null;
12976 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012977 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012978 app.instrumentationProfileFile = null;
12979 app.instrumentationArguments = null;
12980
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080012981 forceStopPackageLocked(app.processName, -1, false, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012982 }
12983
12984 public void finishInstrumentation(IApplicationThread target,
12985 int resultCode, Bundle results) {
12986 // Refuse possible leaked file descriptors
12987 if (results != null && results.hasFileDescriptors()) {
12988 throw new IllegalArgumentException("File descriptors passed in Intent");
12989 }
12990
12991 synchronized(this) {
12992 ProcessRecord app = getRecordForAppLocked(target);
12993 if (app == null) {
12994 Log.w(TAG, "finishInstrumentation: no app for " + target);
12995 return;
12996 }
12997 final long origId = Binder.clearCallingIdentity();
12998 finishInstrumentationLocked(app, resultCode, results);
12999 Binder.restoreCallingIdentity(origId);
13000 }
13001 }
13002
13003 // =========================================================
13004 // CONFIGURATION
13005 // =========================================================
13006
13007 public ConfigurationInfo getDeviceConfigurationInfo() {
13008 ConfigurationInfo config = new ConfigurationInfo();
13009 synchronized (this) {
13010 config.reqTouchScreen = mConfiguration.touchscreen;
13011 config.reqKeyboardType = mConfiguration.keyboard;
13012 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013013 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
13014 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013015 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
13016 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013017 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
13018 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013019 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
13020 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070013021 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013022 }
13023 return config;
13024 }
13025
13026 public Configuration getConfiguration() {
13027 Configuration ci;
13028 synchronized(this) {
13029 ci = new Configuration(mConfiguration);
13030 }
13031 return ci;
13032 }
13033
13034 public void updateConfiguration(Configuration values) {
13035 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13036 "updateConfiguration()");
13037
13038 synchronized(this) {
13039 if (values == null && mWindowManager != null) {
13040 // sentinel: fetch the current configuration from the window manager
13041 values = mWindowManager.computeNewConfiguration();
13042 }
13043
13044 final long origId = Binder.clearCallingIdentity();
13045 updateConfigurationLocked(values, null);
13046 Binder.restoreCallingIdentity(origId);
13047 }
13048 }
13049
13050 /**
13051 * Do either or both things: (1) change the current configuration, and (2)
13052 * make sure the given activity is running with the (now) current
13053 * configuration. Returns true if the activity has been left running, or
13054 * false if <var>starting</var> is being destroyed to match the new
13055 * configuration.
13056 */
13057 public boolean updateConfigurationLocked(Configuration values,
13058 HistoryRecord starting) {
13059 int changes = 0;
13060
13061 boolean kept = true;
13062
13063 if (values != null) {
13064 Configuration newConfig = new Configuration(mConfiguration);
13065 changes = newConfig.updateFrom(values);
13066 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013067 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013068 Log.i(TAG, "Updating configuration to: " + values);
13069 }
13070
Doug Zongker2bec3d42009-12-04 12:52:44 -080013071 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013072
13073 if (values.locale != null) {
13074 saveLocaleLocked(values.locale,
13075 !values.locale.equals(mConfiguration.locale),
13076 values.userSetLocale);
13077 }
13078
Dianne Hackborne36d6e22010-02-17 19:46:25 -080013079 mConfigurationSeq++;
13080 if (mConfigurationSeq <= 0) {
13081 mConfigurationSeq = 1;
13082 }
13083 newConfig.seq = mConfigurationSeq;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013084 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013085 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013086
13087 AttributeCache ac = AttributeCache.instance();
13088 if (ac != null) {
13089 ac.updateConfiguration(mConfiguration);
13090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013091
13092 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13093 msg.obj = new Configuration(mConfiguration);
13094 mHandler.sendMessage(msg);
13095
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013096 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13097 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013098 try {
13099 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013100 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13101 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013102 app.thread.scheduleConfigurationChanged(mConfiguration);
13103 }
13104 } catch (Exception e) {
13105 }
13106 }
13107 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013108 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13109 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013110 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13111 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013112 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13113 broadcastIntentLocked(null, null,
13114 new Intent(Intent.ACTION_LOCALE_CHANGED),
13115 null, null, 0, null, null,
13116 null, false, false, MY_PID, Process.SYSTEM_UID);
13117 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013118 }
13119 }
13120
13121 if (changes != 0 && starting == null) {
13122 // If the configuration changed, and the caller is not already
13123 // in the process of starting an activity, then find the top
13124 // activity to check if its configuration needs to change.
13125 starting = topRunningActivityLocked(null);
13126 }
13127
13128 if (starting != null) {
13129 kept = ensureActivityConfigurationLocked(starting, changes);
13130 if (kept) {
13131 // If this didn't result in the starting activity being
13132 // destroyed, then we need to make sure at this point that all
13133 // other activities are made visible.
13134 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13135 + ", ensuring others are correct.");
13136 ensureActivitiesVisibleLocked(starting, changes);
13137 }
13138 }
13139
Dianne Hackborne36d6e22010-02-17 19:46:25 -080013140 if (values != null && mWindowManager != null) {
13141 mWindowManager.setNewConfiguration(mConfiguration);
13142 }
13143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013144 return kept;
13145 }
13146
13147 private final boolean relaunchActivityLocked(HistoryRecord r,
13148 int changes, boolean andResume) {
13149 List<ResultInfo> results = null;
13150 List<Intent> newIntents = null;
13151 if (andResume) {
13152 results = r.results;
13153 newIntents = r.newIntents;
13154 }
13155 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13156 + " with results=" + results + " newIntents=" + newIntents
13157 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013158 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13159 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013160 r.task.taskId, r.shortComponentName);
13161
13162 r.startFreezingScreenLocked(r.app, 0);
13163
13164 try {
13165 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13166 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013167 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013168 // Note: don't need to call pauseIfSleepingLocked() here, because
13169 // the caller will only pass in 'andResume' if this activity is
13170 // currently resumed, which implies we aren't sleeping.
13171 } catch (RemoteException e) {
13172 return false;
13173 }
13174
13175 if (andResume) {
13176 r.results = null;
13177 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013178 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013179 }
13180
13181 return true;
13182 }
13183
13184 /**
13185 * Make sure the given activity matches the current configuration. Returns
13186 * false if the activity had to be destroyed. Returns true if the
13187 * configuration is the same, or the activity will remain running as-is
13188 * for whatever reason. Ensures the HistoryRecord is updated with the
13189 * correct configuration and all other bookkeeping is handled.
13190 */
13191 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13192 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013193 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13194 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013195
13196 // Short circuit: if the two configurations are the exact same
13197 // object (the common case), then there is nothing to do.
13198 Configuration newConfig = mConfiguration;
13199 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013200 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13201 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013202 return true;
13203 }
13204
13205 // We don't worry about activities that are finishing.
13206 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013207 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013208 "Configuration doesn't matter in finishing " + r);
13209 r.stopFreezingScreenLocked(false);
13210 return true;
13211 }
13212
13213 // Okay we now are going to make this activity have the new config.
13214 // But then we need to figure out how it needs to deal with that.
13215 Configuration oldConfig = r.configuration;
13216 r.configuration = newConfig;
13217
13218 // If the activity isn't currently running, just leave the new
13219 // configuration and it will pick that up next time it starts.
13220 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013221 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013222 "Configuration doesn't matter not running " + r);
13223 r.stopFreezingScreenLocked(false);
13224 return true;
13225 }
13226
13227 // If the activity isn't persistent, there is a chance we will
13228 // need to restart it.
13229 if (!r.persistent) {
13230
13231 // Figure out what has changed between the two configurations.
13232 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013233 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13234 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013235 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013236 + Integer.toHexString(r.info.configChanges)
13237 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013238 }
13239 if ((changes&(~r.info.configChanges)) != 0) {
13240 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13241 r.configChangeFlags |= changes;
13242 r.startFreezingScreenLocked(r.app, globalChanges);
13243 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013244 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13245 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013246 destroyActivityLocked(r, true);
13247 } else if (r.state == ActivityState.PAUSING) {
13248 // A little annoying: we are waiting for this activity to
13249 // finish pausing. Let's not do anything now, but just
13250 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013251 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13252 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013253 r.configDestroy = true;
13254 return true;
13255 } else if (r.state == ActivityState.RESUMED) {
13256 // Try to optimize this case: the configuration is changing
13257 // and we need to restart the top, resumed activity.
13258 // Instead of doing the normal handshaking, just say
13259 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013260 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13261 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013262 relaunchActivityLocked(r, r.configChangeFlags, true);
13263 r.configChangeFlags = 0;
13264 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013265 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13266 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013267 relaunchActivityLocked(r, r.configChangeFlags, false);
13268 r.configChangeFlags = 0;
13269 }
13270
13271 // All done... tell the caller we weren't able to keep this
13272 // activity around.
13273 return false;
13274 }
13275 }
13276
13277 // Default case: the activity can handle this new configuration, so
13278 // hand it over. Note that we don't need to give it the new
13279 // configuration, since we always send configuration changes to all
13280 // process when they happen so it can just use whatever configuration
13281 // it last got.
13282 if (r.app != null && r.app.thread != null) {
13283 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013284 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013285 r.app.thread.scheduleActivityConfigurationChanged(r);
13286 } catch (RemoteException e) {
13287 // If process died, whatever.
13288 }
13289 }
13290 r.stopFreezingScreenLocked(false);
13291
13292 return true;
13293 }
13294
13295 /**
13296 * Save the locale. You must be inside a synchronized (this) block.
13297 */
13298 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13299 if(isDiff) {
13300 SystemProperties.set("user.language", l.getLanguage());
13301 SystemProperties.set("user.region", l.getCountry());
13302 }
13303
13304 if(isPersist) {
13305 SystemProperties.set("persist.sys.language", l.getLanguage());
13306 SystemProperties.set("persist.sys.country", l.getCountry());
13307 SystemProperties.set("persist.sys.localevar", l.getVariant());
13308 }
13309 }
13310
13311 // =========================================================
13312 // LIFETIME MANAGEMENT
13313 // =========================================================
13314
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013315 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13316 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013317 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013318 // This adjustment has already been computed. If we are calling
13319 // from the top, we may have already computed our adjustment with
13320 // an earlier hidden adjustment that isn't really for us... if
13321 // so, use the new hidden adjustment.
13322 if (!recursed && app.hidden) {
13323 app.curAdj = hiddenAdj;
13324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013325 return app.curAdj;
13326 }
13327
13328 if (app.thread == null) {
13329 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013330 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013331 return (app.curAdj=EMPTY_APP_ADJ);
13332 }
13333
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013334 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13335 // The max adjustment doesn't allow this app to be anything
13336 // below foreground, so it is not worth doing work for it.
13337 app.adjType = "fixed";
13338 app.adjSeq = mAdjSeq;
13339 app.curRawAdj = app.maxAdj;
13340 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13341 return (app.curAdj=app.maxAdj);
13342 }
13343
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013344 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013345 app.adjSource = null;
13346 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013347 app.empty = false;
13348 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013349
The Android Open Source Project4df24232009-03-05 14:34:35 -080013350 // Determine the importance of the process, starting with most
13351 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013352 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013353 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013354 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013355 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013356 // The last app on the list is the foreground app.
13357 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013358 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013359 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013360 } else if (app.instrumentationClass != null) {
13361 // Don't want to kill running instrumentation.
13362 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013363 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013364 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013365 } else if (app.persistentActivities > 0) {
13366 // Special persistent activities... shouldn't be used these days.
13367 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013368 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013369 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013370 } else if (app.curReceiver != null ||
13371 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13372 // An app that is currently receiving a broadcast also
13373 // counts as being in the foreground.
13374 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013375 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013376 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013377 } else if (app.executingServices.size() > 0) {
13378 // An app that is currently executing a service callback also
13379 // counts as being in the foreground.
13380 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013381 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013382 app.adjType = "exec-service";
13383 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013384 // The user is aware of this app, so make it visible.
13385 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013386 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013387 app.adjType = "foreground-service";
13388 } else if (app.forcingToForeground != null) {
13389 // The user is aware of this app, so make it visible.
13390 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013391 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013392 app.adjType = "force-foreground";
13393 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013394 } else if (app == mHomeProcess) {
13395 // This process is hosting what we currently consider to be the
13396 // home app, so we don't want to let it go into the background.
13397 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013398 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013399 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013400 } else if ((N=app.activities.size()) != 0) {
13401 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013402 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013403 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013404 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013405 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013406 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013407 for (int j=0; j<N; j++) {
13408 if (((HistoryRecord)app.activities.get(j)).visible) {
13409 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013410 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013411 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013412 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013413 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013414 break;
13415 }
13416 }
13417 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013418 // A very not-needed process. If this is lower in the lru list,
13419 // we will push it in to the empty bucket.
13420 app.hidden = true;
13421 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013422 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013423 adj = hiddenAdj;
13424 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013425 }
13426
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013427 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13428
The Android Open Source Project4df24232009-03-05 14:34:35 -080013429 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013430 // there are applications dependent on our services or providers, but
13431 // this gives us a baseline and makes sure we don't get into an
13432 // infinite recursion.
13433 app.adjSeq = mAdjSeq;
13434 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013435
Christopher Tate6fa95972009-06-05 18:43:55 -070013436 if (mBackupTarget != null && app == mBackupTarget.app) {
13437 // If possible we want to avoid killing apps while they're being backed up
13438 if (adj > BACKUP_APP_ADJ) {
13439 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13440 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013441 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013442 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013443 }
13444 }
13445
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013446 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13447 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013448 final long now = SystemClock.uptimeMillis();
13449 // This process is more important if the top activity is
13450 // bound to the service.
13451 Iterator jt = app.services.iterator();
13452 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13453 ServiceRecord s = (ServiceRecord)jt.next();
13454 if (s.startRequested) {
13455 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13456 // This service has seen some activity within
13457 // recent memory, so we will keep its process ahead
13458 // of the background processes.
13459 if (adj > SECONDARY_SERVER_ADJ) {
13460 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013461 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013462 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013463 }
13464 }
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013465 // If we have let the service slide into the background
13466 // state, still have some text describing what it is doing
13467 // even though the service no longer has an impact.
13468 if (adj > SECONDARY_SERVER_ADJ) {
13469 app.adjType = "started-bg-services";
13470 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013471 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013472 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13473 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013474 Iterator<ConnectionRecord> kt
13475 = s.connections.values().iterator();
13476 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13477 // XXX should compute this based on the max of
13478 // all connected clients.
13479 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013480 if (cr.binding.client == app) {
13481 // Binding to ourself is not interesting.
13482 continue;
13483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013484 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13485 ProcessRecord client = cr.binding.client;
13486 int myHiddenAdj = hiddenAdj;
13487 if (myHiddenAdj > client.hiddenAdj) {
13488 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13489 myHiddenAdj = client.hiddenAdj;
13490 } else {
13491 myHiddenAdj = VISIBLE_APP_ADJ;
13492 }
13493 }
13494 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013495 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013496 if (adj > clientAdj) {
13497 adj = clientAdj > VISIBLE_APP_ADJ
13498 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013499 if (!client.hidden) {
13500 app.hidden = false;
13501 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013502 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013503 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13504 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013505 app.adjSource = cr.binding.client;
13506 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013507 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013508 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13509 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13510 schedGroup = Process.THREAD_GROUP_DEFAULT;
13511 }
13512 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013513 }
13514 HistoryRecord a = cr.activity;
13515 //if (a != null) {
13516 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13517 //}
13518 if (a != null && adj > FOREGROUND_APP_ADJ &&
13519 (a.state == ActivityState.RESUMED
13520 || a.state == ActivityState.PAUSING)) {
13521 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013522 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013523 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013524 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013525 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13526 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013527 app.adjSource = a;
13528 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013529 }
13530 }
13531 }
13532 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013533
13534 // Finally, f this process has active services running in it, we
13535 // would like to avoid killing it unless it would prevent the current
13536 // application from running. By default we put the process in
13537 // with the rest of the background processes; as we scan through
13538 // its services we may bump it up from there.
13539 if (adj > hiddenAdj) {
13540 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013541 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013542 app.adjType = "bg-services";
13543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013544 }
13545
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013546 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13547 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013548 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013549 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13550 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013551 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13552 if (cpr.clients.size() != 0) {
13553 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13554 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13555 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013556 if (client == app) {
13557 // Being our own client is not interesting.
13558 continue;
13559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013560 int myHiddenAdj = hiddenAdj;
13561 if (myHiddenAdj > client.hiddenAdj) {
13562 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13563 myHiddenAdj = client.hiddenAdj;
13564 } else {
13565 myHiddenAdj = FOREGROUND_APP_ADJ;
13566 }
13567 }
13568 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013569 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013570 if (adj > clientAdj) {
13571 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013572 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013573 if (!client.hidden) {
13574 app.hidden = false;
13575 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013576 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013577 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13578 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013579 app.adjSource = client;
13580 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013581 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013582 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13583 schedGroup = Process.THREAD_GROUP_DEFAULT;
13584 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013585 }
13586 }
13587 // If the provider has external (non-framework) process
13588 // dependencies, ensure that its adjustment is at least
13589 // FOREGROUND_APP_ADJ.
13590 if (cpr.externals != 0) {
13591 if (adj > FOREGROUND_APP_ADJ) {
13592 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013593 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013594 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013595 app.adjType = "provider";
13596 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013597 }
13598 }
13599 }
13600 }
13601
13602 app.curRawAdj = adj;
13603
13604 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13605 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13606 if (adj > app.maxAdj) {
13607 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013608 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13609 schedGroup = Process.THREAD_GROUP_DEFAULT;
13610 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013611 }
13612
13613 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013614 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013616 return adj;
13617 }
13618
13619 /**
13620 * Ask a given process to GC right now.
13621 */
13622 final void performAppGcLocked(ProcessRecord app) {
13623 try {
13624 app.lastRequestedGc = SystemClock.uptimeMillis();
13625 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013626 if (app.reportLowMemory) {
13627 app.reportLowMemory = false;
13628 app.thread.scheduleLowMemory();
13629 } else {
13630 app.thread.processInBackground();
13631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013632 }
13633 } catch (Exception e) {
13634 // whatever.
13635 }
13636 }
13637
13638 /**
13639 * Returns true if things are idle enough to perform GCs.
13640 */
13641 private final boolean canGcNow() {
13642 return mParallelBroadcasts.size() == 0
13643 && mOrderedBroadcasts.size() == 0
13644 && (mSleeping || (mResumedActivity != null &&
13645 mResumedActivity.idle));
13646 }
13647
13648 /**
13649 * Perform GCs on all processes that are waiting for it, but only
13650 * if things are idle.
13651 */
13652 final void performAppGcsLocked() {
13653 final int N = mProcessesToGc.size();
13654 if (N <= 0) {
13655 return;
13656 }
13657 if (canGcNow()) {
13658 while (mProcessesToGc.size() > 0) {
13659 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013660 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13661 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13662 <= SystemClock.uptimeMillis()) {
13663 // To avoid spamming the system, we will GC processes one
13664 // at a time, waiting a few seconds between each.
13665 performAppGcLocked(proc);
13666 scheduleAppGcsLocked();
13667 return;
13668 } else {
13669 // It hasn't been long enough since we last GCed this
13670 // process... put it in the list to wait for its time.
13671 addProcessToGcListLocked(proc);
13672 break;
13673 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013674 }
13675 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013676
13677 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013678 }
13679 }
13680
13681 /**
13682 * If all looks good, perform GCs on all processes waiting for them.
13683 */
13684 final void performAppGcsIfAppropriateLocked() {
13685 if (canGcNow()) {
13686 performAppGcsLocked();
13687 return;
13688 }
13689 // Still not idle, wait some more.
13690 scheduleAppGcsLocked();
13691 }
13692
13693 /**
13694 * Schedule the execution of all pending app GCs.
13695 */
13696 final void scheduleAppGcsLocked() {
13697 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013698
13699 if (mProcessesToGc.size() > 0) {
13700 // Schedule a GC for the time to the next process.
13701 ProcessRecord proc = mProcessesToGc.get(0);
13702 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13703
13704 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13705 long now = SystemClock.uptimeMillis();
13706 if (when < (now+GC_TIMEOUT)) {
13707 when = now + GC_TIMEOUT;
13708 }
13709 mHandler.sendMessageAtTime(msg, when);
13710 }
13711 }
13712
13713 /**
13714 * Add a process to the array of processes waiting to be GCed. Keeps the
13715 * list in sorted order by the last GC time. The process can't already be
13716 * on the list.
13717 */
13718 final void addProcessToGcListLocked(ProcessRecord proc) {
13719 boolean added = false;
13720 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13721 if (mProcessesToGc.get(i).lastRequestedGc <
13722 proc.lastRequestedGc) {
13723 added = true;
13724 mProcessesToGc.add(i+1, proc);
13725 break;
13726 }
13727 }
13728 if (!added) {
13729 mProcessesToGc.add(0, proc);
13730 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013731 }
13732
13733 /**
13734 * Set up to ask a process to GC itself. This will either do it
13735 * immediately, or put it on the list of processes to gc the next
13736 * time things are idle.
13737 */
13738 final void scheduleAppGcLocked(ProcessRecord app) {
13739 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013740 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013741 return;
13742 }
13743 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013744 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013745 scheduleAppGcsLocked();
13746 }
13747 }
13748
13749 private final boolean updateOomAdjLocked(
13750 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13751 app.hiddenAdj = hiddenAdj;
13752
13753 if (app.thread == null) {
13754 return true;
13755 }
13756
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013757 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013758
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013759 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013760 if (app.curRawAdj != app.setRawAdj) {
13761 if (app.curRawAdj > FOREGROUND_APP_ADJ
13762 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13763 // If this app is transitioning from foreground to
13764 // non-foreground, have it do a gc.
13765 scheduleAppGcLocked(app);
13766 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13767 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13768 // Likewise do a gc when an app is moving in to the
13769 // background (such as a service stopping).
13770 scheduleAppGcLocked(app);
13771 }
13772 app.setRawAdj = app.curRawAdj;
13773 }
13774 if (adj != app.setAdj) {
13775 if (Process.setOomAdj(app.pid, adj)) {
13776 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13777 TAG, "Set app " + app.processName +
13778 " oom adj to " + adj);
13779 app.setAdj = adj;
13780 } else {
13781 return false;
13782 }
13783 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013784 if (app.setSchedGroup != app.curSchedGroup) {
13785 app.setSchedGroup = app.curSchedGroup;
13786 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13787 "Setting process group of " + app.processName
13788 + " to " + app.curSchedGroup);
13789 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013790 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013791 try {
13792 Process.setProcessGroup(app.pid, app.curSchedGroup);
13793 } catch (Exception e) {
13794 Log.w(TAG, "Failed setting process group of " + app.pid
13795 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013796 e.printStackTrace();
13797 } finally {
13798 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013799 }
13800 }
13801 if (false) {
13802 if (app.thread != null) {
13803 try {
13804 app.thread.setSchedulingGroup(app.curSchedGroup);
13805 } catch (RemoteException e) {
13806 }
13807 }
13808 }
13809 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013810 }
13811
13812 return true;
13813 }
13814
13815 private final HistoryRecord resumedAppLocked() {
13816 HistoryRecord resumedActivity = mResumedActivity;
13817 if (resumedActivity == null || resumedActivity.app == null) {
13818 resumedActivity = mPausingActivity;
13819 if (resumedActivity == null || resumedActivity.app == null) {
13820 resumedActivity = topRunningActivityLocked(null);
13821 }
13822 }
13823 return resumedActivity;
13824 }
13825
13826 private final boolean updateOomAdjLocked(ProcessRecord app) {
13827 final HistoryRecord TOP_ACT = resumedAppLocked();
13828 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13829 int curAdj = app.curAdj;
13830 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13831 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13832
13833 mAdjSeq++;
13834
13835 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13836 if (res) {
13837 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13838 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13839 if (nowHidden != wasHidden) {
13840 // Changed to/from hidden state, so apps after it in the LRU
13841 // list may also be changed.
13842 updateOomAdjLocked();
13843 }
13844 }
13845 return res;
13846 }
13847
13848 private final boolean updateOomAdjLocked() {
13849 boolean didOomAdj = true;
13850 final HistoryRecord TOP_ACT = resumedAppLocked();
13851 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13852
13853 if (false) {
13854 RuntimeException e = new RuntimeException();
13855 e.fillInStackTrace();
13856 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13857 }
13858
13859 mAdjSeq++;
13860
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013861 // Let's determine how many processes we have running vs.
13862 // how many slots we have for background processes; we may want
13863 // to put multiple processes in a slot of there are enough of
13864 // them.
13865 int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
13866 int factor = (mLruProcesses.size()-4)/numSlots;
13867 if (factor < 1) factor = 1;
13868 int step = 0;
13869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013870 // First try updating the OOM adjustment for each of the
13871 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013872 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013873 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13874 while (i > 0) {
13875 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013876 ProcessRecord app = mLruProcesses.get(i);
13877 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013878 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013879 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013880 && app.curAdj == curHiddenAdj) {
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013881 step++;
13882 if (step >= factor) {
13883 step = 0;
13884 curHiddenAdj++;
13885 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013886 }
13887 } else {
13888 didOomAdj = false;
13889 }
13890 }
13891
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013892 // If we return false, we will fall back on killing processes to
13893 // have a fixed limit. Do this if a limit has been requested; else
13894 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013895 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13896 }
13897
13898 private final void trimApplications() {
13899 synchronized (this) {
13900 int i;
13901
13902 // First remove any unused application processes whose package
13903 // has been removed.
13904 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13905 final ProcessRecord app = mRemovedProcesses.get(i);
13906 if (app.activities.size() == 0
13907 && app.curReceiver == null && app.services.size() == 0) {
13908 Log.i(
13909 TAG, "Exiting empty application process "
13910 + app.processName + " ("
13911 + (app.thread != null ? app.thread.asBinder() : null)
13912 + ")\n");
13913 if (app.pid > 0 && app.pid != MY_PID) {
13914 Process.killProcess(app.pid);
13915 } else {
13916 try {
13917 app.thread.scheduleExit();
13918 } catch (Exception e) {
13919 // Ignore exceptions.
13920 }
13921 }
13922 cleanUpApplicationRecordLocked(app, false, -1);
13923 mRemovedProcesses.remove(i);
13924
13925 if (app.persistent) {
13926 if (app.persistent) {
13927 addAppLocked(app.info);
13928 }
13929 }
13930 }
13931 }
13932
13933 // Now try updating the OOM adjustment for each of the
13934 // application processes based on their current state.
13935 // If the setOomAdj() API is not supported, then go with our
13936 // back-up plan...
13937 if (!updateOomAdjLocked()) {
13938
13939 // Count how many processes are running services.
13940 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013941 for (i=mLruProcesses.size()-1; i>=0; i--) {
13942 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013943
13944 if (app.persistent || app.services.size() != 0
13945 || app.curReceiver != null
13946 || app.persistentActivities > 0) {
13947 // Don't count processes holding services against our
13948 // maximum process count.
13949 if (localLOGV) Log.v(
13950 TAG, "Not trimming app " + app + " with services: "
13951 + app.services);
13952 numServiceProcs++;
13953 }
13954 }
13955
13956 int curMaxProcs = mProcessLimit;
13957 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13958 if (mAlwaysFinishActivities) {
13959 curMaxProcs = 1;
13960 }
13961 curMaxProcs += numServiceProcs;
13962
13963 // Quit as many processes as we can to get down to the desired
13964 // process count. First remove any processes that no longer
13965 // have activites running in them.
13966 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013967 i<mLruProcesses.size()
13968 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013969 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013970 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013971 // Quit an application only if it is not currently
13972 // running any activities.
13973 if (!app.persistent && app.activities.size() == 0
13974 && app.curReceiver == null && app.services.size() == 0) {
13975 Log.i(
13976 TAG, "Exiting empty application process "
13977 + app.processName + " ("
13978 + (app.thread != null ? app.thread.asBinder() : null)
13979 + ")\n");
13980 if (app.pid > 0 && app.pid != MY_PID) {
13981 Process.killProcess(app.pid);
13982 } else {
13983 try {
13984 app.thread.scheduleExit();
13985 } catch (Exception e) {
13986 // Ignore exceptions.
13987 }
13988 }
13989 // todo: For now we assume the application is not buggy
13990 // or evil, and will quit as a result of our request.
13991 // Eventually we need to drive this off of the death
13992 // notification, and kill the process if it takes too long.
13993 cleanUpApplicationRecordLocked(app, false, i);
13994 i--;
13995 }
13996 }
13997
13998 // If we still have too many processes, now from the least
13999 // recently used process we start finishing activities.
14000 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014001 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014002 " of " + curMaxProcs + " processes");
14003 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014004 i<mLruProcesses.size()
14005 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014006 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014007 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014008 // Quit the application only if we have a state saved for
14009 // all of its activities.
14010 boolean canQuit = !app.persistent && app.curReceiver == null
14011 && app.services.size() == 0
14012 && app.persistentActivities == 0;
14013 int NUMA = app.activities.size();
14014 int j;
14015 if (Config.LOGV) Log.v(
14016 TAG, "Looking to quit " + app.processName);
14017 for (j=0; j<NUMA && canQuit; j++) {
14018 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14019 if (Config.LOGV) Log.v(
14020 TAG, " " + r.intent.getComponent().flattenToShortString()
14021 + ": frozen=" + r.haveState + ", visible=" + r.visible);
14022 canQuit = (r.haveState || !r.stateNotNeeded)
14023 && !r.visible && r.stopped;
14024 }
14025 if (canQuit) {
14026 // Finish all of the activities, and then the app itself.
14027 for (j=0; j<NUMA; j++) {
14028 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14029 if (!r.finishing) {
14030 destroyActivityLocked(r, false);
14031 }
14032 r.resultTo = null;
14033 }
14034 Log.i(TAG, "Exiting application process "
14035 + app.processName + " ("
14036 + (app.thread != null ? app.thread.asBinder() : null)
14037 + ")\n");
14038 if (app.pid > 0 && app.pid != MY_PID) {
14039 Process.killProcess(app.pid);
14040 } else {
14041 try {
14042 app.thread.scheduleExit();
14043 } catch (Exception e) {
14044 // Ignore exceptions.
14045 }
14046 }
14047 // todo: For now we assume the application is not buggy
14048 // or evil, and will quit as a result of our request.
14049 // Eventually we need to drive this off of the death
14050 // notification, and kill the process if it takes too long.
14051 cleanUpApplicationRecordLocked(app, false, i);
14052 i--;
14053 //dump();
14054 }
14055 }
14056
14057 }
14058
14059 int curMaxActivities = MAX_ACTIVITIES;
14060 if (mAlwaysFinishActivities) {
14061 curMaxActivities = 1;
14062 }
14063
14064 // Finally, if there are too many activities now running, try to
14065 // finish as many as we can to get back down to the limit.
14066 for ( i=0;
14067 i<mLRUActivities.size()
14068 && mLRUActivities.size() > curMaxActivities;
14069 i++) {
14070 final HistoryRecord r
14071 = (HistoryRecord)mLRUActivities.get(i);
14072
14073 // We can finish this one if we have its icicle saved and
14074 // it is not persistent.
14075 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14076 && r.stopped && !r.persistent && !r.finishing) {
14077 final int origSize = mLRUActivities.size();
14078 destroyActivityLocked(r, true);
14079
14080 // This will remove it from the LRU list, so keep
14081 // our index at the same value. Note that this check to
14082 // see if the size changes is just paranoia -- if
14083 // something unexpected happens, we don't want to end up
14084 // in an infinite loop.
14085 if (origSize > mLRUActivities.size()) {
14086 i--;
14087 }
14088 }
14089 }
14090 }
14091 }
14092
14093 /** This method sends the specified signal to each of the persistent apps */
14094 public void signalPersistentProcesses(int sig) throws RemoteException {
14095 if (sig != Process.SIGNAL_USR1) {
14096 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14097 }
14098
14099 synchronized (this) {
14100 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14101 != PackageManager.PERMISSION_GRANTED) {
14102 throw new SecurityException("Requires permission "
14103 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14104 }
14105
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014106 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14107 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014108 if (r.thread != null && r.persistent) {
14109 Process.sendSignal(r.pid, sig);
14110 }
14111 }
14112 }
14113 }
14114
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014115 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014116 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014117
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014118 try {
14119 synchronized (this) {
14120 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14121 // its own permission.
14122 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14123 != PackageManager.PERMISSION_GRANTED) {
14124 throw new SecurityException("Requires permission "
14125 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014126 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014127
14128 if (start && fd == null) {
14129 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014130 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014131
14132 ProcessRecord proc = null;
14133 try {
14134 int pid = Integer.parseInt(process);
14135 synchronized (mPidsSelfLocked) {
14136 proc = mPidsSelfLocked.get(pid);
14137 }
14138 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014139 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014140
14141 if (proc == null) {
14142 HashMap<String, SparseArray<ProcessRecord>> all
14143 = mProcessNames.getMap();
14144 SparseArray<ProcessRecord> procs = all.get(process);
14145 if (procs != null && procs.size() > 0) {
14146 proc = procs.valueAt(0);
14147 }
14148 }
14149
14150 if (proc == null || proc.thread == null) {
14151 throw new IllegalArgumentException("Unknown process: " + process);
14152 }
14153
14154 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14155 if (isSecure) {
14156 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14157 throw new SecurityException("Process not debuggable: " + proc);
14158 }
14159 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014160
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014161 proc.thread.profilerControl(start, path, fd);
14162 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014163 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014164 }
14165 } catch (RemoteException e) {
14166 throw new IllegalStateException("Process disappeared");
14167 } finally {
14168 if (fd != null) {
14169 try {
14170 fd.close();
14171 } catch (IOException e) {
14172 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014173 }
14174 }
14175 }
14176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014177 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14178 public void monitor() {
14179 synchronized (this) { }
14180 }
14181}